Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

В prvi dio Pokušao sam reći inženjerima hobi elektronike koji su odrasli na Arduino hlačama kako i zašto bi trebali čitati podatkovne tablice i drugu dokumentaciju za mikrokontrolere. Tekst se pokazao velikim, pa sam obećao pokazati praktične primjere u zasebnom članku. Pa on je sebe nazvao mliječnom gljivom...

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

Tekst se opet pokazao ogromnim, pa radi praktičnosti izrađujem sadržaj:

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

Disclaimer: Nisam inženjer, ne pretendiram da imam duboko znanje u elektronici, članak je namijenjen amaterima poput mene. Zapravo, sebe sam prije dvije godine smatrao ciljnom publikom. Da mi je netko tada rekao da podatkovne tablice na nepoznatom čipu nije strašno čitati, ne bih trošio puno vremena tražeći neke dijelove koda na internetu i izmišljajući štake sa škarama i ljepljivom trakom.

Fokus ovog članka je na podatkovnim tablicama, a ne na projektima, tako da kôd možda nije baš uredan i često skučen. Sami projekti su vrlo jednostavni, iako prikladni za prvo upoznavanje s novim čipom.

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

STM32

16 LED s DM634 i SPI

Mali projekt koji koristi Blue Pill (STM32F103C8T6) i DM634 LED drajver. Koristeći podatkovne tablice, otkrit ćemo upravljački program, STM IO portove i konfigurirati SPI.

DM634

Tajvanski čip sa 16 16-bitnih PWM izlaza, može se spajati u lance. Niskobudžetni 12-bitni model poznat je iz domaćeg projekta Lightpack. Svojedobno sam, birajući između DM63x i dobro poznatog TLC5940, odabrao DM iz nekoliko razloga: 1) TLC na Aliexpressu je definitivno fejk, ali ovaj nije; 2) DM ima autonomni PWM s vlastitim generatorom frekvencije; 3) moglo se kupiti jeftino u Moskvi, umjesto da čeka 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 ih je lemiti na adapter.

Budući da je proizvođač tajvanski, podatkovni list čip je napisan na kineskom engleskom, što znači da će biti zabavno. Prvo gledamo pinout (Pin priključak) kako biste razumjeli na koju nogu spojiti što i opis pinova (Opis pribadače). 16 pinova:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Istosmjerni izvori odvoda (otvoreni odvod)

Umivaonik / Izlaz s otvorenim odvodom – odvod; izvor dotočne struje; izlaz je spojen na masu u aktivnom stanju - LED diode su spojene na drajver katodama. Električno, ovo, naravno, nije "otvoreni odvod" (otvoreni odvod), ali u podatkovnim tablicama često se nalazi ova oznaka za pinove u načinu odvoda.

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

Referentni otpornik instaliran je između pina REXT i mase, koji kontrolira unutarnji otpor izlaza, pogledajte grafikon na stranici 9 podatkovne tablice. U DM634, ovaj otpor također se može kontrolirati softverom, postavljajući ukupnu svjetlinu (globalna svjetlina); Neću ulaziti u detalje u ovom članku, ovdje ću samo staviti otpornik od 2.2 - 3 kOhma.

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

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

Da, evo ga, kineski engleski u punom sjaju. Prevođenje ovoga je problematično, možete ga razumjeti ako želite, ali postoji drugi način - pogledajte kako je veza s funkcionalno sličnim TLC5940 opisana u podatkovnoj tablici:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
... Za unos podataka u uređaj potrebna su samo tri pina. Uzlazni rub SCLK signala pomiče podatke sa SIN pina na interni registar. Nakon što su svi podaci učitani, kratki visoki XLAT signal zaključava sekvencijalno prenesene podatke u interne registre. Interni registri su vrata aktivirana razinom XLAT signala. Svi podaci se prvo prenose bitovima najvećeg značaja.

reza – zasun/zasun/zasun.
Uzlazni rub – vodeći rub pulsa
MSB prvi – najznačajniji (krajnji lijevi) bit naprijed.
za podatke o satu – slati podatke sekvencijalno (bit po bit).

Riječ reza često se nalazi u dokumentaciji za čipove i prevodi se na razne načine, pa ću si zbog razumijevanja dopustiti

mali obrazovni programLED upravljački program je u biti registar posmaka. "Shift" (smjena) u nazivu - bitovno kretanje podataka unutar uređaja: svaki novi bit gurnut unutra gura cijeli lanac naprijed ispred sebe. Budući da nitko ne želi promatrati kaotično treptanje LED dioda tijekom pomaka, proces se odvija u međuspremničkim registrima odvojenim od radnih registara prigušivačem (reza) je neka vrsta čekaonice u kojoj se bitovi slažu u željenom nizu. Kada je sve spremno, zatvarač se otvara i bitovi počinju raditi, zamjenjujući prethodnu seriju. Riječ reza u dokumentaciji za mikro krugove gotovo uvijek podrazumijeva takav prigušivač, bez obzira u kojim kombinacijama se koristi.

