Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

В prvá časť Snažil som sa povedať hobby inžinierom elektroniky, ktorí vyrástli z nohavíc Arduino, ako a prečo by mali čítať dátové listy a inú dokumentáciu pre mikrokontroléry. Text sa ukázal byť veľký, preto som sľúbil, že praktické príklady ukážem v samostatnom článku. No nazval sa mliečnou hubou...

Dnes vám ukážem, ako pomocou datasheetov vyriešiť celkom jednoduché, no pre mnohé projekty nevyhnutné úlohy na ovládačoch STM32 (Blue Pill) a STM8. Všetky demo projekty sú venované mojim obľúbeným LED diódam, budeme ich svietiť vo veľkom množstve, na čo budeme musieť použiť všemožné zaujímavé periférie.

Text sa opäť ukázal byť obrovský, takže pre pohodlie vytváram obsah:

STM32 Blue Pill: 16 LED s ovládačom DM634
STM8: Nastavenie šiestich pinov PWM
STM8: 8 RGB LED na troch kolíkoch, prerušenia

Upozornenie: Nie som inžinier, nepredstieram hlboké znalosti v elektronike, článok je určený pre amatérov ako som ja. V skutočnosti som sa pred dvoma rokmi považoval za cieľové publikum. Keby mi vtedy niekto povedal, že datasheety na neznámom čipe nie sú strašidelné na čítanie, nestrávil by som veľa času hľadaním nejakých kúskov kódu na internete a vymýšľaním barlí s nožnicami a lepiacou páskou.

Tento článok sa zameriava na dátové listy, nie na projekty, takže kód nemusí byť veľmi prehľadný a často stiesnený. Samotné projekty sú veľmi jednoduché, aj keď vhodné na prvé zoznámenie sa s novým čipom.

Dúfam, že môj článok niekomu pomôže v podobnej fáze ponorenia sa do hobby.

32 STM

16 LED diód s DM634 a SPI

Malý projekt využívajúci Blue Pill (STM32F103C8T6) a DM634 LED driver. Pomocou datasheetov zistíme ovládač, STM IO porty a nakonfigurujeme SPI.

DM634

Taiwanský čip so 16 16-bitovými PWM výstupmi, je možné zapájať do reťazcov. Low-endový 12-bitový model je známy z domáceho projektu Lightpack. Kedysi, keď som sa rozhodoval medzi DM63x a známym TLC5940, som si vybral DM z niekoľkých dôvodov: 1) TLC na Aliexpress je určite falošné, ale toto nie je; 2) DM má autonómne PWM s vlastným frekvenčným generátorom; 3) dalo by sa kúpiť lacno v Moskve, namiesto čakania na balík od Aliho. A, samozrejme, bolo zaujímavé naučiť sa ovládať čip sami, a nie používať hotovú knižnicu. Čipy sú teraz prezentované hlavne v balení SSOP24, dajú sa ľahko spájkovať s adaptérom.

Keďže výrobcom je Taiwan, dátový hárok čip je napísaný v čínskej angličtine, čo znamená, že to bude zábava. Najprv sa pozrieme na pinout (Pinové pripojenie), aby ste pochopili, na ktorú nohu sa má čo pripojiť, a popis kolíkov (Popis špendlíka). 16 kolíkov:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Zdroje drezu DC (otvorený odtok)

drez / Výstup s otvoreným odtokom - vypustiť; zdroj privádzaného prúdu; výstup, v aktívnom stave, spojený so zemou - LED sú s budičom spojené katódami. Elektricky to, samozrejme, nie je „otvorený odtok“ (otvorený odtok), ale v technických listoch sa toto označenie pre kolíky v režime vypúšťania často nachádza.

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Externé odpory medzi REXT a GND na nastavenie hodnoty výstupného prúdu

Medzi kolíkom REXT a zemou je nainštalovaný referenčný odpor, ktorý riadi vnútorný odpor výstupov, pozri graf na strane 9 technického listu. V DM634 je možné tento odpor ovládať aj softvérovo nastavením celkového jasu (globálny jas); V tomto článku nebudem zachádzať do podrobností, len sem dám odpor 2.2 - 3 kOhm.

Aby sme pochopili, ako ovládať čip, pozrime sa na popis rozhrania zariadenia:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

Áno, tu je, čínska angličtina v celej svojej kráse. Preložiť to je problematické, môžete to pochopiť, ak chcete, ale existuje aj iný spôsob - pozrite sa, ako je pripojenie k funkčne podobnému TLC5940 popísané v údajovom liste:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
... Na zadávanie údajov do zariadenia sú potrebné iba tri piny. Nábežná hrana signálu SCLK posúva dáta z pinu SIN do interného registra. Po načítaní všetkých dát krátky vysoký XLAT signál zachytí postupne prenášané dáta do interných registrov. Interné registre sú brány spúšťané úrovňou signálu XLAT. Všetky dáta sa prenášajú najvýznamnejší bit ako prvý.

závora – západka/závora/zámok.
Stúpajúca hrana – predná hrana pulzu
Najprv MSB – najvýznamnejší (úplne vľavo) bit dopredu.
na hodiny údajov – prenášať dáta postupne (bit po bite).

Slovo závora sa často nachádza v dokumentácii k čipom a je preložená rôznymi spôsobmi, takže pre pochopenie si dovolím

