Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

В prvi deo Pokušao sam da kažem hobi inženjerima elektronike koji su izrasli iz Arduino pantalona kako i zašto treba da čitaju tablice i drugu dokumentaciju za mikrokontrolere. Tekst se pokazao velikim, pa sam obećao da ću pokazati praktične primjere u posebnom članku. Pa, on je sebe nazvao utovarivačem...

Danas ću vam pokazati kako koristiti tablice podataka za rješavanje prilično jednostavnih, ali neophodnih zadataka za mnoge projekte na STM32 (Blue Pill) i STM8 kontrolerima. Svi demo projekti su posvećeni mojim omiljenim LED diodama, palićemo ih u velikim količinama, za šta ćemo morati koristiti razne zanimljive periferije.

Tekst se opet pokazao ogromnim, pa radi praktičnosti pravim sadržaj:

STM32 Blue Pill: 16 LED dioda sa DM634 drajverom
STM8: Postavljanje šest PWM pinova
STM8: 8 RGB LED dioda na tri pina, prekidi

Disclaimer: Nisam inženjer, ne pretendujem da imam duboko znanje u elektronici, članak je namijenjen amaterima poput mene. U stvari, prije dvije godine sam sebe smatrao ciljnom publikom. Da mi je neko tada rekao da nije strašno čitati tablice podataka za nepoznati čip, ne bih trošio puno vremena tražeći neke dijelove koda na internetu i izmišljajući štake sa makazama i ljepljivom gipsom.

Fokus ovog članka su listovi sa podacima, a ne projekti, tako da kod možda neće biti previše uglađen i često kao štaka. Sami projekti su vrlo jednostavni, iako su prikladni za prvo upoznavanje s novim čipom.

Nadam se da će moj članak pomoći nekome u sličnoj fazi poniranja u hobi.

STM32

16 LED dioda sa DM634 i SPI

Mali projekat koji koristi Blue Pill (STM32F103C8T6) i DM634 LED drajver. Uz pomoć datasheet-a pozabavićemo se drajverom, STM IO portovima i konfigurisati SPI.

DM634

Tajvanski čip sa 16 x 16-bitnih PWM izlaza, može se povezati. Mlađi 12-bitni model poznat je iz domaćeg projekta lagani paket. Svojevremeno, birajući između DM63x i dobro poznatog TLC5940, odlučio sam se na DM iz nekoliko razloga: 1) TLC na Aliexpressu je definitivno lažan, ali ovaj nije; 2) DM ima autonomni PWM sa sopstvenim generatorom frekvencije; 3) mogao se kupiti jeftino u Moskvi, a ne čekati paket od Alija. I, naravno, bilo je zanimljivo naučiti kako sami kontrolirati čip, a ne koristiti gotovu biblioteku. Čipovi su sada uglavnom predstavljeni u paketu SSOP24, lako se lemljuju na adapteru.

Pošto je proizvođač Tajvanski, list sa podacima na čipu je napisano na kineskom engleskom, što znači da će biti zabavno. Prvo pogledajte pinoutPin veza) da shvatite koju nogu šta spojiti, i opis pinova (Opis pin). 16 pinova:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Sink DC izvori (otvoreni odvod)

Sudoper / Izlaz otvorenog odvoda - zaliha; izvor dolazeće struje; izlaz spojen na masu u aktivnom stanju - LED diode su povezane s drajverom pomoću katoda. Električni, ovo, naravno, nije "otvoreni odvod" (otvoreni odvod), ali u tablicama podataka često se nalazi takva oznaka za izlaze u odvodnom načinu.

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Vanjski otpornici između REXT i GND za postavljanje vrijednosti izlazne struje

Referentni otpornik je instaliran između REXT pina i mase, koji kontroliše unutrašnji otpor izlaza, pogledajte grafikon na stranici 9 u tablici sa podacima. U DM634, ovaj otpor se također može kontrolirati softverom postavljanjem ukupne svjetline (globalna svjetlina); Neću ulaziti u detalje u ovom članku, samo ću ovdje staviti otpornik od 2.2 - 3 kOhm.

Da bismo razumjeli kako kontrolirati čip, pogledajmo opis sučelja uređaja:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

Da, evo ga, kineski engleski u svoj svojoj slavi. Problematično je ovo prevesti, možete to razumjeti ako želite, ali postoji još jedan način - pogledati kako je opisana veza u tablici s funkcionalno bliskim TLC5940:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
… Za unos podataka u uređaj potrebna su samo tri pina. Rastuća ivica SCLK signala pomiče podatke sa SIN pina u interni registar. Nakon što su svi podaci učitani, kratki visoki XLAT signal zatvara serijski prenesene podatke u interne registre. Interni registri su kapije koje pokreće XLAT nivo signala. Svi podaci se prvo prenose MSB.

Latch - zasun / zasun / zasun.
rastuća ivica je prednja ivica pulsa
Prvo MSB – najznačajniji (krajnji lijevi) bit naprijed.
na podatke sata – prenos podataka sekvencijalno (bit po bit).

Reč latch često se nalazi u dokumentaciji za čipove i prevodi se na razne načine, pa ću za razumijevanje dozvoliti sebi

