Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

В první část Snažil jsem se říci hobby inženýrům elektroniky, kteří vyrostli z kalhot Arduino, jak a proč by měli číst datové listy a další dokumentaci k mikrokontrolérům. Text se ukázal být velký, a tak jsem slíbil praktické ukázky ukázat v samostatném článku. No, říkal si mléčná houba...

Dnes vám ukážu, jak pomocí datasheetů řešit celkem jednoduché, ale pro mnoho projektů nezbytné úlohy na ovladačích STM32 (Blue Pill) a STM8. Všechny demo projekty jsou věnovány mým oblíbeným LEDkám, budeme je svítit ve velkém, k čemuž budeme muset použít nejrůznější zajímavé periferie.

Text se opět ukázal jako obrovský, takže pro pohodlí tvořím obsah:

STM32 Blue Pill: 16 LED s ovladačem DM634
STM8: Nastavení šesti pinů PWM
STM8: 8 RGB LED na třech pinech, přerušení

Upozornění: Nejsem inženýr, nepředstírám hluboké znalosti v elektronice, článek je určen pro amatéry, jako jsem já. Ve skutečnosti jsem se před dvěma lety považoval za cílovou skupinu. Kdyby mi tehdy někdo řekl, že datasheety na neznámém čipu nejsou děsivé na čtení, nestrávil bych spoustu času hledáním nějakých kousků kódu na internetu a vymýšlením berlí s nůžkami a lepicí páskou.

Tento článek se zaměřuje na datové listy, nikoli na projekty, takže kód nemusí být příliš úhledný a často stísněný. Samotné projekty jsou velmi jednoduché, i když vhodné pro první seznámení s novým čipem.

Doufám, že můj článek někomu pomůže v podobné fázi ponoření se do koníčka.

STM32

16 LED s DM634 a SPI

Malý projekt využívající Blue Pill (STM32F103C8T6) a ovladač DM634 LED. Pomocí datasheetů zjistíme ovladač, STM IO porty a nakonfigurujeme SPI.

DM634

Tchajwanský čip s 16 16bitovými PWM výstupy, lze zapojit do řetězců. Low-endový 12bitový model je znám z tuzemského projektu Lightpack. Kdysi, když jsem se rozhodoval mezi DM63x a známým TLC5940, jsem si vybral DM z několika důvodů: 1) TLC na Aliexpress je určitě falešné, ale toto není; 2) DM má autonomní PWM s vlastním frekvenčním generátorem; 3) dalo by se to koupit levně v Moskvě, než čekat na balíček od Ali. A samozřejmě bylo zajímavé naučit se ovládat čip sami, než používat hotovou knihovnu. Čipy jsou nyní prezentovány především v balení SSOP24, lze je snadno připájet k adaptéru.

Protože výrobce je Tchaj-wan, datový list čip je napsán v čínské angličtině, což znamená, že to bude zábava. Nejprve se podíváme na pinout (Pin připojení), abyste pochopili, ke které noze co připojit, a popis kolíků (Popis kolíku). 16 pinů:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Zdroje stejnosměrného umyvadla (otevřený odtok)

Dřez / Výstup s otevřeným odtokem – odtok; zdroj přitékajícího proudu; výstup je v aktivním stavu spojen se zemí - LED jsou k budiči připojeny katodami. Elektricky se samozřejmě nejedná o „otevřený odtok“ (otevřený odtok), ale v datasheetech se toto označení pro piny v režimu vypouštění často vyskytuje.

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Externí odpory mezi REXT a GND pro nastavení hodnoty výstupního proudu

Mezi pin REXT a zem je instalován referenční rezistor, který řídí vnitřní odpor výstupů, viz graf na straně 9 datového listu. V DM634 lze tento odpor ovládat také softwarově, nastavením celkového jasu (globální jas); V tomto článku nebudu zacházet do podrobností, jen sem vložím odpor 2.2 - 3 kOhm.

Abychom pochopili, jak ovládat čip, podívejme se na popis rozhraní zařízení:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

Jo, tady to je, čínská angličtina v celé své kráse. Přeložit to je problematické, můžete to pochopit, pokud chcete, ale existuje i jiný způsob - podívejte se, jak je připojení k funkčně podobnému TLC5940 popsáno v datovém listu:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
... Pro zadávání dat do zařízení jsou potřeba pouze tři piny. Náběžná hrana signálu SCLK posouvá data z pinu SIN do vnitřního registru. Po načtení všech dat krátký vysoký signál XLAT zachytí postupně přenášená data do interních registrů. Vnitřní registry jsou brány spouštěné úrovní signálu XLAT. Všechna data jsou přenášena nejvýznamnější bit jako první.

Blokovat – západka/zámek/zámek.
Stoupající hrana – náběžná hrana pulsu
Nejprve MSB – nejvýznamnější (zcela vlevo) bit vpřed.
na hodinová data – přenášet data postupně (bit po bitu).

Slovo závora se často nachází v dokumentaci k čipům a různě se překládá, takže si pro pochopení dovolím