Dakle, prijenos podataka na DM634 provodi se ovako: postavite DAI ulaz na vrijednost najznačajnijeg bita udaljenog LED-a, povucite DCK gore-dolje; postavite DAI ulaz na vrijednost sljedećeg bita, povucite DCK; i tako dalje dok se svi bitovi ne prenesu (uklj), nakon čega povlačimo LAT. To se može učiniti ručno (bit-bang), ali bolje je koristiti SPI sučelje posebno prilagođeno za to, budući da je predstavljeno na našem STM32 u dva primjerka.

Plava pilula STM32F103

Uvod: STM32 kontroleri mnogo su složeniji od Atmega328 nego što bi se moglo činiti zastrašujućim. Štoviše, zbog uštede energije, gotovo sve periferije su isključene u startu, a frekvencija takta je 8 MHz iz internog izvora. Srećom, programeri STM-a napisali su kod koji dovodi čip do "izračunatih" 72 MHz, a autori svih IDE-ova koje poznajem uključili su ga u proceduru inicijalizacije, tako da ne trebamo taktirati (ali možeš ako stvarno želiš). Ali morat ćete uključiti periferne uređaje.

Dokumentacija: Blue Pill je opremljen popularnim STM32F103C8T6 čipom, postoje dva korisna dokumenta za njega:

U podatkovnoj tablici moglo bi nas zanimati:

  • Pinouts – chip pinouts – u slučaju da se odlučimo sami izraditi ploče;
  • Mapa memorije – mapa memorije za određeni čip. Referentni priručnik ima kartu za cijelu liniju i spominje registre koje naš nema.
  • Tablica s definicijama pinova – popis glavnih i alternativnih funkcija pinova; za “plavu pilulu” možete pronaći prikladnije slike na internetu s popisom pinova i njihovih funkcija. Stoga odmah guglamo Blue Pill pinout i držimo ovu sliku pri ruci:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
NB: na slici s interneta došlo je do greške koja je zabilježena u komentarima, hvala na tome. Slika je zamijenjena, ali ovo je lekcija - bolje je provjeriti informacije ne iz podatkovnih tablica.

Uklanjamo podatkovnu tablicu, otvaramo Referentni priručnik i od sada koristimo samo njega.
Procedura: bavimo se standardnim ulazom/izlazom, konfiguriramo SPI, uključujemo potrebne periferije.

Ulaz izlaz

Na Atmega328, I/O je implementiran krajnje jednostavno, zbog čega obilje STM32 opcija može biti zbunjujuće. Sada nam trebaju samo zaključci, ali i oni imaju četiri opcije:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
otvoreni odvod, push-pull, alternativni push-pull, alternativni otvoreni odvod

"Povuci gurni" (gurni povuci) je uobičajeni izlaz iz Arduina, pin može uzeti vrijednost HIGH ili LOW. Ali s "otvorenim odvodom" postoje poteškoće, iako je zapravo sve jednostavno ovdje:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Izlazna konfiguracija / kada je priključak dodijeljen izlazu: / izlazni međuspremnik omogućen: / – otvoreni način odvoda: “0” u izlaznom registru omogućuje N-MOS, “1” u izlaznom registru ostavlja priključak u Hi-Z načinu ( P-MOS nije aktiviran ) / – push-pull mod: "0" u izlaznom registru aktivira N-MOS, "1" u izlaznom registru aktivira P-MOS.

Sve razlike između otvorenog odvoda (otvoreni odvod) od "push-pull" (gurni povuci) je da prvi pin ne može prihvatiti HIGH stanje: kada upisuje jedan u izlazni registar, on prelazi u način rada visokog otpora (visoke impedancije, Bok-Z). Prilikom upisa nule, pin se ponaša isto u oba načina, i logički i električni.

U normalnom načinu izlaza, pin jednostavno emitira sadržaj izlaznog registra. U "alternativi" njime upravljaju odgovarajući periferni uređaji (vidi 9.1.4):

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Ako je port bit konfiguriran kao alternativni funkcijski pin, pin registar je onemogućen i pin je spojen na periferni pin.

Alternativna funkcionalnost svakog pina opisana je u Definicije pin-a Podatkovna tablica nalazi se na preuzetoj slici. Na pitanje što učiniti ako pin ima nekoliko alternativnih funkcija, odgovor daje fusnota u podatkovnoj tablici:

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

Konačno, pinovi u izlaznom načinu rada također imaju brzinu takta. Ovo je još jedna značajka za uštedu energije; u našem slučaju samo smo je postavili na maksimum i zaboravili.

Dakle: koristimo SPI, što znači da dva pina (s podacima i sa signalom takta) trebaju biti "alternativna push-pull funkcija", a drugi (LAT) treba biti "obična push-pull funkcija". Ali prije nego što ih dodijelimo, pozabavimo se SPI-jem.

SPI

Još jedan mali obrazovni program

