Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

В bahagian pertama Saya cuba memberitahu jurutera elektronik hobi yang membesar dari seluar Arduino bagaimana dan mengapa mereka harus membaca lembaran data dan dokumentasi lain untuk mikropengawal. Teksnya ternyata besar, jadi saya berjanji untuk menunjukkan contoh praktikal dalam artikel berasingan. Dia menamakan dirinya cendawan susu...

Hari ini saya akan menunjukkan kepada anda cara menggunakan lembaran data untuk menyelesaikan agak mudah, tetapi perlu untuk banyak projek, tugas pada STM32 (Pil Biru) dan pengawal STM8. Semua projek demo didedikasikan untuk LED kegemaran saya, kami akan menyalakannya dalam kuantiti yang banyak, yang mana kami perlu menggunakan semua jenis peranti yang menarik.

Teks sekali lagi ternyata besar, jadi untuk kemudahan saya membuat kandungannya:

Pil Biru STM32: 16 LED dengan pemacu DM634
STM8: Menyediakan enam pin PWM
STM8: 8 LED RGB pada tiga pin, mengganggu

Penafian: Saya bukan jurutera, saya tidak berpura-pura mempunyai pengetahuan mendalam dalam elektronik, artikel itu ditujukan untuk amatur seperti saya. Malah, saya menganggap diri saya dua tahun lalu sebagai penonton sasaran. Jika seseorang memberitahu saya bahawa lembaran data pada cip yang tidak dikenali tidak menakutkan untuk dibaca, saya tidak akan menghabiskan banyak masa mencari beberapa keping kod di Internet dan mencipta tongkat dengan gunting dan pita pelekat.

Fokus artikel ini adalah pada lembaran data, bukan projek, jadi kod mungkin tidak begitu kemas dan sering sempit. Projek itu sendiri sangat mudah, walaupun sesuai untuk kenalan pertama dengan cip baharu.

Saya berharap artikel saya akan membantu seseorang yang berada pada tahap yang serupa dalam hobi.

STM32

16 LED dengan DM634 dan SPI

Projek kecil menggunakan Pil Biru (STM32F103C8T6) dan pemacu LED DM634. Menggunakan lembaran data, kami akan mengetahui pemacu, port IO STM dan mengkonfigurasi SPI.

DM634

Cip Taiwan dengan 16 output PWM 16-bit, boleh disambungkan dalam rantai. Model 12-bit rendah diketahui daripada projek domestik Pek ringan. Pada satu masa, memilih antara DM63x dan TLC5940 yang terkenal, saya memilih DM atas beberapa sebab: 1) TLC pada Aliexpress pastinya palsu, tetapi yang ini tidak; 2) DM mempunyai PWM autonomi dengan penjana frekuensinya sendiri; 3) ia boleh dibeli dengan murah di Moscow, daripada menunggu bungkusan daripada Ali. Dan, tentu saja, adalah menarik untuk belajar bagaimana untuk mengawal cip itu sendiri, dan bukannya menggunakan perpustakaan siap pakai. Cip kini terutamanya dibentangkan dalam pakej SSOP24; ia mudah dipateri kepada penyesuai.

Oleh kerana pengeluarnya adalah warga Taiwan, Lembaran data cip itu ditulis dalam bahasa Inggeris Cina, yang bermaksud ia akan menjadi menyeronokkan. Mula-mula kita lihat pinout (Sambungan Pin) untuk memahami kaki mana yang hendak disambungkan, dan perihalan pin (Huraian Pin). 16 pin:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Sumber Sinki DC (Longkang Terbuka)

Sink / Keluaran longkang terbuka – longkang; punca arus masuk; output disambungkan ke tanah dalam keadaan aktif - LED disambungkan kepada pemacu oleh katod. Secara elektrik, ini, sudah tentu, bukan "longkang terbuka" (longkang terbuka), tetapi dalam lembaran data sebutan ini untuk pin dalam mod longkang sering dijumpai.

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Perintang luar antara REXT dan GND untuk menetapkan nilai arus keluaran

Perintang rujukan dipasang di antara pin REXT dan tanah, yang mengawal rintangan dalaman output, lihat graf pada halaman 9 lembaran data. Dalam DM634, rintangan ini juga boleh dikawal oleh perisian, menetapkan kecerahan keseluruhan (kecerahan global); Saya tidak akan menerangkan butiran dalam artikel ini, saya hanya akan meletakkan perintang 2.2 - 3 kOhm di sini.

Untuk memahami cara mengawal cip, mari lihat penerangan antara muka peranti:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

Ya, ini dia, Bahasa Inggeris Cina dalam segala kegemilangannya. Menterjemah ini bermasalah, anda boleh memahaminya jika anda mahu, tetapi ada cara lain - lihat bagaimana sambungan kepada TLC5940 yang serupa secara fungsi diterangkan dalam lembaran data:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
... Hanya tiga pin diperlukan untuk memasukkan data ke dalam peranti. Tepi menaik isyarat SCLK mengalihkan data daripada pin SIN ke daftar dalaman. Selepas semua data telah dimuatkan, isyarat XLAT tinggi pendek menyelak data yang dipindahkan secara berurutan ke dalam daftar dalaman. Daftar dalaman ialah pintu yang dicetuskan oleh tahap isyarat XLAT. Semua data dihantar bit yang paling penting terlebih dahulu.

Selak – selak/selak/kunci.
kelebihan yang semakin meningkat – bahagian hadapan nadi
MSB dulu – bit paling ketara (paling kiri) ke hadapan.
kepada data jam – menghantar data secara berurutan (sedikit demi sedikit).

Word selak sering dijumpai dalam dokumentasi untuk cip dan diterjemahkan dalam pelbagai cara, jadi demi pemahaman saya akan membenarkan diri saya

program pendidikan kecilPemacu LED pada asasnya adalah daftar syif. "Anjakan" (peralihan) dalam nama - pergerakan data secara bitwise di dalam peranti: setiap bit baharu yang ditolak ke dalam menolak keseluruhan rantai ke hadapan di hadapannya. Memandangkan tiada siapa yang mahu melihat LED berkelip huru-hara semasa peralihan, proses berlaku dalam daftar penimbal yang dipisahkan daripada daftar kerja oleh peredam (selak) ialah sejenis ruang menunggu di mana bit disusun mengikut urutan yang dikehendaki. Apabila semuanya sudah sedia, pengatup terbuka dan bit berfungsi, menggantikan kumpulan sebelumnya. Perkataan selak dalam dokumentasi untuk litar mikro hampir selalu membayangkan peredam sedemikian, tidak kira dalam kombinasi apa yang digunakan.

Jadi, pemindahan data ke DM634 dijalankan seperti ini: tetapkan input DAI kepada nilai bit paling ketara dari jauh LED, tarik DCK ke atas dan ke bawah; tetapkan input DAI kepada nilai bit seterusnya, tarik DCK; dan seterusnya sehingga semua bit telah dihantar (jam masuk), selepas itu kita tarik LAT. Ini boleh dilakukan secara manual (bit-bang), tetapi lebih baik menggunakan antara muka SPI yang disesuaikan khas untuk ini, kerana ia dibentangkan pada STM32 kami dalam dua salinan.