malý vzdělávací programOvladač LED je v podstatě posuvný registr. "Shift" (posun) v názvu - bitový pohyb dat uvnitř zařízení: každý nový bit vsunutý dovnitř tlačí celý řetězec dopředu před sebe. Protože nikdo nechce pozorovat chaotické blikání LED během směny, proces probíhá ve vyrovnávacích registrech oddělených od pracovních registrů tlumičem (závora) je druh čekárny, kde jsou bity uspořádány v požadovaném pořadí. Když je vše připraveno, závěrka se otevře a bity se dají do práce a nahradí předchozí dávku. Slovo závora v dokumentaci pro mikroobvody téměř vždy předpokládá takový tlumič, bez ohledu na to, v jakých kombinacích se používá.

Přenos dat do DM634 se tedy provádí takto: nastavte vstup DAI na hodnotu nejvýznamnějšího bitu vzdálené LED, vytáhněte DCK nahoru a dolů; nastavte vstup DAI na hodnotu dalšího bitu, vytáhněte DCK; a tak dále, dokud nebudou přeneseny všechny bity (zapsáno), načež vytáhneme LAT. To lze provést ručně (bit-bang), ale je lepší použít rozhraní SPI speciálně přizpůsobené tomuto účelu, protože je na našem STM32 prezentováno ve dvou kopiích.

Modrá pilulka STM32F103

Úvod: Kontroléry STM32 jsou mnohem složitější než Atmega328, než by se mohlo zdát děsivé. Navíc z důvodu úspory energie jsou při startu téměř všechny periferie vypnuty a taktovací frekvence je 8 MHz z interního zdroje. Naštěstí programátoři STM napsali kód, který čip přivede na „vypočítaných“ 72 MHz a autoři všech IDE, které znám, jej zahrnuli do inicializační procedury, takže nemusíme taktovat (ale můžete, pokud opravdu chcete). Budete ale muset zapnout periferie.

Dokumentace: Blue Pill je vybavena oblíbeným čipem STM32F103C8T6, existují k němu dva užitečné dokumenty:

V datasheetu nás může zajímat:

  • Pinouts – chip pinouts – v případě, že se rozhodneme desky vyrobit sami;
  • Memory Map – mapa paměti pro konkrétní čip. Referenční příručka má mapu celé linky a zmiňuje registry, které ten náš nemá.
  • Tabulka definic pinů – seznam hlavních a alternativních funkcí pinů; pro „modrou pilulku“ najdete na internetu pohodlnější obrázky se seznamem pinů a jejich funkcí. Proto si okamžitě vygooglujeme Blue Pill pinout a máme tento obrázek po ruce:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Pozn.: na obrázku z internetu byla chyba, která byla uvedena v komentářích, děkuji za to. Obrázek byl nahrazen, ale toto je poučení - je lepší zkontrolovat informace, které nejsou z datasheetů.

Odebereme datový list, otevřeme referenční příručku a od této chvíle používáme pouze ji.
Postup: vyřídíme standardní vstup/výstup, nakonfigurujeme SPI, zapneme potřebné periferie.

Vstup výstup

Na Atmega328 je I/O implementován extrémně jednoduše, a proto může být množství možností STM32 matoucí. Nyní potřebujeme pouze závěry, ale i ty mají čtyři možnosti:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
otevřený odtok, push-pull, alternativní push-pull, alternativní otevřený odtok

"Táhni-tlač" (tlačit táhnout) je obvyklý výstup z Arduina, pin může mít hodnotu buď HIGH nebo LOW. Ale s „otevřeným odtokem“ existují potíže, i když ve skutečnosti je zde vše jednoduché:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Konfigurace výstupu / když je port přiřazen k výstupu: / výstupní vyrovnávací paměť povolena: / – režim otevřeného odčerpávání: „0“ ve výstupním registru povolí N-MOS, „1“ ve výstupním registru ponechá port v režimu Hi-Z ( P-MOS není aktivován ) / – režim push-pull: „0“ ve výstupním registru aktivuje N-MOS, „1“ ve výstupním registru aktivuje P-MOS.

Celý rozdíl mezi otevřeným odtokem (otevřený odtok) z „push-pull“ (tlačit táhnout) je, že na prvním kolíku nemůže přijmout stav HIGH: při zápisu jedničky do výstupního registru přejde do režimu vysokého odporu (vysoká impedance, Ahoj-Z). Při zápisu nuly se pin chová v obou režimech stejně, jak logicky, tak i elektricky.

V normálním výstupním režimu pin jednoduše vysílá obsah výstupního registru. V "alternativě" je řízena odpovídajícími periferiemi (viz 9.1.4):

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Pokud je bit portu nakonfigurován jako kolík alternativní funkce, registr kolíků je deaktivován a kolík je připojen k kolíku periferie.

Alternativní funkčnost každého pinu je popsána v Definice pinů Datasheet je na staženém obrázku. Na otázku, co dělat, když má pin několik alternativních funkcí, je odpověď uvedena poznámkou pod čarou v datovém listu:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Pokud více periferních zařízení používá stejný pin, aby se předešlo konfliktu mezi alternativními funkcemi, měla by být současně používána pouze jedna periferie, přepínaná pomocí bitu povolení periferních hodin (v příslušném registru RCC).