SPI ili Serial Peripheral Interface (serijsko periferno sučelje) je jednostavno i vrlo učinkovito sučelje za povezivanje MK s drugim MK i vanjskim svijetom općenito. Načelo njegovog rada već je opisano gore, gdje o kineskom LED drajveru (u referentnom priručniku pogledajte odjeljak 25). SPI može raditi u glavnom ("master") i podređenom ("slave") načinu rada. SPI ima četiri osnovna kanala od kojih se ne mogu svi koristiti:

  • MOSI, glavni izlaz / podređeni ulaz: ovaj pin prenosi podatke u glavnom načinu rada, a prima podatke u podređenom načinu rada;
  • MISO, glavni ulaz / podređeni izlaz: naprotiv, prima u glavnom, a odašilje u podređenom;
  • SCK, Serial Clock: postavlja frekvenciju prijenosa podataka u glavnom ili prima signal takta u podređenom. U biti udarački ritmovi;
  • SS, Slave Select: uz pomoć ovog kanala rob zna da se od njega nešto traži. Na STM32 naziva se NSS, gdje je N = negativno, tj. kontroler postaje podređeni ako postoji uzemljenje u ovom kanalu. Dobro se kombinira s Open Drain Output modom, ali to je druga priča.

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

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
U ovom načinu rada aplikacija koristi SPI u načinu rada samo za prijenos ili samo za prijem. / Način rada samo za prijenos sličan je dupleksnom načinu rada: podaci se prenose na pinu za prijenos (MOSI u glavnom načinu rada ili MISO u podređenom načinu rada), a prijemni pin (MISO ili MOSI respektivno) može se koristiti kao obični I/O pin . U ovom slučaju, aplikacija samo treba zanemariti Rx međuspremnik (ako je pročitan, tamo neće biti prenesenih podataka).

Super, MISO pin je slobodan, spojimo LAT signal na njega. Pogledajmo Slave Select, koji se na STM32 može programski kontrolirati, što je izuzetno zgodno. Čitamo istoimeni paragraf u odjeljku 25.3.1 SPI Opći opis:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Softverska kontrola NSS (SSM = 1) / Informacije o odabiru podređenog su sadržane u SSI bitu registra SPI_CR1. Vanjski NSS pin ostaje slobodan za potrebe drugih aplikacija.

Vrijeme je za upis u matične knjige. Odlučio sam koristiti SPI2, potražiti njegovu osnovnu adresu u podatkovnoj tablici - u odjeljku 3.3 Mapa memorije:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

Pa, počnimo:

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

Otvorite odjeljak 25.3.3 s naslovom koji sam po sebi objašnjava "Konfiguriranje SPI-ja u glavnom načinu":

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

1. Postavite frekvenciju serijskog takta s bitovima BR[2:0] u registru SPI_CR1.

Registri su prikupljeni u istoimenom dijelu referentnog priručnika. Promjena adrese (Pomak adrese) za CR1 – 0x00, prema zadanim postavkama svi bitovi se brišu (Poništi vrijednost 0x0000):

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

BR bitovi postavljaju razdjelnik takta kontrolera, određujući tako frekvenciju na kojoj će SPI raditi. Naša frekvencija STM32 bit će 72 MHz, LED drajver, prema podatkovnoj tablici, radi na frekvenciji do 25 MHz, tako da trebamo podijeliti s č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 za definiranje odnosa između prijenosa podataka i vremena serijskog sata (pogledajte dijagram na stranici 240)

Budući da ovdje čitamo podatkovnu tablicu, a ne gledamo sheme, pogledajmo pobliže tekstualni opis CPOL i CPHA bitova na stranici 704 (Opći opis SPI):

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Faza sata i polaritet
Korištenjem CPOL i CPHA bitova SPI_CR1 registra, možete programski odabrati četiri vremenska odnosa. CPOL (polaritet sata) bit kontrolira stanje signala sata kada se podaci ne prenose. Ovaj bit kontrolira glavni i podređeni način rada. Ako je CPOL resetiran, SCK pin je nizak u načinu mirovanja. Ako je CPOL bit postavljen, SCK pin je visok tijekom načina mirovanja.
Kada je postavljen bit CPHA (faza takta), strob zamke visokog bita je drugi rub SCK signala (opadajući ako je CPOL čist, raste ako je CPOL postavljen). Podaci se bilježe drugom promjenom signala sata. Ako je CPHA bit prazan, strob zamke visokog bita je rastući rub SCK signala (padajući rub ako je postavljen CPOL, rastući rub ako je CPOL izbrisan). Podaci se bilježe pri prvoj promjeni signala sata.

Upijajući ovo znanje, dolazimo do zaključka da oba bita moraju ostati nule, jer Želimo da SCK signal ostane nizak kada se ne koristi i da se podaci prenose na uzlaznom rubu impulsa (vidi sl. Rising Edge u podatkovnoj tablici DM634).

Usput, ovdje smo prvi put naišli na značajku vokabulara u ST podatkovnim tablicama: u njima je napisana fraza "resetiraj bit na nulu" malo resetiratiI ne malo raščistiti, poput, na primjer, Atmege.