mali obrazovni programLED drajver je u suštini pomerački registar. "Shift" (smjena) u nazivu - bit po bit kretanje podataka unutar uređaja: svaki novi bit gurnut unutra gura cijeli lanac naprijed ispred sebe. Pošto niko ne želi da posmatra haotično treptanje LED dioda tokom smene, proces se odvija u bafer registrima odvojenim od radnika zatvaračem (latch) je svojevrsna svlačionica u kojoj se bitovi redaju u željenom nizu. Kada je sve spremno, zatvarač se otvara i bitovi idu na posao, zamjenjujući prethodnu seriju. Riječ latch u dokumentaciji za mikro krugove gotovo uvijek se podrazumijeva takav prigušivač, u kojim god kombinacijama se koristi.

Dakle, prijenos podataka na DM634 se vrši na sljedeći način: postavite DAI ulaz na vrijednost visokog bita dalekog LED-a, povucite DCK gore-dolje; postavite DAI ulaz na vrijednost sljedećeg bita, povucite DCK; i tako sve dok se svi bitovi ne prenesu (uklj), nakon čega povlačimo LAT. Ovo se može uraditi ručnobit bang), ali za to je bolje koristiti posebno izoštreno SPI sučelje, budući da je na našem STM32 predstavljeno u dva primjerka.

Plava tableta STM32F103

Uvodno: STM32 kontroleri su mnogo komplikovaniji od Atmega328 nego što mogu biti zastrašujući. Istovremeno, iz razloga uštede energije, skoro sve periferije su isključene u startu, a frekvencija takta je 8 MHz iz internog izvora. Srećom, STM programeri su napisali kod koji dovodi čip na "izračunatih" 72 MHz, a autori svih meni poznatih IDE-ova uključili su ga u proceduru inicijalizacije, tako da ne trebamo taktirati (ali možeš ako zaista želiš). Ali morate uključiti periferne uređaje.

Dokumentacija: Popularni STM32F103C8T6 čip je instaliran na Blue Pill, za njega postoje dva korisna dokumenta:

U tablici podataka može nas zanimati:

  • Pinouts - pinout chip - u slučaju da se odlučimo za izradu ploča sami;
  • Memorijska karta - memorijska mapa za određeni čip. Referentni priručnik ima kartu za cijelu liniju, spominje registre kojih nema na našem.
  • Tablica definicija pinova - lista glavnih i alternativnih funkcija pinova; za "plavu pilulu" na Internetu možete pronaći prikladnije slike s popisom pribadača i njihovih funkcija. Stoga, odmah google Blue Pill pinout i držimo ovu sliku pri ruci:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
NB: došlo je do greške na slici sa interneta, primećene u komentarima, na čemu hvala. Slika je zamijenjena, ali ovo je lekcija - bolje je provjeriti informacije ne iz tablica podataka.

Uklanjamo datasheet, otvaramo Referentni priručnik, od sada koristimo samo njega.
Procedura: pozabavite se standardnim ulazom/izlazom, konfigurirajte SPI, uključite potrebne periferije.

Ulaz Izlaz

Na Atmega328, I/O je izuzetno jednostavan, zbog čega obilje STM32 opcija može biti zbunjujuće. Sada nam trebaju samo zaključci, ali čak i postoje četiri opcije:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Otvoreni izlaz za odvod, Push-Pull izlaz, Push-Pull naizmjenični, otvoreni-Drain naizmjenični

"Povuci-guraj" (push-pull) - uobičajeni izlaz iz Arduina, pin može biti HIGH ili LOW. Ali sa "otvorenim odvodom" nastaju teškoće, iako je u stvari ovdje sve jednostavno:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Izlazna konfiguracija / kada je port dodijeljen izlazu: / izlazni bafer omogućen: / – način rada otvorenog odvoda: "0" u izlaznom registru omogućava N-MOS, "1" u izlaznom registru ostavlja port u Hi-Z modu (P -MOS nije aktiviran ) / - push-pull mod: "0" u izlaznom registru aktivira N-MOS, "1" u izlaznom registru aktivira P-MOS.

Razlika svih otvorenih odvoda (otvoreni odvod) od "push-pull" (push-pull) je da u prvom pinu ne može zauzeti HIGH stanje: kada se jedinica upiše u izlazni registar, ona prelazi u režim visokog otpora (visoka impedancija, Hi-Z). Kada upisujete nulu, pin u oba načina se ponaša isto, i logički i električni.

U normalnom izlaznom modu, pin jednostavno prevodi sadržaj izlaznog registra. U "alternativi" ga kontrolira odgovarajuća periferija (vidi 9.1.4):

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Ako je bit porta konfiguriran kao izlaz alternativne funkcije, izlazni registar je onemogućen i pin je spojen na izlazni signal periferije.

Alternativna funkcionalnost svake igle je opisana u Definicije pin-a Datasheet se nalazi na preuzetoj slici. Na pitanje šta učiniti ako pin ima nekoliko alternativnih funkcija, odgovor je dat fusnotom u podatkovnoj tablici:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Ako više perifernih uređaja koristi isti pin, kako bi se izbjegao sukob između alternativnih funkcija, treba koristiti samo jednu periferiju u isto vrijeme, prebacivanjem pomoću bita za omogućavanje perifernog sata (u odgovarajućem RCC registru).

Konačno, pinovi u izlaznom režimu takođe imaju brzinu takta. Ovo je još jedna funkcija za uštedu energije, u našem slučaju samo je postavimo na maksimum i zaboravimo.