A konečně, piny ve výstupním režimu mají také takt. Toto je další funkce pro úsporu energie; v našem případě ji nastavíme na maximum a zapomeneme na to.

Takže: používáme SPI, což znamená, že dva piny (s daty a hodinovým signálem) by měly být „alternativní funkce push-pull“ a další (LAT) by měl být „regular push-pull“. Než je ale přiřadíme, pojďme se zabývat SPI.

SPI

Další malý vzdělávací program

SPI neboli Serial Peripheral Interface (sériové periferní rozhraní) je jednoduché a velmi efektivní rozhraní pro propojení MK s jinými MK a vnějším světem obecně. Princip jeho činnosti již byl popsán výše, kde o čínském ovladači LED (v referenční příručce, viz část 25). SPI může pracovat v režimu master („master“) a slave („slave“). SPI má čtyři základní kanály, z nichž ne všechny lze použít:

  • MOSI, Master Output / Slave Input: tento pin přenáší data v master režimu a přijímá data v slave režimu;
  • MISO, Master Input / Slave Output: naopak přijímá v masteru a vysílá v slave;
  • SCK, Serial Clock: nastavuje frekvenci přenosu dat v masteru nebo přijímá hodinový signál v slave. V podstatě údery do rytmů;
  • SS, Slave Select: s pomocí tohoto kanálu slave ví, že se po něm něco chce. Na STM32 se nazývá NSS, kde N = negativní, tzn. regulátor se stane slave, pokud je v tomto kanálu uzemnění. Dobře se kombinuje s režimem Open Drain Output, ale to je jiný příběh.

Stejně jako všechno ostatní je SPI na STM32 bohaté na funkčnost, což ztěžuje jeho pochopení. Například může pracovat nejen s SPI, ale také s rozhraním I2S a v dokumentaci jsou jejich popisy smíšené, je třeba včas odříznout přebytek. Náš úkol je extrémně jednoduchý: stačí posílat data pouze pomocí MOSI a SCK. Jdeme do sekce 25.3.4 (poloviční duplexní komunikace, poloduplexní komunikace), kde najdeme 1 hodinový a 1 jednosměrný datový vodič (1 hodinový signál a 1 jednosměrný datový tok):

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
V tomto režimu aplikace používá SPI v režimu pouze pro vysílání nebo pouze pro příjem. / Režim pouze vysílání je podobný duplexnímu režimu: data jsou přenášena na vysílacím kolíku (MOSI v režimu master nebo MISO v režimu slave) a přijímací kolík (MISO nebo MOSI v tomto pořadí) lze použít jako běžný I/O kolík . V tomto případě stačí aplikaci ignorovat Rx buffer (pokud je načten, nebudou tam žádná přenesená data).

Výborně, pin MISO je volný, připojíme na něj signál LAT. Podívejme se na Slave Select, který lze na STM32 ovládat programově, což je mimořádně pohodlné. Přečetli jsme si stejnojmenný odstavec v sekci 25.3.1 Obecný popis SPI:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Softwarové řízení NSS (SSM = 1) / Informace o výběru Slave jsou obsaženy v bitu SSI registru SPI_CR1. Externí pin NSS zůstává volný pro potřeby jiných aplikací.

Je čas zapsat se do registrů. Rozhodl jsem se použít SPI2, hledejte jeho základní adresu v datovém listu - v sekci 3.3 Mapa paměti:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

No, začněme:

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

Otevřete sekci 25.3.3 se samovysvětlujícím názvem „Konfigurace SPI v režimu Master“:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

1. Nastavte frekvenci sériového hodin pomocí bitů BR[2:0] v registru SPI_CR1.

Registry jsou shromážděny ve stejnojmenné části referenční příručky. Posun adresy (Offset adresy) pro CR1 – 0x00 jsou ve výchozím nastavení všechny bity vymazány (Resetovat hodnotu 0x0000):

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