3. Postavite DFF bit da odredite je li blok podataka 8-bitni ili 16-bitni format

Posebno sam uzeo 16-bitni DM634 kako se ne bih mučio s prijenosom 12-bitnih PWM podataka, poput DM633. Ima smisla postaviti DFF na jedan:

#define DFF         0x0800

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

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

LSBFIRST, kao što mu ime sugerira, konfigurira prijenos s bitom najmanje važnosti prvi. Ali DM634 želi primati podatke počevši od najvažnijeg bita. Stoga ga ostavljamo resetiranim.

5. U hardverskom načinu rada, ako je potreban unos s NSS pina, primijenite visoki signal na NSS pin tijekom cijele sekvence prijenosa bajtova. U NSS softverskom načinu, postavite SSM i SSI bitove u SPI_CR1 registar. Ako se NSS pin koristi kao izlaz, potrebno je postaviti samo bit SSOE.

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. Bitovi MSTR i SPE moraju biti postavljeni (ostaju postavljeni samo ako je NSS signal visok)

Zapravo, ovim bitovima određujemo naš SPI kao glavni i uključujemo ga:

#define MSTR        0x0004
#define SPE         0x0040

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

SPI je konfiguriran, idemo odmah napisati funkcije koje šalju bajtove u upravljački program. Nastavite čitati 25.3.3 “Konfiguriranje SPI u glavnom načinu rada”:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Nalog za prijenos podataka
Prijenos počinje kada se bajt upiše u Tx međuspremnik.
Bajt podataka se učitava u registar posmaka na paralelno načinu rada (s interne sabirnice) tijekom prijenosa prvog bita, nakon čega se prenosi na sekvencijalno MOSI pin mod, prvi ili zadnji bit naprijed ovisno o postavci bita LSBFIRST u registru CPI_CR1. Oznaka TXE postavlja se nakon prijenosa podataka iz Tx međuspremnika u registar posmaka, a također generira prekid ako je postavljen bit TXEIE u registru CPI_CR1.

Istaknuo sam nekoliko riječi u prijevodu kako bih skrenuo pozornost na jednu značajku implementacije SPI u STM kontrolere. Na Atmegi TXE zastavica (Tx Prazan, Tx je prazan i spreman za primanje podataka) postavlja se tek nakon što je cijeli bajt poslan van. I ovdje je ova zastavica postavljena nakon što je bajt umetnut u interni registar posmaka. Budući da se tamo gura sa svim bitovima u isto vrijeme (paralelno), a zatim se podaci prenose sekvencijalno, TXE se postavlja prije 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 Sve podataka, tj. Sama TXE zastavica nam neće biti dovoljna.

To znači da nam treba još jedna zastava. Pogledajmo 25.3.7 - “Status Flags”:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
<…>
Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
ZAUZETO zastavica
Oznaku BSY postavlja i briše hardver (pisanje na nju nema učinka). Oznaka BSY označava stanje SPI komunikacijskog sloja.
Ponovno se postavlja:
kada je prijenos dovršen (osim u glavnom načinu rada ako je prijenos kontinuiran)
kada je SPI onemogućen
kada se pojavi pogreška glavnog načina (MODF=1)
Ako prijenos nije kontinuiran, BSY oznaka se briše između svakog prijenosa podataka

Dobro, ovo će mi dobro doći. Otkrijmo gdje se nalazi Tx međuspremnik. Da biste to učinili, pročitajte “Registar SPI podataka”:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Bitovi 15:0 DR[15:0] registar podataka
Podaci primljeni ili podaci koji se prenose.
Registar podataka podijeljen je u dva međuspremnika - jedan za upis (međuspremnik za prijenos) i jedan za čitanje (spremnik za prijem). Upisivanje u podatkovni registar upisuje u Tx međuspremnik, a čitanje iz podatkovnog registra vratit će vrijednost sadržanu u Rx međuspremniku.

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

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

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, budući da trebamo prenijeti 16 puta dva bajta, prema broju izlaza LED drajvera, nešto 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 povući LAT pin, pa ćemo se vratiti na I/O.

Dodjeljivanje igala

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

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Svaki od I/O priključaka opće namjene (GPIO) ima dva 32-bitna konfiguracijska registra (GPIOx_CRL i GPIOx_CRH), dva 32-bitna podatkovna registra (GPIOx_IDR i GPIOx_ODR), 32-bitni set/reset registar (GPIOx_BSRR), 16-bitni reset registar (GPIOx_BRR) i 32-bitni registar za resetiranje registar za blokiranje bitova (GPIOx_LCKR).

Prva dva registra su neobična, a također i prilično nezgodna, jer je 16 port pinova razbacano po njima u formatu "četiri bita po bratu". Oni. pinovi od nula do sedam su u CRL, a ostali su u CRH. U isto vrijeme, preostali registri uspješno sadrže bitove svih pinova porta - često ostaju napola "rezervirani".