Dakle: koristimo SPI, što znači da dva pina (sa podacima i sa taktnim signalom) treba da budu “alternativna push-pull funkcija”, a još jedan (LAT) treba da bude “normalan push-pull”. Ali prije nego što ih dodijelimo, pozabavimo se SPI.

SPI

Još jedan mali hak

SPI ili Serial Peripheral Interface (serijski periferni interfejs) je jednostavan i vrlo efikasan interfejs za komunikaciju MK-a sa drugim MK-ovima i spoljnim svetom uopšte. Princip njegovog rada je već opisan gore, gdje se radi o kineskom LED drajveru (pogledajte odjeljak 25 u referentnom priručniku). SPI može raditi u master ("master") i slave ("slave") modovima. SPI ima četiri osnovna kanala, od kojih nisu svi uključeni:

  • MOSI, glavni izlaz / slave ulaz: ovaj pin šalje podatke u master modu i prima podatke u slave modu;
  • MISO, glavni ulaz / slave izlaz: naprotiv, u masteru prima, u slaveu daje;
  • SCK, Serial Clock: postavlja frekvenciju prijenosa podataka u glavnom ili prima signal takta u slave-u. U suštini, beats the beats;
  • SS, Slave Select: sa ovim kanalom rob zna da želi nešto od njega. Na STM32 se zove NSS, gdje je N = negativan, tj. kontroler postaje slave ako ovaj kanal ima uzemljenje. Dobro se kombinuje sa Open Drain Output modom, ali to je druga priča.

Kao i sve ostalo, SPI na STM32 je bogat funkcionalnošću, što ga čini pomalo teškim za razumijevanje. Na primjer, može raditi ne samo sa SPI, već i sa I2S sučeljem, a njihovi opisi su pomiješani u dokumentaciji, potrebno je pravovremeno odrezati višak. Naš zadatak je krajnje jednostavan: samo trebate dati podatke koristeći samo MOSI i SCK. Idemo na odjeljak 25.3.4 (poludupleks komunikacija, poludupleks komunikacija), gdje nalazimo 1 sat i 1 jednosmjerna žica za prijenos podataka (1 sat i 1 jednosmjerni tok podataka):

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
U ovom načinu, aplikacija koristi SPI u načinu rada samo za prijenos ili samo za prijem. / Režim samo za prijenos sličan je duplex modu: podaci se prenose na pin za prijenos (MOSI u master modu ili MISO u slave modu), dok se pin za prijem (MISO ili MOSI respektivno) može koristiti kao normalan I/O pin. U ovom slučaju, dovoljno je da aplikacija ignoriše Rx bafer (ako je pročitan, neće biti prenesenih podataka).

Odlično, MISO pin je slobodan, spojimo LAT signal na njega. Hajde da se pozabavimo Slave Select-om, koji se može kontrolisati programski na STM32, što je izuzetno zgodno. Čitamo istoimeni paragraf u odeljku 25.3.1 Opšti opis SPI:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
NSS softverska kontrola (SSM = 1) / Informacije o odabiru slave-a sadržane su u SSI bitu registra SPI_CR1. Eksterni NSS pin je ostavljen slobodan za druge potrebe aplikacije.

Vrijeme je za upis u registre. Odlučio sam da koristim SPI2, tražimo njegovu osnovnu adresu u datasheetu - u odjeljku 3.3 Memorijska karta (Memory Map):

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

Pa, da počnemo:

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

Otvaramo odeljak 25.3.3 sa upečatljivim naslovom "Konfigurisanje SPI u master modu":

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

1. Postavite sat serijskog interfejsa sa BR[2:0] bitovima u registru SPI_CR1.

Registri se prikupljaju u istoimenom dijelu referentnog priručnika. Promjena adrese (pomak adrese) CR1 ima 0x00, po defaultu su svi bitovi obrisani (Poništi vrijednost 0x0000):

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