Bity BR nastavují dělič hodin regulátoru a tím určují frekvenci, na které bude SPI pracovat. Naše frekvence STM32 bude 72 MHz, ovladač LED podle jeho datasheetu pracuje s frekvencí až 25 MHz, takže musíme vydělit čtyřmi (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, abyste definovali vztah mezi přenosem dat a časováním sériových hodin (viz diagram na straně 240)

Protože zde čteme datový list a nedíváme se na schémata, podívejme se blíže na textový popis bitů CPOL a CPHA na straně 704 (SPI General Description):

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Fáze a polarita hodin
Pomocí bitů CPOL a CPHA registru SPI_CR1 můžete programově vybrat čtyři vztahy časování. Bit CPOL (polarita hodin) řídí stav hodinového signálu, když nejsou přenášena žádná data. Tento bit řídí režimy master a slave. Pokud je CPOL resetován, je pin SCK v klidovém režimu nízký. Pokud je nastaven bit CPOL, je pin SCK v klidovém režimu vysoký.
Když je bit CPHA (fáze hodin) nastaven, záblesk horní bitové pasti je druhou hranou signálu SCK (klesá, pokud je CPOL volný, stoupá, pokud je nastaveno CPOL). Data jsou zachycena druhou změnou hodinového signálu. Pokud je bit CPHA prázdný, záblesk horní bitové pasti je náběžná hrana signálu SCK (sestupná hrana, pokud je nastavena CPOL, vzestupná hrana, pokud je CPOL vymazána). Data jsou zachycena při první změně hodinového signálu.

Po vstřebání těchto znalostí dojdeme k závěru, že oba bity musí zůstat nulové, protože Chceme, aby signál SCK zůstal nízký, když se nepoužívá, a aby se data přenášela na náběžné hraně pulsu (viz obr. Rising Edge v datovém listu DM634).

Mimochodem, zde jsme se poprvé setkali s rysem slovní zásoby v datasheetech ST: v nich je napsána fráze „reset bit to zero“ trochu resetovatA ne trochu vyčistit, jako je například Atmega.

3. Nastavte bit DFF, abyste určili, zda je datový blok 8bitový nebo 16bitový formát

Konkrétně jsem vzal 16bitový DM634, abych se neobtěžoval s přenosem 12bitových PWM dat, jako je DM633. Má smysl nastavit DFF na jednu:

#define DFF         0x0800

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

4. Pro určení formátu bloku nakonfigurujte bit LSBFIRST v registru SPI_CR1

LSBFIRST, jak jeho název napovídá, konfiguruje přenos s nejméně významným bitem jako první. Ale DM634 chce přijímat data od nejvýznamnějšího bitu. Proto jej necháme resetovat.

5. Pokud je v hardwarovém režimu vyžadován vstup z kolíku NSS, přiveďte na kolík NSS během celé sekvence přenosu bajtů vysoký signál. V softwarovém režimu NSS nastavte bity SSM a SSI v registru SPI_CR1. Pokud má být pin NSS použit jako výstup, je potřeba nastavit pouze bit SSOE.

Nainstalujte SSM a SSI, abyste zapomněli na hardwarový režim NSS:

#define SSI         0x0100
#define SSM         0x0200

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

6. Musí být nastaveny bity MSTR a SPE (zůstanou nastaveny pouze v případě, že je signál NSS vysoký)

Ve skutečnosti pomocí těchto bitů označíme naše SPI jako hlavní a zapneme jej:

#define MSTR        0x0004
#define SPE         0x0040

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

SPI je nakonfigurováno, pojďme rovnou napsat funkce, které posílají bajty ovladači. Pokračovat ve čtení 25.3.3 „Konfigurace SPI v hlavním režimu“:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Objednávka přenosu dat
Přenos začíná, když je bajt zapsán do vyrovnávací paměti Tx.
Datový bajt se načte do posuvného registru at paralelní režimu (z vnitřní sběrnice) při přenosu prvního bitu, po kterém je přenesen na sekvenční Režim MOSI pin, první nebo poslední bit vpřed v závislosti na nastavení bitu LSBFIRST v registru CPI_CR1. Příznak TXE je nastaven po přenosu dat z Tx bufferu do posuvného registrua také generuje přerušení, pokud je nastaven bit TXEIE v registru CPI_CR1.

Zvýraznil jsem pár slov v překladu, abych upozornil na jednu vlastnost implementace SPI v STM kontrolérech. Na Atmega příznak TXE (Tx je prázdný, Tx je prázdný a připraven k příjmu dat) se nastavuje až po odeslání celého bajtu ven. A zde se tento příznak nastavuje po vložení bajtu do interního posuvného registru. Vzhledem k tomu, že se tam strčí se všemi bity současně (paralelně), a pak se data přenášejí sekvenčně, nastaví se TXE před úplným odesláním bytu. To je důležité, protože v případě našeho LED ovladače musíme po odeslání vytáhnout LAT pin vše údaje, tzn. Samotný příznak TXE nám stačit nebude.

To znamená, že potřebujeme další vlajku. Podívejme se na 25.3.7 - „Příznaky stavu“:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
<…>
Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Vlajka BUSY
Příznak BSY je nastaven a vymazán hardwarem (zápis do něj nemá žádný vliv). Příznak BSY označuje stav komunikační vrstvy SPI.
Resetuje se:
po dokončení přenosu (kromě hlavního režimu, pokud je přenos nepřetržitý)
když je SPI deaktivováno
když dojde k chybě hlavního režimu (MODF=1)
Pokud přenos není kontinuální, příznak BSY se mezi každým přenosem dat vymaže

Dobře, tohle se bude hodit. Pojďme zjistit, kde se nachází Tx buffer. Chcete-li to provést, přečtěte si „Registr dat SPI“:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Bity 15:0 DR[15:0] Registr dat
Přijatá data nebo data k přenosu.
Datový registr je rozdělen na dva buffery - jeden pro zápis (vyrovnávací paměť pro přenos) a jeden pro čtení (vyrovnávací paměť pro příjem). Zápis do datového registru zapisuje do Tx bufferu a čtení z datového registru vrátí hodnotu obsaženou v Rx bufferu.

No a stavový registr, kde se nacházejí příznaky TXE a BSY:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení 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
}

Protože potřebujeme přenést 16 krát dva bajty, podle počtu výstupů ovladače LED, něco takového:

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