Radi jednostavnosti, krenimo od kraja popisa.

Ne treba nam registar blokada.

Registri za postavljanje i resetiranje prilično su smiješni jer se djelomično dupliraju: sve možete pisati samo u BSRR, gdje će viših 16 bitova resetirati pin na nulu, a nižih će biti postavljeno na 1, ili također možete koristite BRR, čijih nižih 16 bitova samo resetiraju pin. Sviđa mi se druga opcija. Ovi registri su važni jer daju atomski pristup pinovima:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Atomsko postavljanje ili resetiranje
Nema potrebe za onemogućavanjem prekida prilikom programiranja GPIOx_ODR na razini bita: jedan ili više bitova može se promijeniti jednom atomskom operacijom pisanja APB2. To se postiže upisivanjem "1" u registar za postavljanje/poništavanje (GPIOx_BSRR ili, samo za ponovno postavljanje, GPIOx_BRR) bita koji treba promijeniti. Ostali bitovi ostat će nepromijenjeni.

Registar podataka ima sasvim jasna imena - IDR = Ulazni Registar smjera, ulazni registar; ODR = Izlaz Registar smjera, izlazni registar. Nećemo ih trebati u trenutnom projektu.

I na kraju, kontrolni registri. Budući da nas zanimaju drugi SPI pinovi, naime PB13, PB14 i PB15, odmah pogledamo CRH:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

I vidimo da ćemo morati napisati nešto u bitovima od 20 do 31.

Gore smo već shvatili što želimo od pinova, pa ću ovdje bez snimke zaslona, ​​samo ću reći da MODE određuje smjer (unos ako su oba bita postavljena na 0) i brzinu pina (potrebno nam je 50MHz, tj. oba pina na "1"), a CNF postavlja način rada: regularni "push-pull" - 00, "alternativni" - 10. Prema zadanim postavkama, kao što vidimo gore, svi pinovi imaju treći bit odozdo (CNF0), postavlja ih na način rada plutajući unos.

Budući da planiram učiniti nešto drugo s ovim čipom, zbog jednostavnosti definirao sam sve moguće vrijednosti MODE i CNF za donji i gornji kontrolni registar.

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 nalaze se na portu B (osnovna 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, u skladu s tim, možete napisati definicije za LAT, koje će se trzati registrima BRR i 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_nisko samo po inerciji, uvijek je tako bilo, neka ostane)

Sada je sve super, ali ne ide. Budući da je ovo STM32, oni štede struju, što znači da morate omogućiti taktiranje potrebnih perifernih uređaja.

Uključite mjerenje vremena

Sat, također poznat kao sat, odgovoran je za mjerenje vremena. I već smo mogli primijetiti kraticu RCC. Tražimo ga u dokumentaciji: ovo je Reset and Clock Control.

Kao što je gore rečeno, srećom, najteži dio teme clockinga za nas su odradili ljudi iz STM-a, na čemu im veliko hvala (još jednom ću dati link na Di Haltova web stranica, da bude jasno koliko je zbunjujuće). Trebamo samo registre odgovorne za omogućavanje perifernog takta (Peripheral Clock Enable Registers). Prvo, pronađimo osnovnu adresu RCC-a, ona je na samom početku "Mape memorije":

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

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

Zatim ili kliknite na poveznicu na kojoj pokušavate pronaći nešto u ploči, ili, mnogo bolje, prođite kroz opise registara za omogućavanje iz odjeljaka o omogućiti registre. Gdje ćemo pronaći RCC_APB1ENR i RCC_APB2ENR:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

I oni, sukladno tome, sadrže bitove 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čni kod možete pronaći ovdje.

Ako imate priliku i želju za testiranjem, onda spojite DM634 ovako: DAI na PB15, DCK na PB13, LAT na PB14. Napajamo vozač iz 5 volti, ne zaboravite spojiti uzemljenje.

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

STM8 PWM

PWM na STM8

Kad sam tek planirao ovaj članak, odlučio sam, kao primjer, pokušati svladati neke funkcije nepoznatog čipa koristeći samo podatkovnu tablicu, kako ne bih završio s postolarom bez čizama. STM8 je bio idealan za ovu ulogu: prvo, imao sam nekoliko kineskih ploča sa STM8S103, a drugo, nije baš popularan, pa stoga iskušenje čitanja i pronalaska rješenja na Internetu počiva na nedostatku tih istih rješenja.

Čip također ima podatkovni list и referentni priručnik RM0016, u prvom se nalaze pinout i registracijske adrese, u drugom - sve ostalo. STM8 je programiran u C-u u užasnom IDE-u ST Visual Develop.

Taktiranje i I/O

Prema zadanim postavkama, STM8 radi na frekvenciji od 2 MHz, to se mora odmah ispraviti.

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
HSI (High Speed ​​​​Internal) sat
HSI taktni signal se izvodi iz unutarnjeg RC oscilatora od 16 MHz s programabilnim razdjelnikom (1 do 8). Postavlja se u registru djelitelja takta (CLK_CKDIVR).
Napomena: na početku je odabran HSI RC oscilator s razdjelnikom 8 kao vodeći izvor taktnog signala.