malý vzdelávací programLED driver je v podstate posuvný register. "Shift" (posun) v názve - bitový pohyb dát vo vnútri zariadenia: každý nový bit vsunutý dovnútra posúva celý reťazec dopredu pred sebou. Keďže nikto nechce pozorovať chaotické blikanie LED počas posunu, proces prebieha vo vyrovnávacích registroch oddelených od pracovných registrov tlmičom (závora) je druh čakárne, kde sú bity usporiadané v požadovanom poradí. Keď je všetko pripravené, uzáver sa otvorí a bity sa pustia do práce a nahradia predchádzajúcu dávku. Slovo závora v dokumentácii pre mikroobvody takmer vždy znamená takýto tlmič, bez ohľadu na to, v akých kombináciách sa používa.

Takže prenos dát do DM634 sa vykonáva takto: nastavte vstup DAI na hodnotu najvýznamnejšieho bitu vzdialenej LED, ťahajte DCK nahor a nadol; nastavte vstup DAI na hodnotu nasledujúceho bitu, vytiahnite DCK; a tak ďalej, kým sa neprenesú všetky bity (prihlásený), po ktorom potiahneme LAT. Dá sa to urobiť ručne (bit-bang), ale je lepšie použiť rozhranie SPI špeciálne prispôsobené na to, pretože je prezentované na našom STM32 v dvoch kópiách.

Modrá pilulka STM32F103

Úvod: Ovládače STM32 sú oveľa zložitejšie ako Atmega328, než by sa mohlo zdať desivé. Navyše z dôvodu úspory energie sú takmer všetky periférie pri štarte vypnuté a taktovacia frekvencia je 8 MHz z interného zdroja. Našťastie programátori STM napísali kód, ktorý privedie čip až na „vypočítaných“ 72 MHz a autori všetkých IDE, ktoré poznám, ho zahrnuli do inicializačnej procedúry, takže nemusíme taktovať (ale môžeš, ak naozaj chceš). Periférne zariadenia si ale budete musieť zapnúť.

Dokumentácia: Blue Pill je vybavená populárnym čipom STM32F103C8T6, existujú k nemu dva užitočné dokumenty:

V datasheete nás môže zaujímať:

  • Pinouts – čipové pinouty – v prípade, že sa rozhodneme vyrábať dosky sami;
  • Memory Map – mapa pamäte pre konkrétny čip. Referenčná príručka obsahuje mapu celej linky a spomínajú sa v nej registre, ktoré ten náš nemá.
  • Tabuľka definícií pinov – zoznam hlavných a alternatívnych funkcií pinov; pre „modrú pilulku“ nájdete na internete pohodlnejšie obrázky so zoznamom pinov a ich funkcií. Preto si ihneď vygooglime pinout Blue Pill a máme tento obrázok po ruke:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Pozn.: na obrázku z internetu sa vyskytla chyba, ktorá bola uvedená v komentároch, ďakujeme za to. Obrázok bol nahradený, ale toto je lekcia - je lepšie skontrolovať informácie, ktoré nie sú z údajových listov.

Odstránime údajový list, otvoríme referenčnú príručku a odteraz používame iba ju.
Postup: poradíme so štandardným vstupom/výstupom, nakonfigurujeme SPI, zapneme potrebné periférie.

Vstup výstup

Na Atmega328 je I/O implementovaný extrémne jednoducho, a preto môže byť množstvo možností STM32 mätúce. Teraz potrebujeme len závery, ale aj tieto majú štyri možnosti:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
otvorený odtok, push-pull, alternatívny push-pull, alternatívny otvorený odtok

"Ťahať tlačiť" (tlačiť ťahať) je zvyčajný výstup z Arduina, kolík môže nadobudnúť hodnotu HIGH alebo LOW. Ale s „otvoreným odtokom“ existujú ťažkosti, aj keď v skutočnosti je tu všetko jednoduché:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Konfigurácia výstupu / keď je port priradený k výstupu: / výstupná vyrovnávacia pamäť povolená: / – režim otvoreného odberu: „0“ vo výstupnom registri povolí N-MOS, „1“ vo výstupnom registri ponechá port v režime Hi-Z ( P-MOS nie je aktivovaný ) / – režim push-pull: „0“ vo výstupnom registri aktivuje N-MOS, „1“ vo výstupnom registri aktivuje P-MOS.

Celý rozdiel medzi otvoreným odtokom (otvorený odtok) z „push-pull“ (tlačiť ťahať) je, že na prvom kolíku nemôže akceptovať stav HIGH: pri zápise jedného do výstupného registra prejde do režimu vysokého odporu (vysoká impedancia, Ahoj-Z). Pri zápise nuly sa pin chová rovnako v oboch režimoch, logicky aj elektricky.

V normálnom výstupnom režime pin jednoducho vysiela obsah výstupného registra. V „alternatíve“ je ovládaná príslušnými perifériami (pozri 9.1.4):

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Ak je bit portu nakonfigurovaný ako kolík alternatívnej funkcie, register kolíkov je deaktivovaný a kolík je pripojený k kolíku periférneho zariadenia.

Alternatívna funkčnosť každého kolíka je popísaná v Definície špendlíkov Datasheet je na stiahnutom obrázku. Na otázku, čo robiť, ak má kolík niekoľko alternatívnych funkcií, je odpoveď uvedená v poznámke pod čiarou v údajovom liste:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Ak viacero periférnych zariadení používa rovnaký kolík, aby sa predišlo konfliktu medzi alternatívnymi funkciami, mala by sa súčasne používať iba jedna periféria, prepínaná pomocou bitu povolenia periférnych hodín (v príslušnom registri RCC).

Nakoniec, kolíky vo výstupnom režime majú tiež takt. Toto je ďalšia funkcia na úsporu energie; v našom prípade ju nastavíme na maximum a zabudneme.