Ale zatím nevíme, jak vytáhnout pin LAT, takže se vrátíme k I/O.

Přiřazení pinů

V STM32F1 jsou registry zodpovědné za stav pinů poměrně neobvyklé. Je jasné, že jich je více než Atmega, ale také se liší od ostatních STM čipů. Část 9.1 Obecný popis GPIO:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Každý z obecných I/O portů (GPIO) má dva 32bitové konfigurační registry (GPIOx_CRL a GPIOx_CRH), dva 32bitové datové registry (GPIOx_IDR a GPIOx_ODR), 32bitový registr set/reset (GPIOx_BSRR), 16bitový registr reset (GPIOx_BRR) a 32-bitový registr registr blokování bitů (GPIOx_LCKR).

První dva registry jsou neobvyklé a také docela nepohodlné, protože 16 pinů portu je na nich roztroušeno ve formátu „čtyři bity na bratra“. Tito. piny nula až sedm jsou v CRL a zbytek je v CRH. Zároveň zbývající registry úspěšně obsahují bity všech pinů portu – často zůstávají napůl „rezervované“.

Pro zjednodušení začneme od konce seznamu.

Nepotřebujeme blokovací registr.

Nastavovací a resetovací registry jsou docela vtipné v tom, že se částečně duplikují: vše můžete zapisovat pouze v BSRR, kde vyšších 16 bitů vynuluje pin a nižších na 1, nebo také můžete použijte BRR, z nichž spodních 16 bitů pouze resetuje pin . Líbí se mi druhá možnost. Tyto registry jsou důležité, protože poskytují atomový přístup k pinům:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Atomic Set nebo Reset
Při programování GPIOx_ODR na bitové úrovni není potřeba deaktivovat přerušení: jeden nebo více bitů lze změnit jedinou operací atomického zápisu APB2. Toho je dosaženo zapsáním "1" do registru set/reset (GPIOx_BSRR nebo pouze pro reset GPIOx_BRR) bitu, který je třeba změnit. Ostatní bity zůstanou nezměněny.

Datové registry mají zcela srozumitelné názvy - IDR = Vstup Směrový registr, vstupní registr; ODR = Výstup Směrový registr, výstupní registr. V současném projektu je nebudeme potřebovat.

A nakonec kontrolní registry. Protože nás zajímají druhé piny SPI, konkrétně PB13, PB14 a PB15, okamžitě se podíváme na CRH:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

A vidíme, že budeme muset něco napsat v bitech od 20 do 31.

Co chceme od pinů jsme si už vymysleli výše, takže se zde obejdu bez screenshotu, jen řeknu, že MODE udává směr (vstup, pokud jsou oba bity nastaveny na 0) a rychlost pinu (potřebujeme 50MHz, tzn. oba piny na „1“) a CNF nastaví režim: běžný „push-pull“ – 00, „alternativní“ – 10. Ve výchozím nastavení, jak vidíme výše, mají všechny piny třetí bit odspodu (CNF0), nastaví je do režimu plovoucí vstup.

Jelikož plánuji s tímto čipem udělat něco jiného, ​​pro jednoduchost jsem nadefinoval všechny možné hodnoty MODE a CNF pro dolní i horní řídicí registr.

Nějak takhle

#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 jsou umístěny na portu 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 podle toho můžete psát definice pro LAT, které budou škubány registry 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 jen setrvačností, vždycky to tak bylo, nech to zůstat)

Nyní je vše skvělé, ale nefunguje to. Protože se jedná o STM32, šetří elektrickou energii, což znamená, že musíte povolit taktování požadovaných periferií.

Zapněte taktování

Hodinky, známé také jako Clock, mají na starosti taktování. A už jsme si mohli všimnout zkratky RCC. Hledáme to v dokumentaci: toto je Reset and Clock Control.

Jak bylo řečeno výše, naštěstí nejtěžší část taktovacího tématu za nás udělali lidé ze STM, za což jim moc děkujeme (ještě jednou dám odkaz na Web Di Halt, aby bylo jasné, jak je to matoucí). Potřebujeme pouze registry zodpovědné za povolení periferního taktování (Peripheral Clock Enable Registers). Nejprve najdeme základní adresu RCC, je na samém začátku „mapy paměti“:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

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

A pak buď klikněte na odkaz, kde se pokusíte něco najít v desce, nebo mnohem lépe projděte popisy aktivačních registrů ze sekcí o povolit registry. Kde najdeme RCC_APB1ENR a RCC_APB2ENR:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