Pronalazimo adresu registra u podatkovnoj tablici, opis u refmanu i vidimo da registar treba obrisati:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Budući da ćemo pokrenuti PWM i spojiti LED diode, pogledajmo pinout:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

Čip je malen, mnoge su funkcije obješene na iste pinove. Ono što je u uglatim zagradama je "alternativna funkcionalnost", prebacuje se "opcijskim bajtovima" (opcijski bajtovi) – nešto poput Atmega osigurača. Njihove vrijednosti možete promijeniti programski, ali to nije nužno, jer Nova funkcionalnost se aktivira tek nakon ponovnog pokretanja sustava. Lakše je koristiti ST Visual Programmer (preuzet s Visual Developom), koji može promijeniti ove bajtove. Pinout pokazuje da su pinovi CH1 i CH2 prvog timera skriveni u uglatim zagradama; potrebno je postaviti AFR1 i AFR0 bitove u STVP, a drugi će također prenijeti CH1 izlaz drugog timera sa PD4 na PC5.

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

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

  • poznato iz Atmega DDR registra smjera podataka (Registar smjera podataka): 1 = izlaz;
  • prvi upravljački registar CR1, kada izlazi, postavlja push-pull mod (1) ili otvoreni odvod (0); budući da LED diode spajam na čip s katodama, ovdje ostavljam nule;
  • drugi kontrolni registar CR2, kada je na izlazu, postavlja brzinu takta: 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 podešavanje

Prvo, definirajmo pojmove:

  • Učestalost PWM-a – učestalost otkucaja mjerača vremena;
  • Automatsko ponovno učitavanje, AR – autoloadable vrijednost do koje će tajmer brojati (period impulsa);
  • Događaj ažuriranja, UEV – događaj koji se dogodi kada mjerač vremena izbroji do AR;
  • PWM radni ciklus – PWM radni ciklus, koji se često naziva "faktor rada";
  • Hvatanje/usporedba vrijednosti – vrijednost za snimanje/usporedbu, do koje je mjerač brojao učinit će nešto (u slučaju PWM-a, invertira izlazni signal);
  • Vrijednost predučitavanja – unaprijed učitana vrijednost. Usporedite vrijednost ne može se mijenjati dok mjerač vremena otkucava, inače će se PWM ciklus prekinuti. Stoga se nove prenesene vrijednosti smještaju u međuspremnik i izvlače kada mjerač vremena dosegne kraj svog odbrojavanja i resetira se;
  • Poravnano po rubovima и Načini poravnanja u sredini – poravnanje duž obruba i u središtu, isto kao kod Atmela Brzi PWM и Fazno ispravan PWM.
  • OCiREF, referentni signal usporedbe izlaza – referentni izlazni signal, zapravo ono što se pojavljuje na odgovarajućem pinu u PWM modu.

Kao što je već jasno iz pinout-a, dva tajmera imaju PWM mogućnosti - prvi i drugi. Oba su 16-bitna, prvi ima puno dodatnih značajki (konkretno, može brojati i gore i dolje). Oba nam trebaju da rade jednako, pa sam odlučio krenuti s očito lošijim drugim, da slučajno ne koristim nešto čega nema. Neki problem je što se opis PWM funkcionalnosti svih mjerača vremena u referentnom priručniku nalazi u poglavlju o prvom mjeraču vremena (17.5.7 PWM način rada), tako da morate stalno skakati naprijed-natrag kroz dokument.

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

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
PWM usklađen s granicama
Konfiguracija računa odozdo prema gore
Brojenje odozdo prema gore aktivno je ako je DIR bit u registru TIM_CR1 izbrisan
Primjer
Primjer koristi prvi PWM mod. PWM referentni signal OCiREF održava se visoko sve dok je TIM1_CNT < TIM1_CCRi. Inače je potrebna niska razina. Ako je usporedna vrijednost u registru TIM1_CCRi veća od vrijednosti automatskog učitavanja (registar TIM1_ARR), OCiREF signal se zadržava na 1. Ako je usporedna vrijednost 0, OCiREF se održava na nuli....

STM8 mjerač vremena tijekom događaj ažuriranja prvo provjerava usporediti vrijednost, i tek tada proizvodi referentni signal. Atmegin timer prvo zajebe, a zatim uspoređuje, što rezultira compare value == 0 izlaz je igla, s kojom se mora nekako pozabaviti (na primjer, programskim invertiranjem logike).

Dakle, ono što želimo učiniti: 8-bitni PWM (AR == 255), računajući odozdo prema gore, poravnanje uz rub. Budući da su žarulje spojene na čip pomoću katoda, PWM bi trebao izlaziti 0 (LED uključen) dok usporediti vrijednost i 1 poslije.