BR bitovi postavljaju djelitelj sata kontrolera, određujući tako frekvenciju na kojoj će SPI raditi. Frekvencija STM32 će biti 72 MHz, LED drajver, prema njegovom datasheet-u, radi na frekvenciji do 25 MHz, tako da moramo podijeliti sa četiri (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. Postavite CPOL i CPHA bitove da definirate odnos između prijenosa podataka i sata serijskog sučelja (pogledajte dijagram na stranici 240)

Pošto ovdje čitamo tablicu sa podacima, a ne gledamo sheme, pogledajmo detaljnije tekstualni opis CPOL i CPHA bitova na stranici 704 (SPI opšti opis):

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Faza i polaritet sata
Koristeći CPOL i CPHA bite registra SPI_CR1, možete programski odabrati četiri opcije za omjere vremena. CPOL (Clock Polarity) bit kontrolira stanje signala sata kada se ne prenose podaci. Ovaj bit kontrolira master i slave modove. Ako se CPOL resetuje, pin SCK je nizak u mirovanju. Ako je CPOL bit postavljen, SCK pin je visok kada je u stanju mirovanja.
Ako je CPHA (Clock Phase) bit postavljen, MSB trap strobe je druga ivica SCK signala (pada ako je CPOL obrisan, ili rastuća ivica ako je CPOL postavljen). Podaci se fiksiraju pri drugoj promjeni sata. Ako je CPHA bit obrisan, rastući rub SCK signala (padajući rub ako je CPOL postavljen, ili rastući rub ako je CPOL čist) služi kao strob za zamku visokog bita. Podaci se fiksiraju pri prvoj promeni sata.

Nakon što smo okusili ovo znanje, dolazimo do zaključka da oba bita moraju ostati nula, jer želimo da SCK signal ostane nizak kada se ne koristi, a podaci da se prenose na rastućoj ivici impulsa (vidi sl. rastuća ivica u tablici sa podacima DM634).

Usput, ovdje smo se prvi put susreli sa značajkom vokabulara u ST tablicama podataka: u njima je napisana fraza "postavi bit na nulu" da malo resetujem, a ne da se malo razbistri, kao, na primjer, Atmega.

3. Postavite DFF bit da odredite 8-bitni ili 16-bitni format bloka podataka

Posebno sam uzeo 16-bitni DM634 kako se ne bih mučio s prijenosom 12-bitnih PWM podataka, poput DM633. DFF ima smisla staviti u jedinstvo:

#define DFF         0x0800

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

4. Konfigurirajte LSBFIRST bit u registru SPI_CR1 da definirate format bloka

LSBFIRST, kao što mu ime implicira, prvo postavlja prijenos s najmanjim bitom. Ali DM634 želi prvo primiti MSB podataka. Stoga ga ostavljamo resetiranom.

5. U hardverskom režimu, ako je potreban unos sa NSS pina, povisite NSS pin tokom čitave sekvence prenosa bajtova. U režimu NSS programa, postavite SSM i SSI bitove u registru SPI_CR1. Ako NSS pin treba biti izlaz, potrebno je postaviti samo SSOE bit.

Instalirajte SSM i SSI da zaboravite na NSS hardverski način rada:

#define SSI         0x0100
#define SSM         0x0200

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

6. MSTR i SPE bitovi moraju biti postavljeni (oni ostaju postavljeni samo ako je NSS visok)

Zapravo, sa ovim bitovima dodjeljujemo našem SPI kao master i uključujemo ga:

#define MSTR        0x0004
#define SPE         0x0040

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

SPI je konfigurisan, hajde da odmah napišemo funkcije koje šalju bajtove drajveru. Nastavite čitati 25.3.3 "Konfiguriranje SPI u glavnom modu":

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Procedura prijenosa podataka
Prijenos počinje kada se bajt upiše u Tx bafer.
Bajt podataka se učitava u pomični registar na paralelno modu (sa interne magistrale) tokom prijenosa prvog bita, nakon čega se prenosi u dosljedan MOSI pin mod, prvi ili zadnji bit naprijed ovisno o postavci LSBFIRST bita u registru CPI_CR1. TXE zastavica se postavlja nakon prijenosa podataka iz Tx bafera u pomak registra, i generira se prekid ako je postavljen TXEIE bit u registru CPI_CR1.

Istaknuo sam nekoliko riječi u prijevodu kako bih skrenuo pažnju na jednu osobinu implementacije SPI u STM kontrolerima. Na Atmegi, TXE zastava (Tx Empty, Tx je prazan i spreman za primanje podataka) se postavlja tek nakon što je cijeli bajt poslan napolje. I ovdje se ova zastavica postavlja nakon što je bajt ubačen u interni pomakni registar. Pošto se tamo ubacuje sa svim bitovima u isto vreme (paralelno), a zatim se podaci prenose sekvencijalno, TXE se postavlja pre nego što se bajt u potpunosti pošalje. Ovo je važno jer u slučaju našeg LED drajvera, moramo povući LAT pin nakon slanja всех podataka, tj. samo TXE zastava nam neće biti dovoljna.

Što znači da nam treba još jedna zastava. Pogledajmo 25.3.7 - "Zastavice statusa":

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
<…>
Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
BUSY flag
BSY zastavicu postavlja i briše hardver (upisivanje u nju nema efekta). Oznaka BSY označava stanje komunikacijskog sloja SPI.
Resetuje se:
kada je prijenos završen (osim u master modu ako je prijenos kontinuiran)
kada je SPI onemogućen
kada se pojavi greška glavnog moda (MODF=1)
Ako prijenos nije kontinuiran, BSY zastavica se briše između svakog prijenosa podataka.

Dobro, dobro će doći. Saznajte gdje se nalazi Tx bafer. Da biste to učinili, pročitajte "SPI registar podataka":

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Bitovi 15:0 DR[15:0] Registar podataka
Primljeni podaci ili podaci za prijenos.
Registar podataka je podijeljen u dva bafera, jedan za pisanje (bafer za prijenos) i jedan za čitanje (međuspremnik za prijem). Upisivanje u registar podataka upisuje u Tx bafer, a čitanje iz registra podataka će vratiti vrijednost sadržanu u Rx baferu.

Pa, statusni registar, gdje se nalaze TXE i BSY zastavice:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

Mi pišemo:

#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
}

Pa, pošto trebamo prenijeti 16 puta dva bajta, prema broju izlaza LED drajvera, otprilike ovako:

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();
}

Ali još ne znamo kako da izvučemo LAT pin, pa se vratimo na I/O.

Dodijelite pinove