Pil Biru STM32F103

Pengenalan: Pengawal STM32 jauh lebih kompleks daripada Atmega328 daripada yang mungkin kelihatan menakutkan. Selain itu, atas sebab penjimatan tenaga, hampir semua peranti dimatikan pada permulaan, dan kekerapan jam ialah 8 MHz dari sumber dalaman. Nasib baik, pengaturcara STM menulis kod yang membawa cip sehingga 72 MHz "dikira", dan pengarang semua IDE yang saya tahu memasukkannya dalam prosedur permulaan, jadi kami tidak perlu jam (tetapi anda boleh jika anda benar-benar mahu). Tetapi anda perlu menghidupkan peranti peranti.

Dokumentasi: Pil Biru dilengkapi dengan cip STM32F103C8T6 yang popular, terdapat dua dokumen berguna untuknya:

  • Risalah Data untuk mikropengawal STM32F103x8 dan STM32F103xB;
  • Manual rujukan untuk keseluruhan talian STM32F103 dan banyak lagi.

Dalam lembaran data kami mungkin berminat dengan:

  • Pinout - pinout cip - sekiranya kami memutuskan untuk membuat papan sendiri;
  • Peta Memori – peta memori untuk cip tertentu. Manual Rujukan mempunyai peta untuk keseluruhan baris, dan ia menyebut daftar yang kami tidak miliki.
  • Jadual Definisi Pin – menyenaraikan fungsi utama dan alternatif pin; untuk "pil biru" anda boleh menemui gambar yang lebih mudah di Internet dengan senarai pin dan fungsinya. Oleh itu, kami segera menggoogle pinout Pil Biru dan menyimpan gambar ini di tangan:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
NB: terdapat ralat dalam gambar dari Internet, yang dinyatakan dalam ulasan, terima kasih untuk itu. Gambar telah diganti, tetapi ini adalah pengajaran - lebih baik untuk menyemak maklumat bukan dari lembaran data.

Kami mengalih keluar lembaran data, membuka Manual Rujukan, dan mulai sekarang kami hanya menggunakannya.
Prosedur: kami berurusan dengan input/output standard, mengkonfigurasi SPI, menghidupkan peranti yang diperlukan.

Input Output

Pada Atmega328, I/O dilaksanakan dengan sangat ringkas, itulah sebabnya banyak pilihan STM32 boleh mengelirukan. Sekarang kita hanya memerlukan kesimpulan, tetapi ini mempunyai empat pilihan:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
longkang terbuka, tolak-tarik, tolak-tolak alternatif, longkang terbuka alternatif

"Tarik tolak" (tolak tarik) ialah keluaran biasa daripada Arduino, pin boleh mengambil nilai sama ada HIGH atau LOW. Tetapi dengan "longkang terbuka" ada kesukaran, walaupun sebenarnya semuanya mudah di sini:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Konfigurasi output / apabila port ditetapkan kepada output: / penimbal output didayakan: / – mod saliran terbuka: “0” dalam daftar output membolehkan N-MOS, “1” dalam daftar output meninggalkan port dalam mod Hi-Z ( P-MOS tidak diaktifkan ) / – mod tolak-tarik: “0” dalam daftar output mengaktifkan N-MOS, “1” dalam daftar output mengaktifkan P-MOS.

Semua perbezaan antara longkang terbuka (longkang terbuka) daripada “tolak-tarik” (tolak tarik) ialah dalam pin pertama tidak boleh menerima keadaan TINGGI: apabila menulis satu ke daftar keluaran, ia masuk ke mod rintangan tinggi (impedans tinggi, Hai-Z). Apabila menulis sifar, pin berkelakuan sama dalam kedua-dua mod, secara logik dan elektrik.

Dalam mod keluaran biasa, pin hanya menyiarkan kandungan daftar keluaran. Dalam "alternatif" ia dikawal oleh peranti yang sepadan (lihat 9.1.4):

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Jika bit port dikonfigurasikan sebagai pin fungsi ganti, daftar pin dinyahdayakan dan pin disambungkan ke pin persisian.

Kefungsian alternatif setiap pin diterangkan dalam Definisi Pin Lembaran data terdapat pada imej yang dimuat turun. Kepada soalan tentang apa yang perlu dilakukan jika pin mempunyai beberapa fungsi alternatif, jawapan diberikan oleh nota kaki dalam lembaran data:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Jika berbilang persisian menggunakan pin yang sama, untuk mengelakkan konflik antara fungsi alternatif, hanya satu persisian harus digunakan pada satu masa, ditogol menggunakan bit daya jam persisian (dalam daftar RCC yang sesuai).

Akhirnya, pin dalam mod output juga mempunyai kelajuan jam. Ini adalah satu lagi ciri penjimatan tenaga; dalam kes kami, kami hanya menetapkannya kepada maksimum dan melupakannya.

Jadi: kami menggunakan SPI, yang bermaksud bahawa dua pin (dengan data dan dengan isyarat jam) hendaklah "fungsi tolak-tarik alternatif", dan satu lagi (LAT) hendaklah "tarik-tolak biasa". Tetapi sebelum menugaskan mereka, mari kita berurusan dengan SPI.

SPI

Satu lagi program pendidikan kecil

SPI atau Serial Peripheral Interface (antara muka persisian bersiri) ialah antara muka yang mudah dan sangat berkesan untuk menyambungkan MK dengan MK lain dan dunia luar secara amnya. Prinsip operasinya telah diterangkan di atas, di mana mengenai pemacu LED Cina (dalam manual rujukan, lihat bahagian 25). SPI boleh beroperasi dalam mod induk (“tuan”) dan hamba (“hamba”). SPI mempunyai empat saluran asas, yang mana tidak semuanya boleh digunakan:

  • MOSI, Output Induk / Input Hamba: pin ini menghantar data dalam mod induk, dan menerima data dalam mod hamba;
  • MISO, Input Induk / Output Hamba: sebaliknya, ia menerima dalam tuan, dan menghantar dalam hamba;
  • SCK, Jam Bersiri: menetapkan kekerapan penghantaran data dalam induk atau menerima isyarat jam dalam hamba. Pada asasnya memukul rentak;
  • SS, Slave Select: dengan bantuan saluran ini, hamba tahu bahawa ada sesuatu yang dikehendaki daripadanya. Pada STM32 ia dipanggil NSS, di mana N = negatif, i.e. pengawal menjadi hamba jika terdapat tanah dalam saluran ini. Ia digabungkan dengan baik dengan mod Open Drain Output, tetapi itu cerita lain.