Takže: používame SPI, čo znamená, že dva kolíky (s dátami a hodinovým signálom) by mali byť „alternatívna funkcia push-pull“ a ďalší (LAT) by mal byť „regular push-pull“. Pred ich pridelením sa však poďme zaoberať SPI.

SPI

Ďalší malý vzdelávací program

SPI alebo Serial Peripheral Interface (sériové periférne rozhranie) je jednoduché a veľmi efektívne rozhranie na prepojenie MK s inými MK a vonkajším svetom všeobecne. Princíp jeho činnosti už bol opísaný vyššie, kde je o čínskom ovládači LED (v referenčnej príručke, pozri časť 25). SPI môže pracovať v režime master („master“) a slave („slave“). SPI má štyri základné kanály, z ktorých nie všetky možno použiť:

  • MOSI, Master Output / Slave Input: tento kolík prenáša údaje v režime master a prijíma údaje v režime slave;
  • MISO, Master Input / Slave Output: naopak prijíma v masteri a vysiela v slave;
  • SCK, Serial Clock: nastavuje frekvenciu prenosu dát v masteri alebo prijíma hodinový signál v slave. V podstate biť beaty;
  • SS, Slave Select: pomocou tohto kanála otrok vie, že sa od neho niečo chce. Na STM32 sa nazýva NSS, kde N = záporné, t.j. ovládač sa stane podriadeným, ak je v tomto kanáli uzemnenie. Dobre sa kombinuje s režimom Open Drain Output, ale to je už iný príbeh.

Rovnako ako všetko ostatné, aj SPI na STM32 je bohatý na funkčnosť, čo sťažuje jeho pochopenie. Napríklad môže pracovať nielen s SPI, ale aj s rozhraním I2S a v dokumentácii sú ich popisy zmiešané, je potrebné včas odrezať prebytok. Naša úloha je veľmi jednoduchá: potrebujeme posielať dáta iba pomocou MOSI a SCK. Ideme do časti 25.3.4 (polovičná duplexná komunikácia, poloduplexná komunikácia), kde nájdeme 1 hodinový a 1 jednosmerný dátový kábel (1 hodinový signál a 1 jednosmerný dátový tok):

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
V tomto režime aplikácia používa SPI v režime iba na vysielanie alebo iba na príjem. / Režim iba vysielania je podobný duplexnému režimu: údaje sa prenášajú na vysielacom kolíku (MOSI v režime master alebo MISO v režime slave) a prijímací kolík (MISO alebo MOSI v tomto poradí) možno použiť ako bežný vstupno-výstupný kolík . V tomto prípade stačí aplikácii ignorovať vyrovnávaciu pamäť Rx (ak je načítaná, nebudú tam žiadne prenesené dáta).

Super, pin MISO je voľný, pripojíme naň signál LAT. Pozrime sa na Slave Select, ktorý je na STM32 možné ovládať programovo, čo je mimoriadne pohodlné. Prečítali sme si odsek s rovnakým názvom v časti 25.3.1 Všeobecný popis SPI:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Softvérové ​​riadenie NSS (SSM = 1) / Informácie o výbere Slave sú obsiahnuté v bite SSI registra SPI_CR1. Externý kolík NSS zostáva voľný pre potreby iných aplikácií.

Je čas na zápis do registrov. Rozhodol som sa použiť SPI2, jeho základnú adresu vyhľadajte v údajovom liste - v časti 3.3 Mapa pamäte:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

No, začnime:

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

Otvorte sekciu 25.3.3 so samovysvetľujúcim názvom „Konfigurácia SPI v hlavnom režime“:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

1. Nastavte frekvenciu sériových hodín bitmi BR[2:0] v registri SPI_CR1.

Registre sú zhromaždené v sekcii referenčnej príručky s rovnakým názvom. Posun adresy (Posun adresy) pre CR1 – 0x00 sú predvolene všetky bity vymazané (Resetovať hodnotu 0x0000):

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