U STM32F1, registri odgovorni za stanje pinova su prilično neobični. Jasno je da ih ima više od Atmege, ali se i razlikuju od ostalih STM čipova. Odjeljak 9.1 GPIO Opšti opis:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Svaki od I/O portova opće namjene (GPIO) ima dva 32-bitna konfiguraciona registra (GPIOx_CRL i GPIOx_CRH), dva 32-bitna registra podataka (GPIOx_IDR i GPIOx_ODR), 32-bitni registar za postavljanje/resetovanje (GPIOx_BSRR), 16-bitni registar za resetovanje (GPIOx_BRR) i 32-bitni registar za poništavanje. registar za blokiranje bitova (GPIOx_LCKR).

Neobična, ali i prilično nezgodna, su prva dva registra ovdje, jer je 16 pinova porta razbacano po njima u formatu “četiri bita po bratu”. One. pinovi od XNUMX do XNUMX su u CRL, a ostali su u CRH. U isto vrijeme, preostali registri uspješno uklapaju bitove svih pinova porta - često ostajući polovina "rezervirana".

Radi jednostavnosti, počnimo od kraja liste.

Ne treba nam registar blokiranja.

Postavljanje i reset registri su prilično smiješni po tome što se djelimično dupliraju: sve možete napisati samo u BSRR, gdje će gornjih 16 bitova resetirati pin na nulu, a nižih će biti postavljeno na 1, ili možete također koristite BRR, od kojih nižih 16 bitova samo resetuju pin. Sviđa mi se druga opcija. Ovi registri su važni jer pružaju atomski pristup pinovima:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Atomska instalacija ili resetiranje
Ne morate onemogućiti prekide kada programirate GPIOx_ODR na nivou bita: možete promijeniti jedan ili više bitova s ​​jednom APB2 atomskom operacijom pisanja. Ovo se postiže upisivanjem "1" u registar za postavljanje/resetovanje (GPIOx_BSRR ili, samo za resetovanje, GPIOx_BRR) bita koji treba promeniti. Ostali bitovi će ostati nepromijenjeni.

Registri podataka imaju prilično izgovorena imena - IDR = ulazni Registar pravaca, ulazni registar; ODR= izlaz Registar smjera, izlazni registar. U trenutnom projektu oni nam nisu potrebni.

I konačno, kontrolni registri. Pošto nas zanimaju pinovi drugog SPI-a, odnosno PB13, PB14 i PB15, odmah gledamo CRH:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

I vidimo da će od 20. do 31. biti potrebno nešto napisati u bitovima.

Već smo shvatili šta želimo od gornjih pinova, pa ću ovdje učiniti bez snimka ekrana, samo kažem da MODE postavlja smjer (ulaz ako su oba bita postavljena na 0) i brzinu pina (treba nam 50MHz, tj. oba pin na "1"), a CNF postavlja režim: normalno "push-push" - 00, "alternative" - ​​10. Po defaultu, kao što možemo vidjeti gore, svi pinovi imaju treći bit odozdo ( CNF0), postavlja ih u način rada plutajući ulaz.

Pošto planiram da uradim nešto drugo sa ovim čipom, radi jednostavnosti, generalno sam definisao sve moguće MODE i CNF vrednosti i za donji i za gornji kontrolni registr.

Nekako ovako

#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