Seperti segala-galanya, SPI pada STM32 kaya dengan fungsi, yang menjadikannya agak sukar untuk difahami. Sebagai contoh, ia boleh berfungsi bukan sahaja dengan SPI, tetapi juga dengan antara muka I2S, dan dalam dokumentasi penerangan mereka bercampur-campur, adalah perlu untuk memotong lebihan tepat pada masanya. Tugas kami sangat mudah: kami hanya perlu menghantar data menggunakan MOSI dan SCK sahaja. Kami pergi ke bahagian 25.3.4 (komunikasi separuh dupleks, komunikasi separuh dupleks), di mana kami dapati 1 jam dan 1 wayar data satu arah (1 isyarat jam dan 1 aliran data satu arah):

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Dalam mod ini, aplikasi menggunakan SPI sama ada dalam mod penghantaran sahaja atau terima sahaja. / Mod penghantaran sahaja adalah serupa dengan mod dupleks: data dihantar pada pin hantar (MOSI dalam mod induk atau MISO dalam mod hamba), dan pin terima (MISO atau MOSI masing-masing) boleh digunakan sebagai pin I/O biasa . Dalam kes ini, aplikasi hanya perlu mengabaikan penimbal Rx (jika ia dibaca, tidak akan ada data yang dipindahkan di sana).

Hebat, pin MISO adalah percuma, mari sambungkan isyarat LAT kepadanya. Mari kita lihat Slave Select, yang pada STM32 boleh dikawal secara pemrograman, yang sangat mudah. Kami membaca perenggan dengan nama yang sama dalam bahagian 25.3.1 Penerangan Umum SPI:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Kawalan perisian NSS (SSM = 1) / Maklumat pemilihan hamba terkandung dalam bit SSI daftar SPI_CR1. Pin NSS luaran kekal percuma untuk keperluan aplikasi lain.

Sudah tiba masanya untuk menulis kepada pendaftar. Saya memutuskan untuk menggunakan SPI2, cari alamat asasnya dalam lembaran data - dalam bahagian 3.3 Peta Memori:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

Baiklah, mari kita mulakan:

#define _SPI2_(mem_offset) (*(volatile uint32_t *)(0x40003800 + (mem_offset)))

Buka bahagian 25.3.3 dengan tajuk penjelasan sendiri "Mengkonfigurasi SPI dalam Mod Induk":

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

1. Tetapkan kekerapan jam bersiri dengan bit BR[2:0] dalam daftar SPI_CR1.

Daftar dikumpul dalam bahagian manual rujukan dengan nama yang sama. peralihan alamat (Alamat diimbangi) untuk CR1 – 0x00, secara lalai semua bit dikosongkan (Tetapkan semula nilai 0x0000):

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

Bit BR menetapkan pembahagi jam pengawal, dengan itu menentukan kekerapan di mana SPI akan beroperasi. Kekerapan STM32 kami ialah 72 MHz, pemacu LED, mengikut lembaran datanya, beroperasi dengan frekuensi sehingga 25 MHz, jadi kami perlu membahagikan dengan empat (BR[2:0] = 001).

#define _SPI_CR1 0x00

#define BR_0        0x0008
#define BR_1        0x0010
#define BR_2        0x0020

_SPI2_ (_SPI_CR1) |= BR_0;// pclk/4

2. Tetapkan bit CPOL dan CPHA untuk menentukan hubungan antara pemindahan data dan pemasaan jam bersiri (lihat rajah pada halaman 240)

Memandangkan kita sedang membaca lembaran data di sini dan tidak melihat skema, mari kita lihat dengan lebih dekat perihalan teks bit CPOL dan CPHA pada halaman 704 (Penerangan Umum SPI):

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Fasa jam dan kekutuban
Menggunakan bit CPOL dan CPHA daftar SPI_CR1, anda boleh memilih empat perhubungan pemasaan secara pemrograman. Bit CPOL (kekutuban jam) mengawal keadaan isyarat jam apabila tiada data sedang dihantar. Bit ini mengawal mod tuan dan hamba. Jika CPOL ditetapkan semula, pin SCK rendah dalam mod rehat. Jika bit CPOL ditetapkan, pin SCK adalah tinggi semasa mod rehat.
Apabila bit CPHA (fasa jam) ditetapkan, strob perangkap bit tinggi ialah pinggir kedua isyarat SCK (jatuh jika CPOL jelas, meningkat jika CPOL ditetapkan). Data ditangkap oleh perubahan kedua dalam isyarat jam. Jika bit CPHA adalah jelas, strob perangkap bit tinggi ialah pinggir menaik bagi isyarat SCK (tepi jatuh jika CPOL ditetapkan, tepi meningkat jika CPOL dibersihkan). Data ditangkap pada perubahan pertama dalam isyarat jam.

Setelah menyerap pengetahuan ini, kami sampai pada kesimpulan bahawa kedua-dua bit mesti kekal sifar, kerana Kami mahu isyarat SCK kekal rendah apabila tidak digunakan, dan data dihantar pada pinggir nadi yang semakin meningkat (lihat Rajah. Rising Edge dalam lembaran data DM634).

Ngomong-ngomong, di sini kita mula-mula menemui ciri perbendaharaan kata dalam lembaran data ST: di dalamnya frasa "set semula bit kepada sifar" ditulis untuk menetapkan semula sedikitDan tidak untuk membersihkan sedikit, seperti, contohnya, Atmega.

3. Tetapkan bit DFF untuk menentukan sama ada blok data adalah format 8-bit atau 16-bit

Saya secara khusus mengambil DM16 634-bit supaya tidak mengganggu penghantaran data PWM 12-bit, seperti DM633. Masuk akal untuk menetapkan DFF kepada satu:

#define DFF         0x0800

_SPI2_ (_SPI_CR1) |= DFF; // 16-bit mode

4. Konfigurasikan bit LSBFIRST dalam daftar SPI_CR1 untuk menentukan format blok

LSBFIRST, seperti namanya, mengkonfigurasi penghantaran dengan bit paling tidak ketara terlebih dahulu. Tetapi DM634 mahu menerima data bermula dari bit yang paling ketara. Oleh itu, kami biarkan ia ditetapkan semula.

5. Dalam mod perkakasan, jika input daripada pin NSS diperlukan, gunakan isyarat tinggi pada pin NSS semasa keseluruhan urutan pemindahan bait. Dalam mod perisian NSS, tetapkan bit SSM dan SSI dalam daftar SPI_CR1. Jika pin NSS hendak digunakan sebagai output, hanya bit SSOE perlu ditetapkan.

Pasang SSM dan SSI untuk melupakan mod perkakasan NSS:

#define SSI         0x0100
#define SSM         0x0200

_SPI2_ (_SPI_CR1) |= SSM | SSI; //enable software control of SS, SS high

6. Bit MSTR dan SPE mesti ditetapkan (ia kekal ditetapkan hanya jika isyarat NSS tinggi)

Sebenarnya, dengan bit ini kami menetapkan SPI kami sebagai induk dan menghidupkannya:

#define MSTR        0x0004
#define SPE         0x0040

_SPI2_ (_SPI_CR1) |= MSTR; //SPI master
//когда все готово, включаем SPI
_SPI2_ (_SPI_CR1) |= SPE;