A podle toho obsahují bity, které zahrnují taktování SPI2, IOPB (I/O Port B) a alternativní funkce (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 lze nalézt zde.

Pokud máte možnost a chuť testovat, pak připojte DM634 takto: DAI k PB15, DCK k PB13, LAT k PB14. Ovladač napájíme z 5 voltů, nezapomeňte připojit uzemnění.

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

STM8 PWM

PWM na STM8

Když jsem tento článek teprve plánoval, rozhodl jsem se jako příklad zkusit zvládnout nějakou funkcionalitu neznámého čipu pouze pomocí datasheetu, abych neskončil u ševce bez bot. STM8 byl pro tuto roli ideální: za prvé jsem měl pár čínských desek s STM8S103 a za druhé není příliš populární, a proto pokušení číst a najít řešení na internetu spočívá na nedostatku těchto řešení.

Čip má také datový list и referenční příručka RM0016, v prvním je pinout a registrační adresy, ve druhém - vše ostatní. STM8 je naprogramován v C v hrozném IDE ST Visual Develop.

Taktování a I/O

Standardně STM8 pracuje na frekvenci 2 MHz, to je nutné okamžitě opravit.

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
HSI (vysokorychlostní vnitřní) hodiny
Hodinový signál HSI je odvozen z interního 16 MHz RC oscilátoru s programovatelným děličem (1 až 8). Nastavuje se v registru děliče hodin (CLK_CKDIVR).
Poznámka: na začátku je jako hlavní zdroj hodinového signálu zvolen HSI RC oscilátor s děličem 8.

Adresu registru najdeme v datovém listu, popis v refman a uvidíme, že je třeba registr vymazat:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Protože se chystáme spustit PWM a připojit LED diody, podívejme se na pinout:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

Čip je malý, mnoho funkcí je zavěšeno na stejných pinech. To, co je v hranatých závorkách, je „alternativní funkčnost“, přepíná se pomocí „bytů možností“ (možnost bajtů) – něco jako pojistky Atmega. Jejich hodnoty můžete měnit programově, ale není to nutné, protože Nová funkce se aktivuje až po restartu. Jednodušší je použít ST Visual Programmer (stažený pomocí Visual Develop), který může tyto bajty změnit. Pinout ukazuje, že piny CH1 a CH2 prvního časovače jsou skryté v hranatých závorkách; v STVP je nutné nastavit bity AFR1 a AFR0 a druhý přenese i výstup CH1 druhého časovače z PD4 do PC5.

Takže 6 pinů bude ovládat LED: PC6, PC7 a PC3 pro první časovač, PC5, PD3 a PA3 pro druhý.

Nastavení samotných I/O pinů na STM8 je jednodušší a logičtější než na STM32:

  • známý z datového registru Atmega DDR (Registr směrování dat): 1 = výstup;
  • první řídicí registr CR1, když je na výstupu, nastavuje režim push-pull (1) nebo otevřený odtok (0); jelikož LED připojuji k čipu katodami, nechávám zde nuly;
  • druhý řídicí registr CR2, když je na výstupu, nastavuje takt: 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

Nastavení PWM

Nejprve si definujme pojmy:

  • Frekvence PWM – frekvence, s jakou tiká časovač;
  • Automatické opětovné načtení, AR – automaticky načítatelná hodnota, do které bude časovač počítat (perioda pulsu);
  • Aktualizovat událost, UEV – událost, která nastane, když časovač napočítá do AR;
  • Pracovní cyklus PWM – pracovní cyklus PWM, často nazývaný „pracovní faktor“;
  • Zachycení/porovnání hodnoty – hodnota pro zachycení/porovnání, do které časovač počítal něco udělá (v případě PWM invertuje výstupní signál);
  • Hodnota předpětí – přednastavená hodnota. Porovnejte hodnotu nelze změnit, dokud časovač tiká, jinak se cyklus PWM přeruší. Proto jsou nové přenášené hodnoty umístěny do vyrovnávací paměti a vytaženy, když časovač dosáhne konce svého odpočítávání a je resetován;
  • Zarovnáno na okraj и Režimy zarovnané na střed – zarovnání podél okraje a na střed, stejné jako u Atmelu Rychlé PWM и Fázově správná PWM.
  • OCiREF, výstupní porovnávací referenční signál – referenční výstupní signál, ve skutečnosti to, co se objeví na odpovídajícím pinu v režimu PWM.

Jak je již zřejmé z pinoutu, dva časovače mají schopnosti PWM – první a druhý. Oba jsou 16bitové, první má spoustu dalších funkcí (zejména umí počítat jak nahoru, tak dolů). Potřebujeme, aby obojí fungovalo stejně, a tak jsem se rozhodl začít tím evidentně chudším druhým, abych náhodou nepoužil něco, co tam není. Určitým problémem je, že popis funkce PWM všech časovačů v referenční příručce je v kapitole o prvním časovači (17.5.7 Režim PWM), takže musíte v dokumentu neustále přeskakovat tam a zpět.

PWM na STM8 má důležitou výhodu oproti PWM na Atmega:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Boundary Aligned PWM
Konfigurace účtu zdola nahoru
Počítání zdola nahoru je aktivní, pokud je vymazán bit DIR v registru TIM_CR1
příklad
V příkladu je použit první režim PWM. Referenční signál PWM OCiREF je udržován na vysoké úrovni, dokud TIM1_CNT < TIM1_CCRi. Jinak to má nízkou úroveň. Pokud je srovnávací hodnota v registru TIM1_CCRi větší než hodnota autoload (registr TIM1_ARR), signál OCiREF je udržován na 1. Pokud je srovnávací hodnota 0, je OCiREF udržován na nule....

Časovač STM8 během aktualizovat událost nejprve kontroluje porovnat hodnotua teprve poté vytváří referenční signál. Časovač Atmega se nejprve zvrtne a poté porovná, což má za následek compare value == 0 výstupem je jehla, se kterou je třeba se nějak vypořádat (např. programovým převrácením logiky).

Co tedy chceme udělat: 8bitové PWM (AR == 255), počítání zdola nahoru, zarovnání podél hranice. Vzhledem k tomu, že žárovky jsou připojeny k čipu katodami, PWM by měl vydávat 0 (LED svítí), dokud porovnat hodnotu a 1 po.

O některých jsme již četli Režim PWM, takže požadovaný registr druhého časovače najdeme vyhledáním této fráze v referenční příručce (18.6.8 - TIMx_CCMR1):

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
110: První režim PWM – při počítání zdola nahoru je aktivní první kanál, zatímco TIMx_CNT < TIMx_CCR1. Jinak je první kanál neaktivní. [dále v dokumentu je chybné copy-paste z časovače 1] 111: Druhý režim PWM – při počítání odspodu nahoru je první kanál neaktivní, zatímco TIMx_CNT < TIMx_CCR1. Jinak je aktivní první kanál.

Vzhledem k tomu, že LED jsou k MK připojeny katodami, vyhovuje nám druhý režim (i ten první, ale to ještě nevíme).

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Bit 3 OC1PE: Povolí předpětí kolíku 1
0: Preload registru na TIMx_CCR1 je zakázán. Do TIMx_CCR1 můžete napsat kdykoli. Nová hodnota funguje okamžitě.
1: Preload registru na TIMx_CCR1 je povolen. Operace čtení/zápisu přistupují k registru předběžného načtení. Předem načtená hodnota TIMx_CCR1 je načtena do stínového registru během každé události aktualizace.
*Poznámka: Aby režim PWM fungoval správně, musí být povoleny registry preload. To není nutné v režimu jednoho signálu (bit OPM se nastavuje v registru TIMx_CR1).

Dobře, pojďme zapnout vše, co potřebujeme pro tři kanály druhého časovače:

#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 skládá ze dvou osmibitových registrů, vše 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čítat pouze zdola nahoru, zarovnání podél hranice, není třeba nic měnit. Dělič kmitočtu nastavíme např. na 256. U druhého časovače se dělič nastavuje v registru TIM2_PSCR a je mocninou dvou:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Nezbývá než zapnout závěry a samotný druhý časovač. První problém řeší registry Zachytit/Porovnat umožnit: jsou na nich asymetricky rozmístěny dva, tři kanály. Zde se také můžeme dozvědět, že je možné změnit polaritu signálu, tzn. v zásadě bylo možné použít 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 nakonec spustíme časovač v registru TIMx_CR1:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Pojďme napsat jednoduchou analogii AnalogWrite(), která přenese skutečné hodnoty do časovače pro porovnání. Registry jsou pojmenovány předvídatelně Zachytit/porovnat registry, existují dva z nich pro každý kanál: 8 bitů nižšího řádu v TIM2_CCRxL a vyšší v TIM2_CCRxH. Protože jsme vytvořili 8bitové PWM, stačí zapsat pouze nejméně 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ý čtenář si všimne, že máme mírně vadnou PWM, neschopnou produkovat 100% plnění (při maximální hodnotě 255 je signál invertován na jeden cyklus časovače). U LED to nevadí a pozorný čtenář už tuší, jak to opravit.

PWM na druhém časovači funguje, přejděme k prvnímu.

První časovač má přesně stejné bity ve stejných registrech (jen ty bity, které zůstaly „rezervované“ ve druhém časovači, se v prvním aktivně používají pro nejrůznější pokročilé věci). Stačí tedy v datasheetu najít adresy stejných registrů a zkopírovat kód. Změňte hodnotu frekvenčního děliče, protože... první časovač chce přijímat nikoli mocninu dvou, ale přesnou 16bitovou hodnotu ve dvou registrech Předdělička vysoká и Nízké. Děláme všechno a... první časovač nefunguje. Co se děje?

Problém lze vyřešit pouze prohlédnutím celé sekce o řídicích registrech časovače 1, kde hledáme ten, který druhý časovač nemá. tam bude 17.7.30 Registrace přerušení (TIM1_BKR), kde je tento bit:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Povolit hlavní výstup

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

To je nyní jisté, kód na stejném místě.

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

Multiplex STM8

Multiplexování na STM8

Třetím miniprojektem je připojení osmi RGB LED k druhému časovači v režimu PWM a jejich zobrazení v různých barvách. Vychází z konceptu LED multiplexování, který spočívá v tom, že pokud LED zapínáte a vypínáte velmi, velmi rychle, bude se nám zdát, že neustále svítí (vytrvalost vidění, setrvačnost zrakového vnímání). Jednou jsem to udělal něco takového na Arduinu.

Algoritmus práce vypadá takto:

  • připojena anoda první RGB LED;
  • zapálil jej a vyslal potřebné signály ke katodám;
  • čekal až do konce cyklu PWM;
  • připojena anoda druhé RGB LED;
  • zapálil to...

No atd. Pro krásný provoz je samozřejmě nutné, aby byla současně připojena anoda a „zapálena“ LED. No, nebo skoro. V každém případě musíme napsat kód, který bude vydávat hodnoty ve třech kanálech druhého časovače, měnit je při dosažení UEV a současně měnit aktuálně aktivní RGB LED.

Protože přepínání LED je automatické, musíme vytvořit „videopaměť“, ze které bude obsluha přerušení přijímat data. Toto je jednoduché pole:

uint8_t colors[8][3];

Aby bylo možné změnit barvu konkrétní LED, bude stačit zapsat požadované hodnoty do tohoto pole. A proměnná bude zodpovědná za číslo aktivní LED

uint8_t cnt;

Demux

Pro správné multiplexování potřebujeme, kupodivu, demultiplexer CD74HC238. Demultiplexer - čip, který implementuje operátor do hardwaru <<. Přes tři vstupní piny (bity 0, 1 a 2) mu přivedeme tříbitové číslo X a jako odpověď aktivuje výstupní číslo (1<<X). Zbývající vstupy čipu slouží k škálování celého návrhu. Tento čip potřebujeme nejen kvůli snížení počtu obsazených pinů mikrokontroléru, ale také kvůli bezpečnosti – abychom omylem nerozsvítili více LED, než je možné a nespálili MK. Čip stojí penny a měl by být vždy uložen ve vaší domácí lékárničce.

Náš CD74HC238 bude zodpovědný za napájení anody požadované LED. V plnohodnotném multiplexu by napájel sloupek přes P-MOSFET, ale v tomto demu je to možné přímo, protože odebírá 20 mA, podle absolutní maximální hodnocení v datovém listu. Z Datasheet CD74HC238 potřebujeme pinouty a tento cheat sheet:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
H = úroveň vysokého napětí, L = úroveň nízkého napětí, X – to je jedno

E2 a E1 připojíme k zemi, E3, A0, A1 a A3 k pinům PD5, PC3, PC4 a PC5 STM8. Protože výše uvedená tabulka obsahuje nízké i vysoké úrovně, nakonfigurujeme tyto kolíky jako kolíky push-pull.

PWM

PWM na druhém časovači je nakonfigurován stejným způsobem jako v předchozím příběhu, se dvěma rozdíly:

Nejprve musíme zapnout přerušení Aktualizovat událost (UEV), která zavolá funkci, která přepíná aktivní LED. To se provádí změnou bitu Povolit přerušení aktualizace v rejstříku s vypovídajícím jménem

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
Registr povolení přerušení

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Druhý rozdíl souvisí s fenoménem multiplexování, jako je kupř ghosting – parazitní svit diod. V našem případě se to může objevit kvůli skutečnosti, že časovač, který způsobil přerušení na UEV, stále tiká a obsluha přerušení nemá čas přepnout LED, než časovač začne něco zapisovat na piny. Abyste tomu zabránili, budete muset převrátit logiku (0 = maximální jas, 255 = nic nesvítí) a vyhnout se extrémním hodnotám pracovního cyklu. Tito. zajistěte, aby po UEV LED zcela zhasly na jeden cyklus PWM.

Změna polarity:

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

Vyhněte se nastavení r, gab na 255 a nezapomeňte je při použití převrátit.

Přerušuje

Podstatou přerušení je, že za určitých okolností čip přestane vykonávat hlavní program a zavolá nějakou externí funkci. K přerušením dochází vlivem vnějších nebo vnitřních vlivů, včetně časovače.

Když jsme poprvé vytvořili projekt v ST Visual Develop, kromě main.c dostali jsme okno se záhadným souborem stm8_interrupt_vector.c, automaticky zařazený do projektu. V tomto souboru je každému přerušení přiřazena funkce NonHandledInterrupt. Potřebujeme svázat naši funkci s požadovaným přerušením.

Datový list obsahuje tabulku vektorů přerušení, kde najdeme ty, které potřebujeme:

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8
13 Aktualizace/přetečení TIM2
14 TIM2 zachytit/porovnat

Potřebujeme vyměnit LED na UEV, takže potřebujeme přerušení #13.

V souladu s tím zaprvé ve spisu stm8_interrupt_vector.c změňte výchozí název funkce zodpovědné za přerušení č. 13 (IRQ13) na svůj vlastní:

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

Za druhé, budeme muset vytvořit soubor main.h s následujícím obsahem:

#ifndef __MAIN_H
#define __MAIN_H

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

A nakonec zapište tuto funkci do svého 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;
}

Zbývá pouze povolit přerušení. To se provádí pomocí příkazu assembler rim - budete to muset hledat v Programovací manuál:

//enable interrupts
_asm("rim");

Dalším příkazem assembleru je sim – vypne přerušení. Během zápisu nových hodnot do „videopaměti“ musí být vypnuty, aby přerušení způsobené v nesprávnou chvíli nezkazilo pole.

Celý kód - na GitHubu.

Přečtěte si datové listy 2: SPI na STM32; PWM, časovače a přerušení na STM8

Pokud alespoň někdo považuje tento článek za užitečný, pak jsem ho nenapsal zbytečně. Budu rád za komentáře a připomínky, pokusím se na vše odpovědět.

Zdroj: www.habr.com

Přidat komentář