O nekima smo već čitali PWM način rada, tako da traženi registar drugog mjerača vremena pronalazimo pretraživanjem u referentnom priručniku ove fraze (18.6.8 - TIMx_CCMR1):

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
110: Prvi PWM mod – kada se broji odozdo prema gore, prvi kanal je aktivan dok je TIMx_CNT < TIMx_CCR1. Inače, prvi kanal je neaktivan. [dalje u dokumentu postoji pogrešan copy-paste iz mjerača vremena 1] 111: Drugi PWM mod – kada se broji odozdo prema gore, prvi kanal je neaktivan dok je TIMx_CNT < TIMx_CCR1. Inače, prvi kanal je aktivan.

Budući da su LED diode povezane s MK katodama, drugi način nam odgovara (i prvi, ali to još ne znamo).

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Bit 3 OC1PE: Omogući predopterećenje pina 1
0: Predučitani registar na TIMx_CCR1 je onemogućen. TIMx_CCR1 možete pisati bilo kada. Nova vrijednost djeluje odmah.
1: Omogućen je registar predučitavanja na TIMx_CCR1. Operacije čitanja/pisanja pristupaju registru predučitavanja. Prethodno učitana vrijednost TIMx_CCR1 učitava se u registar u sjeni tijekom svakog događaja ažuriranja.
*Napomena: Da bi PWM način rada ispravno radio, predučitani registri moraju biti omogućeni. Ovo nije potrebno u načinu rada s jednim signalom (OPM bit je postavljen u registru TIMx_CR1).

U redu, uključimo sve što nam je potrebno za tri kanala drugog timera:

#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, sve je jednostavno:

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

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Drugi mjerač vremena može brojati samo odozdo prema gore, poravnanje uz rub, ne treba ništa mijenjati. Postavimo djelitelj frekvencije, na primjer, na 256. Za drugi mjerač vremena, djelitelj je postavljen u registru TIM2_PSCR i stepen je dvojke:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Ostaje samo uključiti zaključke i sam drugi mjerač vremena. Prvi problem rješavaju registri Snimi/Usporedi Omogućiti: na njima su asimetrično raštrkana dva, tri kanala. Ovdje također možemo naučiti da je moguće promijeniti polaritet signala, tj. u načelu je bilo moguće koristiti PWM način 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 na kraju, pokrećemo mjerač vremena u registru TIMx_CR1:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Napišimo jednostavan analog AnalogWrite(), koji će stvarne vrijednosti prenijeti na mjerač vremena za usporedbu. Registri su nazvani predvidljivo Hvatanje/usporedba registara, postoje dva od njih za svaki kanal: 8 bitova nižeg reda u TIM2_CCRxL i onih visokog reda u TIM2_CCRxH. Budući da smo napravili 8-bitni PWM, dovoljno je napisati samo najmanje bitne 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 čitatelj primijetit će da imamo malo neispravan PWM, nesposoban proizvesti 100% punjenje (pri maksimalnoj vrijednosti od 255, signal se invertira za jedan ciklus tajmera). Za LED diode to nije važno, a pažljivi čitatelj već može pogoditi kako to popraviti.

PWM na drugom timeru radi, prijeđimo na prvi.

Prvi timer ima potpuno iste bitove u istim registrima (samo što su oni bitovi koji su ostali "rezervirani" u drugom timeru aktivno korišteni u prvom za svakakve napredne stvari). Stoga je dovoljno pronaći adrese istih registara u podatkovnoj tablici i kopirati kod. Pa, promijenite vrijednost razdjelnika frekvencije, jer... prvi mjerač vremena ne želi primiti potenciju dvojke, već točnu 16-bitnu vrijednost u dva registra Prescaler High и Nizak. Radimo sve i... prvi mjerač vremena ne radi. Što je bilo?

Problem se može riješiti jedino pregledom cijelog odjeljka o upravljačkim registrima mjerača vremena 1, gdje tražimo onaj koji drugi mjerač vremena nema. Biti će 17.7.30 Registar prekida (TIM1_BKR), gdje je ovaj bit:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Omogući glavni izlaz

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

To je sada sve sigurno, šifra tamo.

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

STM8 Multiplex

Multipleksiranje na STM8

Treći mini-projekt je spojiti osam RGB LED dioda na drugi mjerač vremena u PWM modu i omogućiti im da prikazuju različite boje. Temelji se na konceptu LED multipleksiranja, a to je da ako palite i gasite LED diode vrlo, vrlo brzo, činit će nam se da su stalno upaljene (postojanost vida, inercija vizualne percepcije). jednom jesam ovako nešto na Arduinu.

Algoritam rada izgleda ovako:

  • spojio anodu prve RGB LED diode;
  • upalio, šaljući potrebne signale katodama;
  • čekao do kraja PWM ciklusa;
  • spojio anodu drugog RGB LED-a;
  • zapalio...