SPI dikonfigurasikan, mari segera menulis fungsi yang menghantar bait kepada pemacu. Teruskan membaca 25.3.3 “Mengkonfigurasi SPI dalam mod induk”:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Perintah pemindahan data
Penghantaran bermula apabila bait ditulis kepada penimbal Tx.
Bait data dimuatkan ke dalam daftar anjakan di selari mod (dari bas dalaman) semasa penghantaran bit pertama, selepas itu ia dihantar ke berurutan Mod pin MOSI, bit pertama atau terakhir ke hadapan bergantung pada tetapan bit LSBFIRST dalam daftar CPI_CR1. Bendera TXE ditetapkan selepas penghantaran data daripada Tx buffer kepada shift register, dan juga menjana gangguan jika bit TXEIE dalam daftar CPI_CR1 ditetapkan.

Saya menyerlahkan beberapa perkataan dalam terjemahan untuk menarik perhatian kepada satu ciri pelaksanaan SPI dalam pengawal STM. Pada Atmega bendera TXE (Tx Kosong, Tx kosong dan sedia untuk menerima data) ditetapkan hanya selepas keseluruhan bait telah dihantar keluar. Dan di sini bendera ini ditetapkan selepas bait telah dimasukkan ke dalam daftar anjakan dalaman. Oleh kerana ia ditolak ke sana dengan semua bit pada masa yang sama (selari), dan kemudian data dihantar secara berurutan, TXE ditetapkan sebelum bait dihantar sepenuhnya. Ini penting kerana dalam kes pemandu LED kami, kami perlu menarik pin LAT selepas menghantar Semua data, i.e. Bendera TXE sahaja tidak akan mencukupi untuk kita.

Ini bermakna kita memerlukan bendera lain. Mari lihat 25.3.7 - "Bendera Status":

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
<…>
Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
bendera SIBUK
Bendera BSY ditetapkan dan dibersihkan oleh perkakasan (menulis kepadanya tidak mempunyai kesan). Bendera BSY menunjukkan keadaan lapisan komunikasi SPI.
Ia menetapkan semula:
apabila pemindahan selesai (kecuali dalam mod induk jika pemindahan berterusan)
apabila SPI dilumpuhkan
apabila ralat mod induk berlaku (MODF=1)
Jika pemindahan tidak berterusan, bendera BSY dikosongkan antara setiap pemindahan data

Okay, ini akan berguna. Mari ketahui di mana penimbal Tx berada. Untuk melakukan ini, baca "Daftar Data SPI":

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Daftar Data Bit 15:0 DR[15:0].
Data yang diterima atau data yang akan dihantar.
Daftar data dibahagikan kepada dua buffer - satu untuk menulis (transmit buffer) dan satu untuk membaca (receive buffer). Menulis ke daftar data menulis kepada penimbal Tx, dan membaca dari daftar data akan mengembalikan nilai yang terkandung dalam penimbal Rx.

Nah, dan daftar status, di mana bendera TXE dan BSY ditemui:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

Kami menulis:

#define _SPI_DR  0x0C
#define _SPI_SR  0x08

#define BSY         0x0080
#define TXE         0x0002

void dm_shift16(uint16_t value)
{
    _SPI2_(_SPI_DR) = value; //send 2 bytes
    while (!(_SPI2_(_SPI_SR) & TXE)); //wait until they're sent
}

Nah, kerana kita perlu menghantar 16 kali dua bait, mengikut bilangan output pemacu LED, seperti ini:

void sendLEDdata()
{
    LAT_low();
    uint8_t k = 16;
    do
    {   k--;
        dm_shift16(leds[k]);
    } while (k);

    while (_SPI2_(_SPI_SR) & BSY); // finish transmission

    LAT_pulse();
}

Tetapi kami belum tahu cara menarik pin LAT lagi, jadi kami akan kembali ke I/O.

Menetapkan pin

Dalam STM32F1, daftar yang bertanggungjawab untuk keadaan pin agak luar biasa. Jelas bahawa terdapat lebih banyak daripada mereka daripada Atmega, tetapi mereka juga berbeza daripada cip STM yang lain. Bahagian 9.1 Penerangan Umum GPIO:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Setiap port I/O tujuan umum (GPIO) mempunyai dua daftar konfigurasi 32-bit (GPIOx_CRL dan GPIOx_CRH), dua daftar data 32-bit (GPIOx_IDR dan GPIOx_ODR), daftar set/set 32-bit (GPIOx_BSRR), daftar set semula 16-bit (GPIOx_BRR) dan 32- daftar penyekat bit (GPIOx_LCKR).

Dua daftar pertama adalah luar biasa, dan juga agak menyusahkan, kerana 16 pin port bertaburan merentasi mereka dalam format "empat bit setiap saudara". Itu. pin sifar hingga tujuh berada dalam CRL, dan selebihnya dalam CRH. Pada masa yang sama, daftar yang tinggal berjaya mengandungi bit semua pin port - selalunya tinggal separuh "terpelihara".

Untuk kesederhanaan, mari kita mulakan dari akhir senarai.

Kami tidak memerlukan daftar penyekat.

Daftar set dan set semula agak lucu kerana ia sebahagiannya menduplikasi antara satu sama lain: anda boleh menulis semuanya hanya dalam BSRR, di mana 16 bit yang lebih tinggi akan menetapkan semula pin kepada sifar, dan yang lebih rendah akan ditetapkan kepada 1, atau anda juga boleh gunakan BRR, 16 bit yang lebih rendah daripadanya hanya menetapkan semula pin . Saya suka pilihan kedua. Daftar ini penting kerana ia menyediakan akses atom kepada pin:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Set Atom atau Set Semula
Tidak perlu melumpuhkan gangguan apabila memprogramkan GPIOx_ODR pada tahap bit: satu atau lebih bit boleh ditukar dengan satu operasi tulis atom APB2. Ini dicapai dengan menulis "1" pada daftar set/set semula (GPIOx_BSRR atau, untuk set semula sahaja, GPIOx_BRR) bit yang perlu diubah. Bit lain akan kekal tidak berubah.

Daftar data mempunyai nama yang cukup jelas - IDR = Input Daftar Arah, daftar masukan; ODR = Output Daftar Arah, daftar keluaran. Kami tidak memerlukannya dalam projek semasa.

Dan akhirnya, daftar kawalan. Oleh kerana kami berminat dengan pin SPI kedua, iaitu PB13, PB14 dan PB15, kami segera melihat CRH:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

Dan kita melihat bahawa kita perlu menulis sesuatu dalam bit dari 20 hingga 31.

Kami telah mengetahui di atas apa yang kami mahu daripada pin, jadi di sini saya akan lakukan tanpa tangkapan skrin, saya hanya akan mengatakan bahawa MODE menentukan arah (input jika kedua-dua bit ditetapkan kepada 0) dan kelajuan pin (kita memerlukan 50MHz, i.e. kedua-dua pin kepada "1"), dan CNF menetapkan mod: "tekan-tarik" biasa - 00, "alternatif" - 10. Secara lalai, seperti yang kita lihat di atas, semua pin mempunyai bit ketiga dari bawah (CNF0), ia menetapkan mereka kepada mod input terapung.