Bity BR nastavujú delič hodín regulátora, čím určujú frekvenciu, na ktorej bude SPI pracovať. Naša frekvencia STM32 bude 72 MHz, ovládač LED podľa jeho datasheetu pracuje s frekvenciou až 25 MHz, takže musíme vydeliť štyrmi (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. Nastavte bity CPOL a CPHA na definovanie vzťahu medzi prenosom údajov a časovaním sériových hodín (pozrite si diagram na strane 240)

Keďže tu čítame údajový list a nepozeráme sa na schémy, pozrime sa bližšie na textový popis bitov CPOL a CPHA na strane 704 (všeobecný popis SPI):

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Fáza a polarita hodín
Pomocou bitov CPOL a CPHA registra SPI_CR1 môžete programovo vybrať štyri časové vzťahy. Bit CPOL (polarita hodín) riadi stav hodinového signálu, keď sa neprenášajú žiadne dáta. Tento bit riadi režimy master a slave. Ak je CPOL resetovaný, kolík SCK je v pokojovom režime nízky. Ak je nastavený bit CPOL, kolík SCK je počas pokojového režimu vysoký.
Keď je nastavený bit CPHA (fáza hodín), záblesk vysokej bitovej pasce je druhou hranou signálu SCK (klesajúci, ak je CPOL voľný, stúpajúci, ak je nastavený CPOL). Údaje sú zachytené druhou zmenou hodinového signálu. Ak je bit CPHA čistý, záblesk zachytávania vysokého bitu je vzostupnou hranou signálu SCK (zostupná hrana, ak je nastavený CPOL, vzostupná hrana, ak je CPOL vymazaný). Dáta sa zachytia pri prvej zmene hodinového signálu.

Po vstrebaní týchto poznatkov dospejeme k záveru, že oba bity musia zostať nulové, pretože Chceme, aby signál SCK zostal nízky, keď sa nepoužíval, a aby sa dáta prenášali na vzostupnej hrane impulzu (pozri obr. Rising Edge v údajovom liste DM634).

Mimochodom, tu sme sa prvýkrát stretli s vlastnosťou slovnej zásoby v údajových listoch ST: v nich je napísaná fráza „vynulovať bit na nulu“ trochu resetovaťA nie trochu sa vyjasniť, ako napríklad Atmega.

3. Nastavte bit DFF, aby ste určili, či má dátový blok 8-bitový alebo 16-bitový formát

Konkrétne som vzal 16-bitový DM634, aby som sa neobťažoval s prenosom 12-bitových PWM dát, ako je DM633. Má zmysel nastaviť DFF na jednu:

#define DFF         0x0800

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

4. Nakonfigurujte bit LSBFIRST v registri SPI_CR1, aby ste určili formát bloku

LSBFIRST, ako už názov napovedá, konfiguruje prenos s najmenej významným bitom ako prvý. Ale DM634 chce prijímať dáta od najvýznamnejšieho bitu. Preto ho necháme resetovaný.

5. Ak sa v hardvérovom režime vyžaduje vstup z kolíka NSS, priveďte na kolík NSS vysoký signál počas celej sekvencie prenosu bajtov. V softvérovom režime NSS nastavte bity SSM a SSI v registri SPI_CR1. Ak má byť pin NSS použitý ako výstup, je potrebné nastaviť iba bit SSOE.

Nainštalujte SSM a SSI, aby ste zabudli na hardvérový režim NSS:

#define SSI         0x0100
#define SSM         0x0200

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

6. Musia byť nastavené bity MSTR a SPE (zostanú nastavené, iba ak je signál NSS vysoký)

V skutočnosti pomocou týchto bitov označíme naše SPI ako hlavné a zapneme ho:

#define MSTR        0x0004
#define SPE         0x0040

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

SPI je nakonfigurované, okamžite napíšme funkcie, ktoré posielajú bajty ovládaču. Pokračovať v čítaní 25.3.3 „Konfigurácia SPI v hlavnom režime“:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Objednávka prenosu dát
Prenos začína, keď je bajt zapísaný do vyrovnávacej pamäte Tx.
Dátový bajt sa načíta do posuvného registra na paralelný režimu (z internej zbernice) pri prenose prvého bitu, po ktorom sa prenesie do sekvenčné Režim MOSI pin, prvý alebo posledný bit dopredu v závislosti od nastavenia bitu LSBFIRST v registri CPI_CR1. Príznak TXE sa nastaví po prenose dát z vyrovnávacej pamäte Tx do posuvného registraa tiež generuje prerušenie, ak je nastavený bit TXEIE v registri CPI_CR1.

Zvýraznil som pár slov v preklade, aby som upozornil na jednu vlastnosť implementácie SPI v ovládačoch STM. Na Atmega vlajka TXE (Tx Empty, Tx je prázdny a pripravený na príjem dát) sa nastaví až po odoslaní celého bajtu smerom von. A tu sa tento príznak nastavuje po vložení bajtu do interného posuvného registra. Keďže sa tam posúva so všetkými bitmi súčasne (paralelne), a potom sa dáta prenášajú postupne, nastaví sa TXE ešte pred úplným odoslaním bajtu. To je dôležité, pretože v prípade nášho LED ovládača musíme po odoslaní vytiahnuť kolík LAT všetko údaje, t.j. Samotná vlajka TXE nám stačiť nebude.

To znamená, že potrebujeme ďalšiu vlajku. Pozrime sa na 25.3.7 - „Príznaky stavu“:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
<…>
Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Vlajka BUSY
Príznak BSY je nastavený a vymazaný hardvérom (zápis do neho nemá žiadny vplyv). Príznak BSY označuje stav komunikačnej vrstvy SPI.
Resetuje sa:
po dokončení prenosu (okrem hlavného režimu, ak je prenos nepretržitý)
keď je SPI vypnuté
keď sa vyskytne chyba hlavného režimu (MODF=1)
Ak prenos nie je nepretržitý, príznak BSY sa medzi každým prenosom údajov vymaže

Dobre, toto sa vám bude hodiť. Poďme zistiť, kde sa nachádza vyrovnávacia pamäť Tx. Ak to chcete urobiť, prečítajte si „Registrácia údajov SPI“:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Bity 15:0 DR[15:0] Data Register
Prijaté údaje alebo údaje, ktoré sa majú preniesť.
Dátový register je rozdelený na dve vyrovnávacie pamäte – jednu na zápis (vysielacia vyrovnávacia pamäť) a jednu na čítanie (prijímacia vyrovnávacia pamäť). Zápis do dátového registra zapisuje do vyrovnávacej pamäte Tx a čítanie z dátového registra vráti hodnotu obsiahnutú v vyrovnávacej pamäti Rx.

No a stavový register, kde sa nachádzajú príznaky TXE a BSY:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

Píšeme:

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

No, keďže potrebujeme preniesť 16 krát dva bajty, podľa počtu výstupov LED ovládača, niečo takéto:

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

Zatiaľ však nevieme, ako vytiahnuť kolík LAT, takže sa vrátime k I/O.

Priradenie pinov

V STM32F1 sú registre zodpovedné za stav kolíkov dosť nezvyčajné. Je jasné, že ich je viac ako Atmega, no zároveň sa líšia od ostatných STM čipov. Časť 9.1 Všeobecný popis GPIO:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Každý zo všeobecných I/O portov (GPIO) má dva 32-bitové konfiguračné registre (GPIOx_CRL a GPIOx_CRH), dva 32-bitové dátové registre (GPIOx_IDR a GPIOx_ODR), 32-bitový register set/reset (GPIOx_BSRR), 16-bitový resetovací register (GPIOx_BRR) a 32-bitový register. register blokovania bitov (GPIOx_LCKR).

Prvé dva registre sú nezvyčajné a tiež dosť nepohodlné, pretože 16 pinov portov je na nich roztrúsených vo formáte „štyri bity na brata“. Tie. kolíky nula až sedem sú v CRL a zvyšok je v CRH. Súčasne zostávajúce registre úspešne obsahujú bity všetkých pinov portu - často zostávajú napoly „rezervované“.

Pre jednoduchosť začneme od konca zoznamu.

Nepotrebujeme blokovací register.

Nastavovacie a resetovacie registre sú celkom vtipné v tom, že sa čiastočne duplikujú: všetko môžete zapísať iba v BSRR, kde vyšších 16 bitov vynuluje pin a nižšie na 1, alebo môžete tiež použite BRR, z ktorých dolných 16 bitov iba resetuje pin . Páči sa mi druhá možnosť. Tieto registre sú dôležité, pretože poskytujú atómový prístup k pinom:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Atomic Set alebo Reset
Pri programovaní GPIOx_ODR na bitovej úrovni nie je potrebné deaktivovať prerušenia: jeden alebo viac bitov je možné zmeniť jedinou operáciou atómového zápisu APB2. Dosiahne sa to zapísaním „1“ do registra set/reset (GPIOx_BSRR alebo, len pre reset, GPIOx_BRR) bitu, ktorý je potrebné zmeniť. Ostatné bity zostanú nezmenené.

Dátové registre majú celkom zrozumiteľné názvy - IDR = Vstup Smerový register, vstupný register; ODR = Výkon Smerový register, výstupný register. V aktuálnom projekte ich nebudeme potrebovať.

A nakoniec riadiace registre. Keďže nás zaujímajú druhé piny SPI, konkrétne PB13, PB14 a PB15, okamžite sa pozrieme na CRH:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

A vidíme, že budeme musieť niečo napísať v bitoch od 20 do 31.

Vyššie sme si už vymysleli, čo od pinov chceme, takže tu sa zaobídem bez screenshotu, len poviem, že MODE udáva smer (vstup, ak sú oba bity nastavené na 0) a rýchlosť pinu (potrebujeme 50MHz, t.j. oba piny na „1“) a CNF nastaví režim: bežný „push-pull“ – 00, „alternatívny“ – 10. Štandardne, ako vidíme vyššie, všetky kolíky majú tretí bit zdola (CNF0), nastaví ich do režimu plávajúci vstup.

Keďže s týmto čipom plánujem urobiť niečo iné, pre jednoduchosť som definoval všetky možné hodnoty MODE a CNF pre dolný aj horný riadiaci register.

Nejako takto

#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še piny sú umiestnené na porte B (základná adresa – 0x40010C00), kód:

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

A podľa toho môžete napísať definície pre LAT, ktoré budú trhané registrami BRR a 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_low len zotrvačnosťou, vždy to tak bolo, nech to tak zostane)