Pa itd. Naravno, za lijep rad potrebno je da anoda bude spojena i da se LED dioda "upali" u isto vrijeme. Pa, ili skoro. U svakom slučaju, trebamo napisati kod koji će ispisivati ​​vrijednosti u tri kanala drugog timera, mijenjati ih kada se dostigne UEV, a istovremeno mijenjati trenutno aktivni RGB LED.

Budući da je prebacivanje LED dioda automatsko, moramo stvoriti "video memoriju" iz koje će rukovatelj 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, čudno, CD74HC238 demultipleksor. Demultipleksor - čip koji implementira operator u hardver <<. Preko tri ulazna pina (bitovi 0, 1 i 2) dovodimo mu trobitni broj X, a on kao odgovor aktivira izlazni broj (1<<X). Preostali ulazi čipa koriste se za skaliranje cijelog dizajna. Ovaj čip nam je potreban ne samo da smanjimo broj zauzetih pinova mikrokontrolera, već i za sigurnost - kako ne bismo slučajno uključili više LED dioda nego što je moguće i ne spalimo MK. Čip košta peni i uvijek ga treba držati u kućnom ormariću s lijekovima.

Naš CD74HC238 bit će odgovoran za dovod napona na anodu željene LED diode. U punopravnom multipleksu, on bi opskrbljivao napon stupcu preko P-MOSFET-a, ali u ovoj demonstraciji to je moguće izravno, jer troši 20 mA, prema apsolutne maksimalne ocjene u podatkovnoj tablici. Iz Podatkovna tablica CD74HC238 trebamo pinouts i ovu varalicu:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
H = visoka razina napona, L = razina niskog napona, X – nije me briga

Spojimo E2 i E1 na masu, E3, A0, A1 i A3 na pinove PD5, PC3, PC4 i PC5 STM8. Budući da gornja tablica sadrži i niske i visoke razine, mi konfiguriramo ove pinove kao push-pull pinove.

PWM

PWM na drugom timeru je konfiguriran na isti način kao u prethodnoj priči, s dvije razlike:

Prvo, moramo omogućiti uključenje prekida Ažuriraj događaj (UEV) koji će pozvati funkciju koja uključuje i isključuje aktivni LED. To se postiže promjenom nastavka Ažuriraj Omogući prekid u registar znakovitog imena

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
Registar omogućivanja prekida

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Druga razlika je vezana uz fenomen multipleksiranja, kao npr ghosting – parazitski sjaj dioda. U našem slučaju, može se pojaviti zbog činjenice da mjerač vremena, nakon što je izazvao prekid na UEV-u, nastavlja otkucavati, a rukovatelj prekidima nema vremena za prebacivanje LED prije nego što mjerač vremena počne pisati nešto na pinove. Da biste se borili protiv toga, morat ćete preokrenuti logiku (0 = maksimalna svjetlina, 255 = ništa ne svijetli) i izbjegavati ekstremne vrijednosti radnog ciklusa. Oni. osigurajte da se nakon UEV LED diode potpuno ugase za jedan PWM ciklus.

Promjena polariteta:

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

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

Prekidi

Bit prekida je da pod određenim okolnostima čip prestane izvršavati glavni program i pozove neku vanjsku funkciju. Prekidi se javljaju zbog vanjskih ili unutarnjih utjecaja, uključujući mjerač vremena.

Kada smo prvi put izradili projekt u ST Visual Developu, pored toga main.c dobili smo prozor s misterioznom datotekom stm8_interrupt_vector.c, automatski uključen u projekt. U ovoj datoteci, funkcija je dodijeljena svakom prekidu NonHandledInterrupt. Moramo vezati našu funkciju na željeni prekid.

Podatkovna tablica ima tablicu vektora prekida, gdje nalazimo one koji su nam potrebni:

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8
13 TIM2 ažuriranje/preljev
14 TIM2 snimanje/usporedba

Moramo promijeniti LED na UEV, pa nam treba prekid #13.

Prema tome, prvo, u datoteku stm8_interrupt_vector.c promijenite zadani naziv funkcije odgovorne za prekid br. 13 (IRQ13) u svoj:

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

Drugo, morat ćemo stvoriti datoteku main.h sa sljedećim sadržajem:

#ifndef __MAIN_H
#define __MAIN_H

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

I na kraju, zapiš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 samo omogućiti prekide. To se radi pomoću naredbe asemblera rim - morat ćete ga potražiti u Priručnik za programiranje:

//enable interrupts
_asm("rim");

Druga asemblerska naredba je sim – isključuje prekide. Moraju se isključiti dok se nove vrijednosti zapisuju u "video memoriju", tako da prekid uzrokovan u pogrešnom trenutku ne pokvari niz.

Svi kodovi - na GitHubu.

Pročitajte podatkovne tablice 2: SPI na STM32; PWM, mjerači vremena i prekidi na STM8

Ako barem netko smatra ovaj članak korisnim, onda ga nisam uzalud napisao. Bit će mi drago primiti komentare i primjedbe, pokušat ću odgovoriti na sve.

Izvor: www.habr.com

Dodajte komentar