Oleh kerana saya bercadang untuk melakukan sesuatu yang lain dengan cip ini, untuk kesederhanaan saya telah menentukan semua nilai MODE dan CNF yang mungkin untuk kedua-dua daftar kawalan bawah dan atas.

Entah kenapa begini

#define CNF0_0 0x00000004
#define CNF0_1 0x00000008
#define CNF1_0 0x00000040
#define CNF1_1 0x00000080
#define CNF2_0 0x00000400
#define CNF2_1 0x00000800
#define CNF3_0 0x00004000
#define CNF3_1 0x00008000
#define CNF4_0 0x00040000
#define CNF4_1 0x00080000
#define CNF5_0 0x00400000
#define CNF5_1 0x00800000
#define CNF6_0 0x04000000
#define CNF6_1 0x08000000
#define CNF7_0 0x40000000
#define CNF7_1 0x80000000
#define CNF8_0 0x00000004
#define CNF8_1 0x00000008
#define CNF9_0 0x00000040
#define CNF9_1 0x00000080
#define CNF10_0 0x00000400
#define CNF10_1 0x00000800
#define CNF11_0 0x00004000
#define CNF11_1 0x00008000
#define CNF12_0 0x00040000
#define CNF12_1 0x00080000
#define CNF13_0 0x00400000
#define CNF13_1 0x00800000
#define CNF14_0 0x04000000
#define CNF14_1 0x08000000
#define CNF15_0 0x40000000
#define CNF15_1 0x80000000

#define MODE0_0 0x00000001
#define MODE0_1 0x00000002
#define MODE1_0 0x00000010
#define MODE1_1 0x00000020
#define MODE2_0 0x00000100
#define MODE2_1 0x00000200
#define MODE3_0 0x00001000
#define MODE3_1 0x00002000
#define MODE4_0 0x00010000
#define MODE4_1 0x00020000
#define MODE5_0 0x00100000
#define MODE5_1 0x00200000
#define MODE6_0 0x01000000
#define MODE6_1 0x02000000
#define MODE7_0 0x10000000
#define MODE7_1 0x20000000
#define MODE8_0 0x00000001
#define MODE8_1 0x00000002
#define MODE9_0 0x00000010
#define MODE9_1 0x00000020
#define MODE10_0 0x00000100
#define MODE10_1 0x00000200
#define MODE11_0 0x00001000
#define MODE11_1 0x00002000
#define MODE12_0 0x00010000
#define MODE12_1 0x00020000
#define MODE13_0 0x00100000
#define MODE13_1 0x00200000
#define MODE14_0 0x01000000
#define MODE14_1 0x02000000
#define MODE15_0 0x10000000
#define MODE15_1 0x20000000

Pin kami terletak pada port B (alamat asas – 0x40010C00), kod:

#define _PORTB_(mem_offset) (*(volatile uint32_t *)(0x40010C00 + (mem_offset)))

#define _BRR  0x14
#define _BSRR 0x10
#define _CRL  0x00
#define _CRH  0x04

//используем стандартный SPI2: MOSI на B15, CLK на B13
//LAT пусть будет на неиспользуемом MISO – B14

//очищаем дефолтный бит, он нам точно не нужен
_PORTB_ (_CRH) &= ~(CNF15_0 | CNF14_0 | CNF13_0 | CNF12_0);

//альтернативные функции для MOSI и SCK
_PORTB_ (_CRH) |= CNF15_1 | CNF13_1;

//50 МГц, MODE = 11
_PORTB_ (_CRH) |= MODE15_1 | MODE15_0 | MODE14_1 | MODE14_0 | MODE13_1 | MODE13_0;

Dan, oleh itu, anda boleh menulis definisi untuk LAT, yang akan digerakkan oleh daftar BRR dan BSRR:

/*** LAT pulse – high, then low */
#define LAT_pulse() _PORTB_(_BSRR) = (1<<14); _PORTB_(_BRR) = (1<<14)

#define LAT_low() _PORTB_(_BRR) = (1<<14)

(LAT_rendah hanya dengan inersia, ia sentiasa seperti itu, biarkan ia kekal)

Sekarang semuanya hebat, tetapi ia tidak berfungsi. Kerana ini adalah STM32, ia menjimatkan tenaga elektrik, yang bermaksud anda perlu mendayakan masa bagi peranti yang diperlukan.

Hidupkan jam

Jam tangan, juga dikenali sebagai Jam, bertanggungjawab untuk mencatat masa. Dan kita sudah dapat melihat singkatan RCC. Kami mencarinya dalam dokumentasi: ini ialah Reset dan Kawalan Jam.

Seperti yang dinyatakan di atas, mujurlah, bahagian yang paling sukar dalam topik masa telah dilakukan untuk kami oleh orang dari STM, yang mana kami mengucapkan ribuan terima kasih kepada mereka (sekali lagi saya akan memberikan pautan kepada laman web Di Halt, untuk menjelaskan betapa mengelirukannya). Kami hanya memerlukan daftar yang bertanggungjawab untuk mendayakan jam persisian (Jam Periferal Membolehkan Daftar). Mula-mula, mari kita cari alamat asas RCC, ia adalah pada permulaan "Peta Memori":

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

#define _RCC_(mem_offset) (*(volatile uint32_t *)(0x40021000 + (mem_offset)))

Dan kemudian sama ada klik pada pautan di mana anda cuba mencari sesuatu dalam pinggan, atau, lebih baik, pergi melalui penerangan tentang daftar yang membolehkan dari bahagian tentang membolehkan daftar. Di mana kita akan menemui RCC_APB1ENR dan RCC_APB2ENR:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

Dan mereka, sewajarnya, mengandungi bit yang termasuk penyusunan masa SPI2, IOPB (I/O Port B) dan fungsi alternatif (AFIO).

#define _APB2ENR 0x18
#define _APB1ENR 0x1C

#define IOPBEN 0x0008
#define SPI2EN 0x4000
#define AFIOEN 0x0001

//включаем тактирование порта B и альт. функций
_RCC_(_APB2ENR) |= IOPBEN | AFIOEN;

//включаем  тактирование SPI2
_RCC_(_APB1ENR) |= SPI2EN;

Kod akhir boleh didapati di sini.

Jika anda mempunyai peluang dan keinginan untuk menguji, kemudian sambungkan DM634 seperti ini: DAI ke PB15, DCK ke PB13, LAT ke PB14. Kami memberi kuasa kepada pemandu dari 5 volt, jangan lupa untuk menyambungkan alasan.

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

STM8 PWM

PWM pada STM8

Apabila saya baru merancang artikel ini, saya memutuskan, sebagai contoh, untuk cuba menguasai beberapa fungsi cip yang tidak dikenali hanya menggunakan lembaran data, supaya saya tidak akan berakhir dengan pembuat kasut tanpa but. STM8 adalah sesuai untuk peranan ini: pertama, saya mempunyai beberapa papan Cina dengan STM8S103, dan kedua, ia tidak begitu popular, dan oleh itu godaan untuk membaca dan mencari penyelesaian di Internet terletak pada kekurangan penyelesaian ini.