Teraz je všetko skvelé, ale nefunguje to. Keďže ide o STM32, šetria elektrickú energiu, čo znamená, že musíte povoliť taktovanie požadovaných periférií.

Zapnite hodiny

Hodinky, známe aj ako Clock, majú na starosti taktovanie. A to sme si už mohli všimnúť skratku RCC. Hľadáme to v dokumentácii: toto je Reset and Clock Control.

Ako bolo povedané vyššie, našťastie, najťažšiu časť taktovacej témy nám spravili ľudia zo STM, za čo im veľmi pekne ďakujeme (ešte raz dám link na Web Di Halt, aby bolo jasné, aké je to mätúce). Potrebujeme len registre zodpovedné za umožnenie periférneho taktovania (Peripheral Clock Enable Registers). Najprv nájdime základnú adresu RCC, je na úplnom začiatku „mapy pamäte“:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

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

A potom buď kliknite na odkaz, kde sa pokúsite nájsť niečo v tanieri, alebo oveľa lepšie, prejdite si popisy aktivačných registrov z častí o povoliť registre. Kde nájdeme RCC_APB1ENR a RCC_APB2ENR:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

A teda obsahujú bity, ktoré zahŕňajú taktovanie SPI2, IOPB (I/O Port B) a alternatívne funkcie (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;

Konečný kód nájdete tu.

Ak máte možnosť a chuť testovať, tak pripojte DM634 takto: DAI k PB15, DCK k PB13, LAT k PB14. Vodič napájame z 5 voltov, nezabudnite pripojiť uzemnenie.

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

STM8 PWM

PWM na STM8

Keď som len plánoval tento článok, rozhodol som sa ako príklad skúsiť zvládnuť nejakú funkcionalitu neznámeho čipu iba pomocou datasheetu, aby som neskončil u obuvníka bez čižiem. STM8 bol pre túto úlohu ideálny: po prvé, mal som pár čínskych dosiek s STM8S103 a po druhé, nie je veľmi populárny, a preto pokušenie čítať a nájsť riešenie na internete spočíva v nedostatku týchto riešení.

Čip má tiež dátový hárok и referenčná príručka RM0016, v prvom je pinout a adresa registra, v druhom - všetko ostatné. STM8 je naprogramovaný v C v hroznom IDE ST Visual Develop.

Hodiny a I/O

Štandardne STM8 pracuje na frekvencii 2 MHz, treba to okamžite opraviť.

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
HSI (vysokorýchlostné vnútorné) hodiny
Hodinový signál HSI je odvodený z interného 16 MHz RC oscilátora s programovateľným deličom (1 až 8). Nastavuje sa v registri deliča hodín (CLK_CKDIVR).
Poznámka: na začiatku je ako hlavný zdroj hodinového signálu zvolený HSI RC oscilátor s deličom 8.

Adresu registra nájdeme v údajovom liste, popis v refman a vidíme, že register je potrebné vymazať:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Keďže ideme spustiť PWM a pripojiť LED diódy, pozrime sa na pinout:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

Čip je malý, veľa funkcií je zavesených na rovnakých pinoch. To, čo je v hranatých zátvorkách, je „alternatívna funkčnosť“, prepína sa pomocou „bajtov možností“ (možnosť bajtov) – niečo ako poistky Atmega. Ich hodnoty môžete zmeniť programovo, ale nie je to potrebné, pretože Nová funkcia sa aktivuje až po reštarte. Jednoduchšie je použiť ST Visual Programmer (stiahnutý pomocou Visual Develop), ktorý dokáže zmeniť tieto bajty. Pinout ukazuje, že kolíky CH1 a CH2 prvého časovača sú skryté v hranatých zátvorkách; v STVP je potrebné nastaviť bity AFR1 a AFR0 a druhý prenesie aj výstup CH1 druhého časovača z PD4 do PC5.

Takže 6 pinov bude ovládať LED diódy: PC6, PC7 a PC3 pre prvý časovač, PC5, PD3 a PA3 pre druhý.

Nastavenie samotných I/O pinov na STM8 je jednoduchšie a logickejšie ako na STM32:

  • známy z registra smeru údajov Atmega DDR (Register smeru údajov): 1 = výstup;
  • prvý riadiaci register CR1, keď je na výstupe, nastavuje režim push-pull (1) alebo otvorený odtok (0); keďže LED pripájam k čipu katódami, nechávam tu nuly;
  • druhý riadiaci register CR2 pri výstupe nastavuje frekvenciu hodín: 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

nastavenie PWM

Najprv si definujme pojmy:

  • Frekvencia PWM – frekvencia, s akou tiká časovač;
  • Automatické opätovné načítanie, AR – automaticky načítateľná hodnota, do ktorej bude časovač počítať (obdobie impulzu);
  • Aktualizovať udalosť, UEV – udalosť, ktorá nastane, keď časovač napočítal do AR;
  • Pracovný cyklus PWM – pracovný cyklus PWM, často nazývaný „pracovný faktor“;
  • Zachytiť/porovnať hodnotu – hodnota pre zachytenie/porovnanie, do ktorej počítalo časovač niečo urobí (v prípade PWM invertuje výstupný signál);
  • Hodnota predpätia – prednastavená hodnota. Porovnajte hodnotu nemôže zmeniť, kým tiká časovač, inak sa cyklus PWM preruší. Preto sa nové prenášané hodnoty uložia do vyrovnávacej pamäte a vytiahnu sa, keď časovač dosiahne koniec odpočítavania a vynuluje sa;
  • Zarovnané na okraj и Režimy zarovnané na stred – zarovnanie pozdĺž hranice a v strede, rovnaké ako Atmel Rýchle PWM и Fázovo správne PWM.
  • OCiREF, výstupný porovnávací referenčný signál – referenčný výstupný signál, v skutočnosti to, čo sa objaví na príslušnom kolíku v režime PWM.

Ako je už zrejmé z pinoutu, dva časovače majú schopnosti PWM – prvý a druhý. Oba sú 16-bitové, prvý má množstvo doplnkových funkcií (najmä vie počítať hore aj dole). Potrebujeme, aby obe fungovali rovnako, a tak som sa rozhodol začať tým zjavne chudobnejším druhým, aby som náhodou nepoužil niečo, čo tam nie je. Určitým problémom je, že popis funkčnosti PWM všetkých časovačov v referenčnej príručke je v kapitole o prvom časovači (17.5.7 Režim PWM), takže musíte neustále skákať tam a späť v celom dokumente.

PWM na STM8 má dôležitú výhodu oproti PWM na Atmega:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Hranične zarovnané PWM
Konfigurácia účtu zdola nahor
Počítanie zdola nahor je aktívne, ak je bit DIR v registri TIM_CR1 vymazaný
Príklad
Príklad používa prvý režim PWM. Referenčný signál PWM OCiREF je udržiavaný vysoko, pokiaľ TIM1_CNT < TIM1_CCRi. V opačnom prípade to trvá na nízkej úrovni. Ak je porovnávacia hodnota v registri TIM1_CCRi väčšia ako hodnota automatického načítania (register TIM1_ARR), signál OCiREF sa podrží na 1. Ak je porovnávacia hodnota 0, OCiREF sa udržiava na nule....

Časovač STM8 počas aktualizovať udalosť najprv skontroluje porovnať hodnotua až potom vytvára referenčný signál. Časovač Atmega sa najskôr poskrutkuje a potom porovná, čo vedie k compare value == 0 výstupom je ihla, s ktorou sa treba nejako vysporiadať (napr. programovým invertovaním logiky).

Čo teda chceme urobiť: 8-bitové PWM (AR == 255), počítanie zdola nahor, zarovnanie pozdĺž hranice. Keďže žiarovky sú pripojené k čipu katódami, PWM by mal vydávať 0 (LED svieti), kým porovnať hodnotu a 1 po.

O niektorých sme už čítali Režim PWM, takže požadovaný register druhého časovača nájdeme vyhľadaním tejto frázy v referenčnej príručke (18.6.8 - TIMx_CCMR1):

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
110: Prvý režim PWM – pri počítaní zdola nahor je aktívny prvý kanál, kým TIMx_CNT < TIMx_CCR1. V opačnom prípade je prvý kanál neaktívny. [ďalej v dokumente je chybné kopírovanie-prilepenie z časovača 1] 111: Druhý režim PWM – pri počítaní zdola nahor je prvý kanál neaktívny, kým TIMx_CNT < TIMx_CCR1. V opačnom prípade je aktívny prvý kanál.

Keďže sú LED diódy pripojené k MK katódami, vyhovuje nám druhý režim (tiež prvý, ale to ešte nevieme).

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Bit 3 OC1PE: Povolenie predpätia kolíka 1
0: Preload register na TIMx_CCR1 je zakázaný. Do TIMx_CCR1 môžete napísať kedykoľvek. Nová hodnota funguje okamžite.
1: Predbežné načítanie registra na TIMx_CCR1 je povolené. Operácie čítania/zápisu pristupujú k registru predbežného načítania. Predinštalovaná hodnota TIMx_CCR1 sa načíta do tieňového registra počas každej udalosti aktualizácie.
*Poznámka: Aby režim PWM fungoval správne, musia byť povolené registre predbežného načítania. Toto nie je potrebné v režime jedného signálu (bit OPM je nastavený v registri TIMx_CR1).

Dobre, zapnime všetko, čo potrebujeme pre tri kanály druhého časovača:

#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 pozostáva z dvoch osembitových registrov, všetko je jednoduché:

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

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Druhý časovač môže počítať iba zdola nahor, zarovnanie pozdĺž hranice, netreba nič meniť. Delič frekvencie nastavíme napríklad na 256. Pre druhý časovač je delič nastavený v registri TIM2_PSCR a je mocninou dvoch:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Ostáva už len zapnúť závery a samotný druhý časovač. Prvý problém riešia registre Zachytiť/Porovnať Umožniť: sú tam dva, tri kanály roztrúsené cez ne asymetricky. Tu sa môžeme dozvedieť aj to, že je možné meniť polaritu signálu, t.j. v princípe bolo možné použiť PWM Mode 1. Píšeme:

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

A nakoniec spustíme časovač v registri TIMx_CR1:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Napíšme jednoduchý analóg AnalogWrite(), ktorý prenesie skutočné hodnoty do časovača na porovnanie. Registre sú pomenované predvídateľne Zachytiť/porovnať registre, existujú dva z nich pre každý kanál: 8 bitov nižšieho rádu v TIM2_CCRxL a bitov vyššieho rádu v TIM2_CCRxH. Keďže sme vytvorili 8-bitové PWM, stačí zapísať len tie najmenej významné bity:

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

Pozorný čitateľ si všimne, že máme mierne chybnú PWM, ktorá nedokáže produkovať 100% naplnenie (pri maximálnej hodnote 255 je signál invertovaný na jeden cyklus časovača). V prípade LED na tom nezáleží a pozorný čitateľ už vie, ako to opraviť.

PWM na druhom časovači funguje, prejdime k prvému.

Prvý časovač má presne rovnaké bity v rovnakých registroch (len tie bity, ktoré zostali „rezervované“ v druhom časovači, sa v prvom aktívne používajú na všetky druhy pokročilých vecí). Preto stačí nájsť adresy rovnakých registrov v datasheete a skopírovať kód. Zmeňte hodnotu frekvenčného deliča, pretože... prvý časovač chce prijať nie mocninu dvoch, ale presnú 16-bitovú hodnotu v dvoch registroch Preddelička vysoká и Nízky. Robíme všetko a... prvý časovač nefunguje. Čo sa deje?

Problém sa dá vyriešiť len tak, že si prezrieme celú časť o riadiacich registroch časovača 1, kde hľadáme ten, ktorý druhý časovač nemá. Tam bude 17.7.30 Registrácia prestávok (TIM1_BKR), kde je tento bit:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Povoliť hlavný výstup

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

To je teraz určite všetko, kód tam.

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

Multiplex STM8

Multiplexovanie na STM8

Tretím miniprojektom je pripojiť osem RGB LED diód k druhému časovaču v režime PWM a dosiahnuť, aby zobrazovali rôzne farby. Vychádza z konceptu LED multiplexovania, ktorý spočíva v tom, že ak veľmi, veľmi rýchlo zapínate a vypínate LED diódy, bude sa nám zdať, že neustále svietia (perzistencia videnia, zotrvačnosť zrakového vnímania). Raz som to urobil niečo také na Arduine.

Algoritmus práce vyzerá takto:

  • pripojená anóda prvej RGB LED;
  • zapálil ju a poslal potrebné signály na katódy;
  • čakal až do konca cyklu PWM;
  • pripojená anóda druhej RGB LED;
  • zapálil to...

No atď. Samozrejme, pre krásnu prevádzku je potrebné, aby bola pripojená anóda a súčasne sa „zapálila“ LED. No, alebo skoro. V každom prípade musíme napísať kód, ktorý bude vydávať hodnoty v troch kanáloch druhého časovača, meniť ich pri dosiahnutí UEV a zároveň meniť aktuálne aktívnu RGB LED.

Keďže prepínanie LED je automatické, musíme si vytvoriť „video pamäť“, z ktorej bude obsluha prerušení prijímať dáta. Toto je jednoduché pole:

uint8_t colors[8][3];

Ak chcete zmeniť farbu konkrétnej LED, stačí do tohto poľa zapísať požadované hodnoty. A premenná bude zodpovedná za počet aktívnych LED

uint8_t cnt;

Demux

Pre správne multiplexovanie potrebujeme, napodiv, demultiplexor CD74HC238. Demultiplexer - čip, ktorý implementuje operátora do hardvéru <<. Cez tri vstupné piny (bity 0, 1 a 2) mu privedieme trojbitové číslo X a ako odpoveď aktivuje výstupné číslo (1<<X). Zvyšné vstupy čipu slúžia na škálovanie celého dizajnu. Tento čip potrebujeme nielen kvôli zníženiu počtu obsadených pinov mikrokontroléra, ale aj kvôli bezpečnosti – aby sa nám náhodou nerozsvietilo viac LED ako je možné a nespálil sa MK. Čip stojí cent a mal by byť vždy uložený vo vašej domácej lekárničke.

Náš CD74HC238 bude zodpovedný za napájanie anódy požadovanej LED. V plnohodnotnom multiplexe by dodával napätie do stĺpca cez P-MOSFET, ale v tomto deme je to možné priamo, lebo odoberá 20 mA, podľa aboslútne maximálne hodnotenie v údajovom liste. Od Údajový list CD74HC238 potrebujeme pinouty a tento cheat sheet:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
H = úroveň vysokého napätia, L = úroveň nízkeho napätia, X – to je jedno

Pripojíme E2 a E1 k zemi, E3, A0, A1 a A3 k pinom PD5, PC3, PC4 a PC5 STM8. Keďže vyššie uvedená tabuľka obsahuje nízke aj vysoké úrovne, konfigurujeme tieto kolíky ako kolíky push-pull.

PWM

PWM na druhom časovači je nakonfigurovaný rovnakým spôsobom ako v predchádzajúcom príbehu s dvoma rozdielmi:

Najprv musíme povoliť prerušenie Aktualizovať udalosť (UEV), ktorá zavolá funkciu, ktorá prepína aktívnu LED. To sa dosiahne zmenou bitu Povoliť prerušenie aktualizácie v registri s výrečným menom

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
Register povolenia prerušenia

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Druhý rozdiel súvisí s fenoménom multiplexovania, ako napr ghosting – parazitná žiara diód. V našom prípade sa to môže objaviť v dôsledku skutočnosti, že časovač, ktorý spôsobil prerušenie na UEV, naďalej tiká a obsluha prerušenia nemá čas prepnúť LED, kým časovač začne niečo zapisovať na kolíky. Aby ste tomu zabránili, budete musieť invertovať logiku (0 = maximálny jas, 255 = nič nesvieti) a vyhnúť sa extrémnym hodnotám pracovného cyklu. Tie. zabezpečte, aby po UEV LED úplne zhasli na jeden cyklus PWM.

Zmena polarity:

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

Nenastavujte r, g a b na 255 a nezabudnite ich pri používaní prevrátiť.

Prerušenia

Podstatou prerušenia je, že za určitých okolností čip prestane vykonávať hlavný program a zavolá nejakú externú funkciu. K prerušeniam dochádza v dôsledku vonkajších alebo vnútorných vplyvov, vrátane časovača.

Keď sme prvýkrát vytvorili projekt v ST Visual Develop, okrem main.c dostali sme okno so záhadným spisom stm8_interrupt_vector.c, automaticky zaradený do projektu. V tomto súbore je každému prerušeniu priradená funkcia NonHandledInterrupt. Potrebujeme naviazať našu funkciu na požadované prerušenie.

Datasheet obsahuje tabuľku vektorov prerušení, kde nájdeme tie, ktoré potrebujeme:

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8
13 Aktualizácia/pretečenie TIM2
14 TIM2 zachytiť/porovnať

Potrebujeme zmeniť LED pri UEV, takže potrebujeme prerušenie #13.

V súlade s tým po prvé v spise stm8_interrupt_vector.c zmeňte predvolený názov funkcie zodpovednej za prerušenie č. 13 (IRQ13) na svoj vlastný:

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

Po druhé, budeme musieť vytvoriť súbor main.h s nasledujúcim obsahom:

#ifndef __MAIN_H
#define __MAIN_H

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

A nakoniec túto funkciu napíšte do svojho 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;
}

Zostáva len povoliť prerušenia. To sa vykonáva pomocou príkazu assembler rim - budete to musieť hľadať v Programovací manuál:

//enable interrupts
_asm("rim");

Ďalším príkazom assembleru je sim – vypne prerušenia. Musia byť vypnuté počas zapisovania nových hodnôt do „videopamäte“, aby prerušenie spôsobené v nesprávnom okamihu nepokazilo pole.

Celý kód - na GitHub.

Čítanie údajových listov 2: SPI na STM32; PWM, časovače a prerušenia na STM8

Ak aspoň niekto považuje tento článok za užitočný, nenapísal som ho zbytočne. Budem rád za komentáre a pripomienky, pokúsim sa na všetko odpovedať.

Zdroj: hab.com

Pridať komentár