Naši pinovi su na portu B (bazna adresa - 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;

I, shodno tome, možete napisati definicije za LAT, koje će trzati BRR i BSRR registre:

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

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

(LAT_nisko samo po inerciji, nekako je uvijek bilo, neka ostane za sebe)

Sada je sve super, ali ne ide. Budući da je ovo STM32, ovdje štede struju, što znači da morate uključiti clocking potrebne periferije.

Uključite taktiranje

Sat je odgovoran za taktiranje, oni su također Clock. I već smo mogli primijetiti skraćenicu RCC. Tražimo ga u dokumentaciji: ovo je Reset and Clock Control (Upravljanje resetovanjem i taktom).

Kao što je gore pomenuto, srećom, ljudi iz STM-a su nam odradili najteži dio teme clockanja, na čemu im veliko hvala (opet ću dati link na Di Haltova web stranicada bude jasno koliko je to zbunjeno). Potrebni su nam samo registri odgovorni za omogućavanje perifernog takta (Peripheral Clock Enable Registers). Prvo, pronađimo osnovnu adresu RCC-a, ona je na samom početku "Memorijske kartice":

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

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

I onda ili kliknite na link gdje da pokušate pronaći nešto u tabeli, ili, mnogo bolje, pređite opise uključenih registara iz odjeljaka o omogućiti registre. Gdje nalazimo RCC_APB1ENR i RCC_APB2ENR:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

I u njima, redom, bitovi koji uključuju taktiranje SPI2, IOPB (I / O Port B) i alternativne funkcije (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;

Konačan kod se može pronaći ovdje.

Ako postoji prilika i želja za testiranjem, onda povezujemo DM634 ovako: DAI na PB15, DCK na PB13, LAT na PB14. Vozača hranimo od 5 volti, ne zaboravite kombinirati uzemljenje.

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

STM8 PWM

PWM na STM8

Kada sam tek planirao ovaj članak, odlučio sam, na primjer, pokušati savladati neku funkcionalnost nepoznatog čipa uz pomoć samo datasheet-a, kako obućar ne bi ispao bez čizama. STM8 je bio savršen za ovu ulogu: prvo, imao sam nekoliko kineskih ploča sa STM8S103, a drugo, nije baš popularan, pa stoga iskušenje da pročitate i nađete rješenje na internetu počiva na odsustvu istih rješenja.

Čip takođe ima list sa podacima и referentni priručnik RM0016, u prvom pinout i registar adrese, u drugom - sve ostalo. Programiranje STM8 u C u ružnom IDE-u ST Visual Develop.

Sat i I/O

Standardno, STM8 radi na frekvenciji od 2 MHz, to se mora odmah ispraviti.

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
HSI sat (visoki interni)
HSI takt je izveden iz internog RC oscilatora od 16 MHz sa programabilnim djeliteljem (1 do 8). Postavlja se u registru razdjelnika sata (CLK_CKDIVR).
Napomena: HSI RC oscilator sa djeliteljem od 8 je odabran kao glavni izvor takta pri pokretanju.

Pronalazimo adresu registra u datasheet-u, opis u refman-u i vidimo da registar treba obrisati:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Pošto ćemo pokrenuti PWM i povezati LED diode, pogledajmo pinout:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

Čip je mali, mnoge funkcije su suspendovane na istim pinovima. Ono što je u uglastim zagradama je "alternativna funkcionalnost", ona se prebacuje sa "opcijskim bajtovima" (bajtova opcija) - nešto poput Atmega osigurača. Njihove vrijednosti možete promijeniti programski, ali to nije neophodno, jer. Nova funkcionalnost se aktivira tek nakon ponovnog pokretanja. Lakše je koristiti ST Visual Programmer (preuzet uz Visual Develop), koji može promijeniti ove bajtove. Pinout pokazuje da su izlazi CH1 i CH2 prvog tajmera skriveni u uglastim zagradama; potrebno je postaviti AFR1 i AFR0 bitove u STVP, a drugi će također prenijeti izlaz CH1 drugog tajmera sa PD4 na PC5.

Tako će 6 pinova kontrolirati LED diode: PC6, PC7 i PC3 za prvi tajmer, PC5, PD3 i PA3 za drugi.

Postavljanje samih I/O pinova na STM8 je jednostavnije i logičnije nego na STM32:

  • Atmega-poznati registar smjera podataka DDR (Registar smjernica podataka): 1 = izlaz;
  • prvi kontrolni registar CR1, na izlazu, postavlja push-pull mod (1) ili otvoreni odvod (0); pošto spajam LED diode na čip sa katodama, ovdje ostavljam nule;
  • drugi kontrolni registar CR2 postavlja brzinu takta pri izlazu: 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

PWM postavka

Prvo, hajde da definišemo pojmove:

  • Frekvencija PWM-a – učestalost kojom tajmer otkucava;
  • Automatsko ponovno punjenje, AR – automatski učitana vrijednost do koje će tajmer računati (period impulsa);
  • Događaj ažuriranja, UEV – događaj koji se javlja kada je tajmer odbrojao do AR;
  • PWM radni ciklus - PWM radni ciklus, koji se često naziva "radni ciklus";
  • Snimite/uporedite vrijednost – vrijednost koju treba uhvatiti/uporediti, računajući do koje tajmer uradiće nešto (u slučaju PWM, on invertuje izlazni signal);
  • vrijednost predopterećenja – unaprijed učitana vrijednost. uporedi vrijednost ne može se promijeniti dok tajmer otkucava, inače će se PWM ciklus prekinuti. Stoga se nove prenesene vrijednosti stavljaju u međuspremnik i izvlače kada tajmer dođe do kraja odbrojavanja i resetuje se;
  • Poravnano po ivicama и Režimi poravnati po sredini – poravnanje na ivici i u centru, isto kao i atmelovskie Brzi PWM и Fazno ispravan PWM.
  • OCiREF, Referentni signal za usporedbu izlaza - referentni izlazni signal, zapravo, ono što se pojavljuje na odgovarajućem pinu u PWM modu.

Kao što je već jasno iz pinouta, dva tajmera imaju PWM mogućnosti - prvi i drugi. Oba su 16-bitna, a prvi ima puno dodatnih funkcija (posebno, može brojati i gore i dolje). Oboje treba da radimo na isti način, pa sam odlučio da počnem sa očigledno lošijom drugom, da slučajno ne koristim nešto čega nema. Neki problem je što je opis PWM funkcionalnosti svih tajmera u referentnom priručniku u poglavlju o prvom tajmeru (17.5.7 PWM način rada), tako da morate stalno skakati naprijed-nazad kroz dokument.

PWM na STM8 ima važnu prednost u odnosu na Atmega PWM:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
PWM sa poravnavanjem ivica
Konfiguracija računa odozdo prema gore
Prebrojavanje je aktivno ako je DIR bit u registru TIM_CR1 čist
Primjer:
Primjer koristi prvi PWM način rada. PWM referentni signal OCiREF se drži visokim sve dok TIM1_CNT < TIM1_CCRi. U suprotnom, potreban je nizak nivo. Ako je vrijednost za poređenje u TIM1_CCRi registru veća od vrijednosti automatskog učitavanja (TIM1_ARR registar), OCiREF signal se drži na 1. Ako je vrijednost poređenja 0, OCiREF se drži na nuli....

STM8 tajmer tokom ažuriranje događaja prvo proverava uporedi vrijednost, i tek tada proizvodi referentni signal. U Atmegi tajmer prvo drhti, a zatim se upoređuje, zbog čega, kada compare value == 0 izlaz je igla s kojom se mora nekako riješiti (na primjer, programskim invertiranjem logike).

Dakle, šta želimo da uradimo: 8-bitni PWM (AR == 255), računajući odozdo prema gore, poravnanje duž granice. Pošto su sijalice povezane sa čipom katodama, PWM bi trebao da daje 0 (LED uključen) sve dok uporedi vrijednost i 1 poslije.

O nekima smo već čitali PWM mod, tako da pronalazimo željeni registar drugog tajmera pretragom u referentnom priručniku za ovu frazu (18.6.8 - TIMx_CCMR1):

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
110: Prvi PWM mod - kada se broji odozdo prema gore, prvi kanal je aktivan sve dok je TIMx_CNT < TIMx_CCR1. U suprotnom, prvi kanal je neaktivan. [dalje u dokumentu, pogrešan copy-paste sa tajmera 1] 111: Drugi PWM mod - kada se broji odozdo prema gore, prvi kanal je neaktivan sve dok TIMx_CNT < TIMx_CCR1. U suprotnom, prvi kanal je aktivan.

S obzirom da su LED diode spojene na MK katodama, drugi način rada nam odgovara (i prvi, ali to još ne znamo).

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Bit 3 OC1PE: Omogući izlaz za predučitavanje 1
0: Predučitavanje registra na TIMx_CCR1 onemogućeno. Možete pisati na TIMx_CCR1 u bilo koje vrijeme. Nova vrijednost djeluje odmah.
1: Predučitavanje registra na TIMx_CCR1 omogućeno. Operacije čitanja/pisanja pristupaju predučitavanju registra. Unaprijed učitana vrijednost TIMx_CCR1 se učitava u sjeni registar za vrijeme svakog događaja ažuriranja.
*Napomena: Registri prethodnog učitavanja moraju biti omogućeni da bi PWM način rada ispravno radio. Ovo je opciono u režimu jednog signala (OPM bit je postavljen u TIMx_CR1 registru).

U redu, uključite sve što vam treba za tri kanala drugog tajmera:

#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 se sastoji od dva osmobitna registra, ovdje je sve jednostavno:

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

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Drugi tajmer može brojati samo odozdo prema gore, poravnanje na ivici, ništa ne treba mijenjati. Postavite djelitelj frekvencije, na primjer, na 256. Za drugi tajmer, djelitelj je postavljen u TIM2_PSCR registru i ima snagu dva:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Ostaje uključiti zaključke i sam drugi mjerač vremena. Prvi zadatak rješavaju registri Snimite/uporedite omogućiti: ima ih dva, tri kanala su asimetrično razbacana po njima. Ovdje također možemo naučiti da je moguće promijeniti polaritet signala, tj. u principu bi se mogao koristiti i PWM Mode 1. Pišemo:

#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;

I konačno, pokrećemo tajmer u registru TIMx_CR1:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Napišimo jednostavan analog AnalogWrite (), koji će prenijeti stvarne vrijednosti ​​Timeru radi poređenja. Registri su predvidljivo imenovani Registri za snimanje/uporedi, postoje dva od njih za svaki kanal: nižih 8 bitova u TIM2_CCRxL i visokih bitova u TIM2_CCRxH. Pošto smo započeli 8-bitni PWM, dovoljno je napisati samo niske bitove:

#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;
}

Pažljivi čitalac će primijetiti da imamo malo neispravan PWM, koji ne može dati 100% popunjenosti (na maksimalnoj vrijednosti od 255, signal se invertuje jednim ciklusom tajmera). Za LED diode to ne igra ulogu, a pažljivi čitatelj već pogađa kako to popraviti.

PWM na drugom tajmeru radi, idite na prvi.

Prvi tajmer ima potpuno iste bitove u istim registrima (samo oni bitovi koji su ostali "rezervirani" u drugom tajmeru se aktivno koriste za sve vrste naprednih stvari u prvom). Stoga je dovoljno pronaći adrese istih registara u podatkovnom listu i kopirati kod. Pa, promijenite vrijednost djelitelja frekvencije, jer. prvi tajmer želi dobiti ne stepen dvojke, već tačnu 16-bitnu vrijednost u dva registra Prescaler High и nizak. Radimo sve i ... prvi tajmer ne radi. Sta je bilo?

Jedini način da riješimo problem je da pogledamo cijeli dio o kontrolnim registrima tajmera 1, gdje tražimo onaj koji drugi tajmer nema. tamo će biti 17.7.30 Break registar (TIM1_BKR), gdje postoji nešto ovako:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Omogućite glavni izlaz

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

To je sve za sada, kod na istom mestu.

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

STM8 Multipleks

Multipleksiranje na STM8

Treći mini-projekat je da poveže osam RGB LED dioda na drugi tajmer u PWM modu i učini ih da pokazuju različite boje. Bazira se na konceptu LED multipleksiranja, koji se sastoji u tome da ako uključite i isključite LED diode vrlo, vrlo brzo, činit će nam se da su stalno upaljene (postojanost vida, inercija vizuelne percepcije). Jednom sam tako nešto na arduinu.

Algoritam rada izgleda ovako:

  • spojio anodu prve RGB LED diode;
  • upalio, dajući potrebne signale katodama;
  • čekao kraj PWM ciklusa;
  • spojio anodu druge RGB LED diode;
  • zapalio...

pa itd. Naravno, za lijep rad potrebno je da se anodna veza i "paljenje" LED-a odvijaju istovremeno. Pa, skoro. U svakom slučaju, trebamo napisati kod koji će emitovati vrijednosti ​​​u tri kanala drugog tajmera, mijenjati ih kada se dostigne UEV i istovremeno mijenjati trenutno aktivnu RGB LED diodu.

Pošto je LED prebacivanje automatsko, potrebno je da kreirate "video memoriju" odakle će rukovalac prekida primati podatke. Ovo je jednostavan niz:

uint8_t colors[8][3];

Da biste promijenili boju određene LED diode, bit će dovoljno upisati potrebne vrijednosti u ovaj niz. A varijabla će biti odgovorna za broj aktivne LED diode

uint8_t cnt;

Demux

Za pravilno multipleksiranje, potreban nam je, začudo, CD74HC238 demultiplekser. Demultiplekser - čip koji implementira operator u hardver <<. Kroz tri ulazna pina (bitovi 0, 1 i 2) unosimo mu trobitni broj X, a on kao odgovor aktivira izlazni broj (1<<X). Preostali ulazi čipa se koriste za skaliranje cijelog dizajna. Ovaj čip nam je potreban ne samo da smanjimo broj zauzetih pinova mikrokontrolera, već i zbog sigurnosti - kako slučajno ne bismo uključili više LED dioda nego što je moguće i ne spalili MK. Čip košta peni, uvijek ga treba držati u kutiji prve pomoći kod kuće.

CD74HC238 će biti odgovoran za dovod napona na anodu željene LED diode. U punopravnom multipleksu, on bi doveo napon na kolonu preko P-MOSFET-a, ali u ovom demonstraciji to možete učiniti direktno, jer. povlači 20mA, prema apsolutne maksimalne ocjene u tablici sa podacima. Od datasheet CD74HC238 trebamo pinout i ovaj cheat sheet:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
H = nivo visokog napona, L = nivo niskog napona, X - nije briga

Povezujemo E2 i E1 na masu, E3, A0, A1 i A3 na pinove PD5, PC3, PC4 i PC5 STM8. Pošto gornja tabela sadrži i niske i visoke nivoe, postavili smo ove igle kao push-pull igle.

PWM

PWM na drugom tajmeru je konfigurisan na isti način kao u prethodnoj priči, sa dvije razlike:

Prvo, moramo uključiti prekid Ažuriraj događaj (UEV) koji će pozvati funkciju za prebacivanje aktivne LED diode. To se radi promjenom bita Omogućavanje prekida ažuriranja u registru sa govornim imenom

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
Registar omogućavanja prekida

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Druga razlika je povezana sa takvim fenomenom multipleksiranja kao što je ghosting - parazitski sjaj dioda. U našem slučaju, to se može pojaviti zbog činjenice da tajmer, nakon što je izazvao prekid na UEV-u, nastavlja otkucavati, a rukovalac prekida nema vremena da prebaci LED prije nego što tajmer počne nešto pisati na izlaze. Da biste se borili protiv ovoga, morat ćete invertirati logiku (0 = maksimalna svjetlina, 255 = ništa nije uključeno) i ne dozvoliti ekstremne vrijednosti radnog ciklusa. One. osigurajte da se nakon UEV-a LED diode potpuno ugase za jedan PWM ciklus.

Promijenite polaritet:

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

Izbjegavajte postavljanje r, g i b na 255 i ne zaboravite ih obrnuti kada koristite.

Prekida

Suština prekida je da, pod određenim okolnostima, čip prestane da izvršava glavni program i pozove neku eksternu funkciju. Do prekida dolazi zbog vanjskih ili unutrašnjih utjecaja, uključujući i tajmer.

Kada smo prvi put kreirali projekat u ST Visual Develop, osim main.c imamo prozor sa misterioznim fajlom stm8_interrupt_vector.cautomatski uključeni u projekat. U ovoj datoteci, funkcija je pridružena svakom prekidu NonHandledInterrupt. Moramo vezati našu funkciju za željeni prekid.

Datasheet ima tabelu vektora prekida, gdje nalazimo one koji su nam potrebni:

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8
13 TIM2 ažuriranje/prelijevanje
14 TIM2 Snimanje/Uporedi

Moramo promijeniti LED na UEV, tako da je potreban prekid #13.

Shodno tome, prvo, u dosijeu stm8_interrupt_vector.c promijenimo naziv funkcije odgovorne za prekid broj 13 (IRQ13) prema zadanim postavkama u naše vlastito:

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

Drugo, moraćemo da kreiramo fajl main.h sadržaj ovako:

#ifndef __MAIN_H
#define __MAIN_H

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

I na kraju, upišite ovu funkciju u svoj 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;
}

Ostaje omogućiti prekide. Ovo se radi pomoću asemblerske komande. rim - moraćete da ga potražite unutra Priručnik za programiranje:

//enable interrupts
_asm("rim");

Još jedno asemblersko uputstvo - sim - Isključuje prekide. Moraju biti onemogućeni dok se nove vrijednosti upisuju u "video memoriju" kako prekid izazvan u nesretnom trenutku ne bi pokvario niz.

Sav kod - na Githubu.

Pročitajte tablice 2: SPI na STM32; PWM, tajmeri i prekidi na STM8

Ako je barem nekome ovaj članak koristan, onda ga nisam uzalud napisao. Bit će mi drago komentarima i primjedbama, trudit ću se odgovoriti na sve.

izvor: www.habr.com

Dodajte komentar