Cip juga ada Lembaran data и manual rujukan RM0016, pada yang pertama terdapat pinout dan mendaftarkan alamat, pada yang kedua - segala-galanya. STM8 diprogramkan dalam C dalam IDE yang dahsyat ST Visual Membangunkan.

Jam dan I/O

Secara lalai, STM8 beroperasi pada frekuensi 2 MHz, ini mesti diperbetulkan dengan segera.

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Jam HSI (Dalaman Dalaman Berkelajuan Tinggi).
Isyarat jam HSI diperolehi daripada pengayun RC dalaman 16 MHz dengan pembahagi boleh atur cara (1 hingga 8). Ia ditetapkan dalam daftar pembahagi jam (CLK_CKDIVR).
Nota: pada permulaan, pengayun RC HSI dengan pembahagi 8 dipilih sebagai sumber utama isyarat jam.

Kami mencari alamat daftar dalam lembaran data, penerangan dalam refman dan melihat bahawa daftar perlu dikosongkan:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Oleh kerana kita akan menjalankan PWM dan menyambungkan LED, mari lihat pinout:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

Cipnya kecil, banyak fungsi digantung pada pin yang sama. Apa yang terdapat dalam kurungan segi empat sama ialah "fungsi alternatif", ia ditukar oleh "bait pilihan" (bait pilihan) – sesuatu seperti Atmega fius. Anda boleh menukar nilai mereka secara pemrograman, tetapi ia tidak perlu, kerana Fungsi baharu diaktifkan hanya selepas but semula. Lebih mudah untuk menggunakan ST Visual Programmer (dimuat turun dengan Visual Develop), yang boleh menukar bait ini. Pinout menunjukkan bahawa pin CH1 dan CH2 pemasa pertama disembunyikan dalam kurungan segi empat sama; adalah perlu untuk menetapkan bit AFR1 dan AFR0 dalam STVP, dan yang kedua juga akan memindahkan output CH1 pemasa kedua dari PD4 ke PC5.

Oleh itu, 6 pin akan mengawal LED: PC6, PC7 dan PC3 untuk pemasa pertama, PC5, PD3 dan PA3 untuk yang kedua.

Menyediakan pin I/O sendiri pada STM8 adalah lebih mudah dan lebih logik daripada pada STM32:

  • biasa dari daftar arah data DDR Atmega (Daftar Arah Data): 1 = keluaran;
  • daftar kawalan pertama CR1, apabila output, menetapkan mod tolak-tarik (1) atau longkang terbuka (0); kerana saya menyambungkan LED ke cip dengan katod, saya meninggalkan sifar di sini;
  • daftar kawalan kedua CR2, apabila output, menetapkan kelajuan jam: 1 = 10 MHz

#define PA_DDR     *(volatile uint8_t *)0x005002
#define PA_CR2     *(volatile uint8_t *)0x005004
#define PD_DDR     *(volatile uint8_t *)0x005011
#define PD_CR2     *(volatile uint8_t *)0x005013
#define PC_DDR     *(volatile uint8_t *)0x00500C
#define PC_CR2     *(volatile uint8_t *)0x00500E

PA_DDR = (1<<3); //output
PA_CR2 |= (1<<3); //fast
PD_DDR = (1<<3); //output
PD_CR2 |= (1<<3); //fast
PC_DDR = ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //output
PC_CR2 |= ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //fast

tetapan PWM

Pertama, mari kita tentukan istilah:

  • Kekerapan PWM – kekerapan pemasa berdetik;
  • Muat semula automatik, AR – nilai autoloadable sehingga pemasa akan dikira (tempoh nadi);
  • Kemas kini Acara, UEV – peristiwa yang berlaku apabila pemasa telah dikira kepada AR;
  • Kitaran Tugas PWM – Kitaran tugas PWM, sering dipanggil "faktor tugas";
  • Tangkap/Bandingkan Nilai – nilai untuk tangkapan/perbandingan, yang pemasa telah dikira akan melakukan sesuatu (dalam kes PWM, ia menyongsangkan isyarat keluaran);
  • Nilai Pramuat – nilai pramuat. Bandingkan nilai tidak boleh berubah semasa pemasa berdetik, jika tidak, kitaran PWM akan pecah. Oleh itu, nilai yang dihantar baru diletakkan dalam penimbal dan ditarik keluar apabila pemasa mencapai penghujung kira detiknya dan ditetapkan semula;
  • Dijajarkan tepi и Mod sejajar tengah – penjajaran di sepanjang sempadan dan di tengah, sama seperti Atmel PWM pantas и PWM pembetulan fasa.
  • OCiREF, Output Bandingkan Isyarat Rujukan – isyarat keluaran rujukan, sebenarnya, apa yang muncul pada pin yang sepadan dalam mod PWM.

Seperti yang sudah jelas dari pinout, dua pemasa mempunyai keupayaan PWM - yang pertama dan yang kedua. Kedua-duanya adalah 16-bit, yang pertama mempunyai banyak ciri tambahan (khususnya, ia boleh mengira kedua-dua naik dan turun). Kami memerlukan kedua-duanya untuk bekerja sama, jadi saya memutuskan untuk memulakan dengan yang kedua yang jelas lebih miskin, supaya tidak menggunakan sesuatu yang tidak ada secara tidak sengaja. Beberapa masalah ialah perihalan fungsi PWM semua pemasa dalam manual rujukan adalah dalam bab tentang pemasa pertama (17.5.7 Mod PWM), jadi anda perlu melompat ke sana ke mari sepanjang dokumen sepanjang masa.

PWM pada STM8 mempunyai kelebihan penting berbanding PWM pada Atmega:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
PWM Sejajar Sempadan
Konfigurasi akaun dari bawah ke atas
Pengiraan bawah ke atas aktif jika bit DIR dalam daftar TIM_CR1 dikosongkan
Contoh
Contoh menggunakan mod PWM pertama. Isyarat rujukan PWM OCiREF dipegang tinggi selagi TIM1_CNT < TIM1_CCRi. Jika tidak, ia memerlukan tahap yang rendah. Jika nilai perbandingan dalam daftar TIM1_CCRi lebih besar daripada nilai autoload (daftar TIM1_ARR), isyarat OCiREF dipegang pada 1. Jika nilai perbandingan ialah 0, OCiREF dipegang pada sifar....

Pemasa STM8 semasa acara kemas kini semak dulu bandingkan nilai, dan hanya kemudian menghasilkan isyarat rujukan. Pemasa Atmega mula-mula mengosongkan dan kemudian membandingkan, menghasilkan compare value == 0 output adalah jarum, yang mesti ditangani entah bagaimana (contohnya, dengan membalikkan logik secara pemrograman).

Jadi apa yang kita mahu lakukan: 8-bit PWM (AR == 255), mengira dari bawah ke atas, penjajaran di sepanjang sempadan. Memandangkan mentol lampu disambungkan kepada cip oleh katod, PWM harus mengeluarkan 0 (LED dihidupkan) sehingga bandingkan nilai dan 1 selepas.

Kami telah membaca tentang beberapa Mod PWM, jadi kami mencari daftar pemasa kedua yang diperlukan dengan mencari dalam manual rujukan untuk frasa ini (18.6.8 - TIMx_CCMR1):

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
110: Mod PWM pertama – apabila mengira dari bawah ke atas, saluran pertama aktif manakala TIMx_CNT < TIMx_CCR1. Jika tidak, saluran pertama tidak aktif. [selanjutnya dalam dokumen terdapat salinan-tampal yang salah dari pemasa 1] 111: Mod PWM kedua – apabila mengira dari bawah ke atas, saluran pertama tidak aktif manakala TIMx_CNT < TIMx_CCR1. Jika tidak, saluran pertama aktif.

Memandangkan LED disambungkan ke MK oleh katod, mod kedua sesuai dengan kita (yang pertama juga, tetapi kita belum tahu lagi).

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Bit 3 OC1PE: Dayakan pramuat pin 1
0: Daftar pramuat pada TIMx_CCR1 dilumpuhkan. Anda boleh menulis kepada TIMx_CCR1 pada bila-bila masa. Nilai baharu berfungsi serta-merta.
1: Daftar pramuat pada TIMx_CCR1 didayakan. Operasi baca/tulis akses daftar pramuat. Nilai pramuat TIMx_CCR1 dimuatkan ke dalam daftar bayangan semasa setiap acara kemas kini.
*Nota: Untuk mod PWM berfungsi dengan betul, daftar pramuat mesti didayakan. Ini tidak diperlukan dalam mod isyarat tunggal (bit OPM ditetapkan dalam daftar TIMx_CR1).

Okey, mari hidupkan semua yang kita perlukan untuk tiga saluran pemasa kedua:

#define TIM2_CCMR1 *(volatile uint8_t *)0x005307
#define TIM2_CCMR2 *(volatile uint8_t *)0x005308
#define TIM2_CCMR3 *(volatile uint8_t *)0x005309

#define PWM_MODE2   0x70 //PWM mode 2, 0b01110000
#define OCxPE       0x08 //preload enable

TIM2_CCMR1 = (PWM_MODE2 | OCxPE);
TIM2_CCMR2 = (PWM_MODE2 | OCxPE);
TIM2_CCMR3 = (PWM_MODE2 | OCxPE);

AR terdiri daripada dua daftar lapan bit, semuanya mudah:

#define TIM2_ARRH  *(volatile uint8_t *)0x00530F
#define TIM2_ARRL  *(volatile uint8_t *)0x005310

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Pemasa kedua hanya boleh mengira dari bawah ke atas, penjajaran di sepanjang sempadan, tiada apa yang perlu diubah. Mari kita tetapkan pembahagi frekuensi, sebagai contoh, kepada 256. Untuk pemasa kedua, pembahagi ditetapkan dalam daftar TIM2_PSCR dan merupakan kuasa dua:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Apa yang tinggal ialah menghidupkan kesimpulan dan pemasa kedua itu sendiri. Masalah pertama diselesaikan dengan daftar Tangkap/Bandingkan enable: terdapat dua, tiga saluran yang bertaburan merentasinya secara tidak simetri. Di sini kita juga boleh mengetahui bahawa adalah mungkin untuk menukar kekutuban isyarat, i.e. pada dasarnya, adalah mungkin untuk menggunakan Mod PWM 1. Kami menulis:

#define TIM2_CCER1 *(volatile uint8_t *)0x00530A
#define TIM2_CCER2 *(volatile uint8_t *)0x00530B

#define CC1E  (1<<0) // CCER1
#define CC2E  (1<<4) // CCER1
#define CC3E  (1<<0) // CCER2

TIM2_CCER1 = (CC1E | CC2E);
TIM2_CCER2 = CC3E;

Dan akhirnya, kami memulakan pemasa dalam daftar TIMx_CR1:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Mari tulis analog mudah AnalogWrite(), yang akan memindahkan nilai sebenar kepada pemasa untuk perbandingan. Daftar-daftar tersebut dinamakan secara boleh diramalkan Tangkap/Banding daftar, terdapat dua daripadanya untuk setiap saluran: 8 bit tertib rendah dalam TIM2_CCRxL dan tertib tinggi dalam TIM2_CCRxH. Oleh kerana kami telah mencipta PWM 8-bit, cukup untuk menulis hanya bit yang paling tidak ketara:

#define TIM2_CCR1L *(volatile uint8_t *)0x005312
#define TIM2_CCR2L *(volatile uint8_t *)0x005314
#define TIM2_CCR3L *(volatile uint8_t *)0x005316

void setRGBled(uint8_t r, uint8_t g, uint8_t b)
{
    TIM2_CCR1L = r;
    TIM2_CCR2L = g;
    TIM2_CCR3L = b;
}

Pembaca yang penuh perhatian akan menyedari bahawa kami mempunyai PWM yang sedikit rosak, tidak dapat menghasilkan isian 100% (pada nilai maksimum 255, isyarat diterbalikkan untuk satu kitaran pemasa). Untuk LED ini tidak penting, dan pembaca yang penuh perhatian sudah boleh meneka cara membetulkannya.

PWM pada pemasa kedua berfungsi, mari kita beralih kepada yang pertama.

Pemasa pertama mempunyai bit yang betul-betul sama dalam daftar yang sama (hanya bit yang kekal "terpelihara" dalam pemasa kedua secara aktif digunakan dalam yang pertama untuk semua jenis perkara lanjutan). Oleh itu, cukup untuk mencari alamat daftar yang sama dalam lembaran data dan menyalin kod. Nah, tukar nilai pembahagi frekuensi, kerana... pemasa pertama mahu menerima bukan kuasa dua, tetapi nilai 16-bit yang tepat dalam dua daftar Prescaler Tinggi и Rendah. Kami melakukan segala-galanya dan... pemasa pertama tidak berfungsi. Apa masalahnya?

Masalahnya hanya boleh diselesaikan dengan melihat seluruh bahagian mengenai daftar kawalan pemasa 1, di mana kita mencari yang tidak dimiliki oleh pemasa kedua. Akan ada 17.7.30 Daftar rehat (TIM1_BKR), di mana terdapat bit ini:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Dayakan output utama

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

Itu sahaja yang pasti sekarang, kodnya di sana.

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

STM8 Multiplex

Pemultipleksan pada STM8

Projek mini ketiga adalah untuk menyambungkan lapan LED RGB ke pemasa kedua dalam mod PWM dan menjadikannya menunjukkan warna yang berbeza. Ia berdasarkan konsep pemultipleksan LED, iaitu jika anda menghidupkan dan mematikan LED dengan sangat, sangat cepat, nampaknya ia sentiasa hidup (kegigihan penglihatan, inersia persepsi visual). Saya pernah buat sesuatu seperti ini pada Arduino.

Algoritma kerja kelihatan seperti ini:

  • menyambungkan anod LED RGB pertama;
  • menyalakannya, menghantar isyarat yang diperlukan ke katod;
  • menunggu sehingga akhir kitaran PWM;
  • menyambungkan anod LED RGB kedua;
  • nyalakannya...

Nah, dll. Sudah tentu, untuk operasi yang indah diperlukan anod disambungkan dan LED "dinyalakan" pada masa yang sama. Nah, atau hampir. Walau apa pun, kita perlu menulis kod yang akan mengeluarkan nilai dalam tiga saluran pemasa kedua, menukarnya apabila UEV dicapai, dan pada masa yang sama menukar LED RGB yang sedang aktif.

Memandangkan pensuisan LED adalah automatik, kita perlu mencipta "memori video" dari mana pengendali gangguan akan menerima data. Ini adalah tatasusunan mudah:

uint8_t colors[8][3];

Untuk menukar warna LED tertentu, cukup untuk menulis nilai yang diperlukan ke dalam tatasusunan ini. Dan pembolehubah akan bertanggungjawab untuk bilangan LED aktif

uint8_t cnt;

Demux

Untuk pemultipleksan yang betul, kita memerlukan, anehnya, demultiplexer CD74HC238. Demultiplexer - cip yang melaksanakan operator dalam perkakasan <<. Melalui tiga pin input (bit 0, 1 dan 2) kami memberinya nombor tiga bit X, dan sebagai tindak balas ia mengaktifkan nombor output (1<<X). Baki input cip digunakan untuk menskalakan keseluruhan reka bentuk. Kami memerlukan cip ini bukan sahaja untuk mengurangkan bilangan pin mikropengawal yang diduduki, tetapi juga untuk keselamatan - supaya tidak sengaja menghidupkan lebih banyak LED daripada yang mungkin dan tidak membakar MK. Cip itu berharga satu sen dan hendaklah sentiasa disimpan dalam kabinet ubat rumah anda.

CD74HC238 kami akan bertanggungjawab untuk membekalkan voltan ke anod LED yang dikehendaki. Dalam pemultipleks penuh, ia akan membekalkan voltan ke lajur melalui P-MOSFET, tetapi dalam demo ini ia boleh dilakukan secara langsung, kerana ia menarik 20 mA, mengikut penilaian maksimum mutlak dalam lembaran data. daripada Lembaran Data CD74HC238 kami memerlukan pinout dan helaian cheat ini:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
H = aras voltan tinggi, L = aras voltan rendah, X – tak kisah

Kami menyambungkan E2 dan E1 ke tanah, E3, A0, A1 dan A3 ke pin PD5, PC3, PC4 dan PC5 STM8. Memandangkan jadual di atas mengandungi kedua-dua aras rendah dan tinggi, kami mengkonfigurasi pin ini sebagai pin tolak tarik.

PWM

PWM pada pemasa kedua dikonfigurasikan dengan cara yang sama seperti dalam cerita sebelumnya, dengan dua perbezaan:

Pertama, kita perlu mendayakan gangguan dihidupkan Kemas kini Acara (UEV) yang akan memanggil fungsi yang menogol LED aktif. Ini dilakukan dengan menukar bit Kemas Kini Interrupt Enable dalam daftar dengan nama yang jelas

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
Sampuk dayakan daftar

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Perbezaan kedua adalah berkaitan dengan fenomena pemultipleksan, seperti ghosting – cahaya parasit diod. Dalam kes kami, ia mungkin muncul disebabkan oleh fakta bahawa pemasa, setelah menyebabkan gangguan pada UEV, terus berdetik, dan pengendali gangguan tidak mempunyai masa untuk menukar LED sebelum pemasa mula menulis sesuatu pada pin. Untuk memerangi ini, anda perlu menyongsangkan logik (0 = kecerahan maksimum, 255 = tiada yang menyala) dan mengelakkan nilai kitaran tugas yang melampau. Itu. pastikan selepas UEV LED padam sepenuhnya untuk satu kitaran PWM.

Menukar kekutuban:

//set polarity 
    TIM2_CCER1 |= (CC1P | CC2P);
    TIM2_CCER2 |= CC3P;

Elakkan menetapkan r, g dan b kepada 255 dan ingat untuk menyongsangkannya apabila menggunakannya.

menyampuk

Intipati gangguan ialah dalam keadaan tertentu cip berhenti melaksanakan program utama dan memanggil beberapa fungsi luaran. Gangguan berlaku disebabkan oleh pengaruh luaran atau dalaman, termasuk pemasa.

Apabila kami mula-mula mencipta projek dalam ST Visual Develop, sebagai tambahan kepada main.c kami menerima tetingkap dengan fail misteri stm8_interrupt_vector.c, disertakan secara automatik dalam projek. Dalam fail ini, fungsi diberikan kepada setiap gangguan NonHandledInterrupt. Kita perlu mengikat fungsi kita kepada gangguan yang dikehendaki.

Lembaran data mempunyai jadual vektor gangguan, di mana kami mencari yang kami perlukan:

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8
13 Kemas kini/limpahan TIM2
14 TIM2 menangkap/membanding

Kami perlu menukar LED di UEV, jadi kami memerlukan gangguan #13.

Oleh itu, pertama sekali, dalam fail stm8_interrupt_vector.c tukar nama lalai bagi fungsi yang bertanggungjawab untuk gangguan No. 13 (IRQ13) kepada anda sendiri:

{0x82, TIM2_Overflow}, /* irq13 */

Kedua, kita perlu membuat fail main.h dengan kandungan berikut:

#ifndef __MAIN_H
#define __MAIN_H

@far @interrupt void TIM2_Overflow (void);
#endif

Dan akhirnya, tulis fungsi ini dalam anda main.c:

@far @interrupt void TIM2_Overflow (void)
{
    PD_ODR &= ~(1<<5); // вырубаем демультиплексор
    PC_ODR = (cnt<<3); // записываем в демультиплексор новое значение
    PD_ODR |= (1<<5); // включаем демультиплексор

    TIM2_SR1 = 0; // сбрасываем флаг Update Interrupt Pending

    cnt++; 
    cnt &= 7; // двигаем счетчик LED

    TIM2_CCR1L = ~colors[cnt][0]; // передаем в буфер инвертированные значения
    TIM2_CCR2L = ~colors[cnt][1]; // для следующего цикла ШИМ
    TIM2_CCR3L = ~colors[cnt][2]; // 

    return;
}

Yang tinggal hanyalah untuk membolehkan gangguan. Ini dilakukan menggunakan arahan assembler rim - anda perlu mencarinya Manual Pengaturcaraan:

//enable interrupts
_asm("rim");

Satu lagi arahan pemasang ialah sim – mematikan gangguan. Ia mesti dimatikan semasa nilai baharu sedang ditulis pada "memori video", supaya gangguan yang disebabkan pada masa yang salah tidak merosakkan tatasusunan.

Semua kod - pada GitHub.

Membaca lembaran data 2: SPI pada STM32; PWM, pemasa dan gangguan pada STM8

Sekiranya sekurang-kurangnya seseorang mendapati artikel ini berguna, maka saya tidak menulisnya dengan sia-sia. Saya akan gembira menerima komen dan teguran, saya akan cuba menjawab segala-galanya.

Sumber: www.habr.com

Tambah komen