Reklama

Začínáme s mikrokontroléry ATxmega – USART 2. díl (využití DMA)

Úvod

V tomto díle seriálu o použití jednotky USART si předvedeme, jak může k odesílání posloužit DMA. A protože se použití DMA u mikrokontrolérů řady AU a E drobně liší, tak si předvedeme dva příklady.

Jen pro přehlednost seznam všech příkladů v seriálu je následující:

  • Odesílání s Printf (ATxmega E) (A) – 1. díl
  • Příjem řetězců s přerušením + printf/scanf (ATxmega E) (B) – 1. díl
  • Odesílání s DMA (ATxmega E) (C)
  • Odesílání s DMA (ATxmega AU) (D)
  • SPI režim odesílání 16bit s pollingem (ATxmega E) (E) – 3. díl
Odesílání s DMA (ATxmega E) (C)

Pro ty, kteří ještě neměli tu čest pracovat s DMA, tak bude tento příklad asi obzvlášť zajímavý. DMA je totiž mocný nástroj, který v prvé řadě může ve vhodných situacích citelně zvýšit výkon mikrokontroléru. A kromě toho může také v mnohých situacích zjednodušit program. Umí totiž bez intervence jádra (a tedy i programu) přesouvat data mezi pamětí a periferiemi (případně mezi pamětí a pamětí anebo periferií a periferií). Technicky vzato mu stačí říct odkud kam má data přesouvat, po jakých balících a kdy to má dělat. Pak už ho jen spustíte a on se o celý přenos dat postará. Nastíním jednoduchou situaci, kdy vám DMA výrazně usnadní život. Představte si, že využíváte D/A převodník na plný výkon. Tedy situaci kdy generujete dejme tomu na jednom kanále signál s rychlostí 1 Msps (tedy 1 milion vzorků za sekundu). V takovém případě musíte D/A převodníku každou µs přenést nových dvanáct bitů dat. To je i při frekvenci 32 MHz v podstatě limitní záležitost. Na provedení celé akce máte jen 32 µs tedy při 32 MHz jen 32 strojových cyklů. Pokud se vám vůbec podaří napsat program, který to bude stíhat, už mu určitě nezbude čas na cokoli dalšího. Představa, že si pomůžete využitím přerušení je také zcestná, protože vstup a výstup z rutiny přerušení spolkne několik (až devět) už tak chybějících strojových cyklů. A tohle je přesně situace, kde se DMA uplatní ze všeho nejvíce. DMA čeká, až si D/A převodník sám řekne o nová data, v nejkratší možné době mu je přenese a opět čeká. Jádro mezi tím může vykonávat nerušeně program, protože celý přenos dat z paměti do D/A převodníku probíhá na pozadí. Protože transport vyžaduje přenos dvou bytů (D/A převodník je dvanácti bitový) každou µs, blokuje DMA komunikaci s RAM pouze dva takty ze třiceti dvou, vytížení RAM je tedy jen něco přes 6 % a vytížení jádra nulové. Nebudu zastírat, že celá věc je o něco málo komplikovanější. K RAM nemůžou přistupovat zároveň DMA i jádro. Jádro má prioritu a pokud tedy vykonává nějakou hodně nevhodnou činnost, tak může přístup k RAM blokovat na dost dlouho na to, aby DMA nestihlo přenést potřebná data k D/A převodníku. Ale to jsou vyloženě výjimečné situace. Protože se ale nyní zabýváme USARTem, tak si ukážeme,jak lze DMA využít k odesílání dat.

Podobná situace jakou jsem výše nastínil s DMA převodníkem vás může čekat také i při odesílání USARTem. Situace je tím tíživější, čím vyšší datovou rychlost používáte. Nejvyšší datové rychlosti dosahuje USART v synchronním režimu, kde může chrlit data rychlostí až 16 Mb/s. Vezmeme-li v úvahu, že jedna zpráva ve formátu 8N1 zabírá deset bitů, tak musí být data přesunuta do USARTu každých 0.625 µs. Tedy na přípravu jedné zprávy by jádro mělo jen něco okolo dvaceti strojových cyklů. Zase platí, že by se při takové činnosti nemohlo věnovat čemukoli dalšímu. Při větším objemu přenášených dat, by tak došlo k zablokování programu na celou dobu odesílání. A i tak byste museli věnovat značnou péči zdrojovému kódu, aby celou akci stíhal. Protože my synchronní přenos použít nechceme (nemáme hardware, kterým by ho bylo možné do PC přijímat), ukážeme si spolupráci DMA a USART na běžném asynchronním přenosu. Přirozeně si zvolíme nějakou slušně vysokou datovou rychlost. Třeba občas používanou 921600 b/s.

Konfigurace USART je shodná jako v příkladech v minulém dílu, takže ji není třeba více komentovat. Snad jen poznamenám, že v hlavičce je zakomentovaná konfigurace pro přenosovou rychlost 2 Mb/s (hodnoty BSEL a BSCALE), můžete ji v případě zájmu také vyzkoušet. Stejně tak nebudu komentovat ani konfiguraci hodin – mikrokontrolér taktujeme na 32 MHz. Komentář si zaslouží pouze příprava DMA. Někde v paměti máme připravené pole, které budeme odesílat. Jedná se o proměnnou test_data[], kterou pomocí funkce snprintf vyplníme textovou zprávou. Největší pozornost budeme muset věnovat nastavení DMA. Mikrokontroléry řady Atxmega E mají jiné DMA než ostatní řady (A,AU,B,C) a nese označení EDMA (jako Enhanced DMA). Může pracovat ve dvou režimech tzv. “periferním” (Peripheral channel) anebo “standardním” (Standard channel). Rozdíl je v tom, že periferní režim může přenášet data pouze mezi periferií a pamětí, kdežto standardní režim mezi čímkoli. Směr přenosu si v periferním režimu uživatel nemůže specifikovat a je dána volbou “requestu” (viz dále). Ve standardním režimu můžete používat celkem dva kanály a v periferním režimu čtyři kanály. My konfigurujeme EDMA v periferním režimu. Dále je potřeba nastavit prioritu kanálů. Pokud chtějí dva kanály přistupovat k RAM zároveň, tak musí kanál s nižší prioritou počkat. Vzhledem k tomu, že používáme jen jeden kanál (CH0), tak je nám to celkem jedno a používáme “spravedlivou” prioritu “round robin” (každý jednou). Nastavení všech čtyř kanálu je nezávislé, takže všechno co v příkladu nebo zde v textu uvidíte, platí pro každý kanál individuálně. V prvé řadě EDMA musíme vysvětlit, jak probíhá spouštění (triggrování). Jsou dvě možnosti. Buď na pokyn přenést naráz celý balík paměti (tedy celé pole test_data[]), nebo na jeden pokyn přenést vždy jen krátkou dávku (jeden nebo dva byty). Druhá možnost, nazývaná “one-shot” a nastavovaná bitem SINGLE, je přesně to co potřebujeme. Dále je potřeba nastavit kdo dává DMA pokyny k přenosu (tzv. DMA request). V našem případě je to USARTD0_DRE. Jakmile je datový registr USARTu prázdný, tak dá pokyn DMA a to přenese další byte z paměti do USART. Logicky musíme DMA specifikovat, kterou oblast paměti má odesílat. Adresu mu nastavíme v registru ADDR. DMA také musíme nastavit, že má adresu v paměti postupně inkrementovat (jinak by stále přenášel první byte zprávy). Poslední podstatný parametr je počet přenášených bytů (tedy de facto délka pole test_data[]). Ten musíme DMA také sdělit. Po jeho přenesení se DMA kanál vypne, na další “requesty” nereaguje a vysílání skončí. Bylo by možné nastavit tzv. “repeat” režim, pak by DMA po skončení začalo přenášet znovu. V takovém případě by ale bylo nutné specifikovat, že se musí adresa paměti (DMA ji inkrementuje) po skončení přenosu znovu načíst (na původní hodnotu – první prvek pole test_data[]). My to v příkladu nastavujeme, ale “repeat” režim nepoužíváme. Raději zopakuji, že DMA přenos je ukončen z vůle EDMA, nikoli z vůle USARTu. USART i po skončení přenosu stále vysílá DMA request, že je jeho DATA registr prázdný. DMA ale na jeho výzvy po skončení přenosu nereaguje, protože je příslušný kanál vypnutý. Dokončení celého přenosu je signalizováno stavovým bitem TRNIF. Spuštění příslušného kanálu se provádí nastavením bitu ENABLE v registru CTRLA. V našem příkladu vždy spustíme DMA, poté počkáme na dokončení přenosu (sledujeme stavový bit TRNIF). Po skončení bit vymažeme, připravíme nová data a celou akci zopakujeme. Tento způsob použití DMA není praktický, protože vůbec nevyužíváme toho, že nám DMA uvolnilo ruce k jiné činnosti. Typicky tedy DMA spustíte a budete vykonávat nějakou smysluplnější činnost než jen čekání na to až skončí. Pokud to budete potřebovat, může DMA po skončení vyvolat přerušení a vy pak nemusíte zbytečně zjišťovat, zda přenos ještě probíhá nebo už je dokončen. Následuje zdrojový kód.

 

001: // C) USART – odesílání s DMA
002:
003: #define F_CPU 32000000
004: #include <avr/io.h>
005: #include <avr/pgmspace.h> // není nutné
006: #include <util/delay.h>
007: #include <stdio.h>
008:
009: void clock_init(void);// inicializace clocku
010: void usart_init(void);// inicializace USARTu (Tx na PD7)
011: void DMA_init(void);
012:
013: #define BSEL 75// parametry baudrate (921600 b/s)
014: #define BSCALE –6
015: //#define BSEL 0 // parametry baudrate (2Mb/s)
016: //#define BSCALE 0
017: #define LEN 10// délka bloku odesílaných dat
018:
019: char test_data[LEN] = {0};// pole k odeslání
020: int16_t x;// pracovní proměnná
021:
022: int main(void){
023: clock_init();// interní 32MHz
024: usart_init();
025: DMA_init();
026:
027: while (1){
028: // povolit channel 0
029: EDMA.CH0.CTRLA |= EDMA_CH_ENABLE_bm;
030: // počkat na dokončení přenosu – lze využít i přerušení
031: while(!(EDMA.CH0.CTRLB & EDMA_CH_TRNIF_bm)){}
032: // smaž vlajku dokončení přenosu
033: EDMA.CH0.CTRLB |= EDMA_CH_TRNIF_bm;
034: // připrav nová data
035: snprintf(test_data,LEN-1,"x=%i\r\n",x);
036: x++;// posíláme něco zajímavého
037: _delay_ms(100);// počkej 100ms a pošli znovu
038: }
039: }
040:
041: void DMA_init(void){
042: // konfigurace EDMA
043: // kanály v režimu "peripheral", priorita round-robin
044: EDMA.CTRL = EDMA_CHMODE_PER0123_gc | EDMA_PRIMODE_RR0123_gc;
045: EDMA.CTRL |= EDMA_ENABLE_bm;// spustit EDMA
046: // channel 0 – Peripheral mode
047: // odesíláme 1 byte na 1 trigger
048: EDMA.CH0.CTRLA = EDMA_CH_SINGLE_bm;
049: // znovunačíst adresu paměti až po skončení celého přenosu
050: EDMA.CH0.ADDRCTRL = EDMA_CH_RELOAD_TRANSACTION_gc | EDMA_CH_DIR_INC_gc;
051: // periferie se kterou probíhá výměna dat
052: EDMA.CH0.TRIGSRC = EDMA_CH_TRIGSRC_USARTD0_DRE_gc;
053: EDMA.CH0.TRFCNTL = LEN;// kolik dat přenášíme…
054: // …a odkud (respektive kam)
055: EDMA.CH0.ADDR = (uint16_t)(test_data);
056: }
057:
058: void usart_init(void){
059: PORTD.DIR = PIN7_bm;// Tx (PD7) je výstup
060: PORTD.OUTSET = PIN7_bm;// Tx do log.1 – není nutné
061: PORTD.REMAP = PORT_USART0_bm;// Remapujeme Tx na pin PD7
062: // dolních 8 bitů 12bitové hodnoty BSEL
063: USARTD0.BAUDCTRLA = (char)BSEL;
064: // Horní 4 bity hodnoty BSEL + hodnota BSCALE
065: USARTD0.BAUDCTRLB = (BSCALE << USART_BSCALE_gp) | ((char)(BSEL>>8) & 0x0f);
066: // 1 stopbit, žádná parita, 8 datových
067: // bitů, asynchronní mód
068: USARTD0.CTRLC = USART_CHSIZE_8BIT_gc;
069: // Povolit vysílač (Tx)
070: USARTD0.CTRLB = USART_TXEN_bm;
071: }
072:
073: void clock_init(void){
074: OSC.CTRL |= OSC_RC32MEN_bm;// spustit interní 32MHz oscilátor
075: // počkat než se rozběhne
076: while (!(OSC.STATUS & OSC_RC32MRDY_bm)){};
077: CCP = CCP_IOREG_gc;// odemčít zápis do registru CLK.CTRL
078: // vybrat 32MHz jako systémový clock
079: CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
080: }
Vzorové zdrojové kódy slouží pouze k jednoduché demonstraci funkce, proto často obsahují globální proměnné, neobsahují většinou ukazatele, dále také neobsahují kontroly proměnných, definování nevyužitých pinů mikrokontroléru a podobné správné programátorské návyky. Proto je nutné tyto kódy brát s patřičnou rezervou.
 

 

Dodatek

Na Obr. 1. si můžete prohlédnout, jak probíhá přenos. Bystřejší z vás si jistě všimnou, že přenášíme zbytečně moc bytů. Zpráva obsahuje deset bitů, ale užitečných je jen osm. Správnější verze příkladu, by měla využít návratovou hodnotu funkce snprintf(). Ta by měla vracet číslo odpovídající celkovému počtu znaků v textu. To bychom mohli využít a nastavit délku přenosu EDMA na délku konkrétního textu. Nastavení provádíme v registru TRFCNTL a může nabývat hodnot 1 až 256. Pro hodnotu 256 je potřeba do registru zapsat nulu. Ti zájemci, kteří by chtěli příklad tímto způsobem modifikovat si musí ohlídat návratovou hodnotu funkce snprintf(). Ta nesmí překročit výše zmiňovaných 256 a kromě toho snprintf() může v případě nějakého problému také vracet zápornou hodnotu a tu by přirozeně nebylo vhodné nikam zapisovat. Vylepšené odesílání si můžete prohlédnout v příkladu D, kde demonstruji použití DMA na ATxmega řady AU.

 
Obr. 1: - USART s DMA (926100 b/s), celý přenos 10 bytů zabere přibližně 110 µs

Obr. 1: – USART s DMA (926100 b/s), celý přenos 10 bytů zabere přibližně 110 µs

 

Odesílání s DMA (ATxmega AU) (D)

Protože je DMA na mikrokontrolérech řady E dosti odlišné od ostatních členů rodiny ATxmega, zařadil jsem do tutoriálu tento “polopříklad”. Neukážeme si na něm vlastně nic zásadně nového. Pouze si předvedeme jak nakonfigurovat USART s DMA přenosem na mikrokontrolérech řady AU. Samotná konfigurace USARTu, I/O i hodin je shodná. Jen DMA je poněkud plnohodnotnější. Vrhněme se tedy na to. U řady E pracoval EDMA buď v režimu “periferním” nebo “standardním”. U “periferního” režimu tekly data pouze mezi periferií (která posílala “requesty”) a pamětí. Přicházeli jste tak o jistou míru volnosti. Nemohli jste libovolně specifikovat odkud, a kam data potečou. Takové možnosti měl u řady E pouze “standardní” režim. ATxmegy řady AU mají DMA, které takto svoje kanály nedělí. Dalo by se říct, že všechny kanály jsou “standardní”. Tedy specifikujete odkud, a kam data potečou libovolně a stejně tak nejsou žádné restrikce kladeny na to, kdo bude posílat “requesty” a tedy rozhodovat o tom kdy dojde k přenosu dat. No a my si takovou konfiguraci ukážeme na mikrokontroléru ATxmega128A3U. Přirozeně čím více máte k dispozici možností, tím náročnější je správné nastavení DMA. Než se na něj vrhneme tak jen pro úplnost vyjasníme, jak je to s nastavením USARTů, hodin a I/O. Je to totiž snadné. Nastavují se úplně stejně jako u řady E. V tomto příkladu použijeme USARTC0 s vývodem TX na PC3. Hodiny jako obvykle zvolíme interní a to 32 MHz. Jejich kmitočet bohužel není nejpřesnější (odchylka v jednotkách procent) a při vyšších datových rychlostech může způsobovat problémy. Tak to mějte na paměti, až se budete divit, že vám do PC jdou místo znaků nesmysly ;)

Aby byla trochu legrace, tak si pustíme UART v asynchronním režimu na nejvyšší možnou rychlost, tedy na 4 Mb/s. S dekódováním takového signálu můžou mít některé převodníky USB -> UART problémy. Stíhají ho třeba FT232H a PL2303. A nestíhají například FT230X, FT232 nebo CP2102. Taky některé terminálové programy na PC mohou mít s takovou datovou rychlostí problémy. Já mám zatím ověřenou Putty, která stíhala i 12 Mb/s. Nikdo vás však nenutí komunikovat pouze s PC. UART může klidně posloužit pro komunikaci mezi mikrokontroléry. Ještě připomenu, že v příkladu C (USART s DMA na mikrokontrolérech ATxmega E), měla naše odesílací funkce malý nedostatek (odesílala zbytečně moc znaků) – tento nedostatek odstraníme. A teď hurá na konfiguraci DMA.

Na mikrokontrolérech řady AU máte k dispozici čtyřkanálové DMA. Kanály jsou nezávislé (včetně rutin přerušení) a mají některé nadstandardní funkce oproti EDMA na mikrokontrolérech řady E. Tou funkcí je například “double buffer” DMA, kdy se dva DMA kanály střídají a každý přenáší další balík dat. Jádro pak typicky zpracovává druhou polovinu dat. Na druhou stranu EDMA měl také své bonusy (možnost filtrace dat), ale tyto debaty si necháme až na seriál o DMA. Konfigurace DMA je celkem přímočará. Je potřeba nastavit cílovou a zdrojovou adresu a počet přenášených bytů. Dále je potřeba specifikovat, zda používáme “one-shot” režim, kdy se na jeden “request” odešle pouze jedna dávka (burst). To je náš případ. Dále potřebujete specifikovat velikost dávky (1, 2, 4 nebo 8 bytů). A pak přijde to “nejtěžší”. Správně nastavit, která adresa se má inkrementovat, která ne a kdy se má znovu načíst její počáteční hodnota. My to nemáme moc těžké, protože USART potřebuje dostávat data po jednom bytu. Takže cílová adresa (USARTC0.DATA) se inkrementovat nebude a znovu načítat také ne. Zdrojová adresa se bude inkrementovat po každém odeslaném bytu (burst) a znovu se její hodnota načte po skončení celého přenosu. Velikost dávky bude jeden byte. Pak už jen nakonfigurujeme “requesty”. Ty budou přicházet od Data Register Empty. Tedy v okamžiku kdy je USART připraven přijmout další data. To je vše. Všimněte si, že délku odesílaných data v příkladu měníme, podle toho kolik jich aktuálně potřebujeme odeslat. Na Obr. 2 pak můžete vidět, že už je to docela fofr a celá zpráva se vychrlí za méně jak 20 µs.

 
Obr. 2: UART na maximální rychlosti 4 Mb/s

Obr. 2: UART na maximální rychlosti 4 Mb/s

 

 
Obr.3: Vývojová deska X3-DIL64 Leon Insturments

Obr. 3: Vývojová deska X3-DIL64 Leon Insturments

 

001: // D – USART odesílání s DMA (Xmega AU)
002: #define F_CPU 32000000
003: #include <avr/io.h>
004: #include <util/delay.h>
005: #include <stdio.h>
006:
007: void clock_init(void);
008: void usart_init(void);
009: void DMA_init(void);
010: // pozor na přesnost clocku u tak vysokých baudrate !
011: #define BSEL 0// parametry baudrate (4Mb/s) – double speed USART
012: #define BSCALE 0
013: #define LEN 20// maximální délka řetězce
014:
015: char odesli[LEN] = {0};// obsah tohoto pole budeme odesílat
016: int x = 0,delka;// pomocné proměnné
017:
018: int main(void){
019: clock_init();
020: usart_init();
021: DMA_init();
022: while (1){
023: x++;// něco zajímavého k odesílání
024: // formátujeme zprávu
025: delka=snprintf(odesli,LEN,"x=%i\n\r",x);
026: if(delka>0 && delka<LEN){// pokud formátování prošlo korektně
027: DMA.CH0.TRFCNT = delka;// nastavíme DMA délku odesílaného řetězce
028: // povolit kanál 0 – spustit přenos
029: DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;
030: }
031: // počkáme na dokončení přenosu
032: while(!(DMA.CH0.CTRLB & DMA_CH_TRNIF_bm)){}
033: // smažeme vlajku dokončení přenosu
034: DMA.CH0.CTRLB |= DMA_CH_TRNIF_bm;
035: _delay_ms(100);// chvíli počkáme a jedeme znovu
036: }
037: }
038:
039: void DMA_init(void){
040: DMA.CTRL = DMA_ENABLE_bm;// povolit DMA
041: // nastavit channel 0
042: // cílová adresa pevná bez inkrementace,
043: // zdrojovou adresu inkrementovat a znovu načíst
044: // až po skončení přenosu
045: DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_TRANSACTION_gc | DMA_CH_SRCDIR_INC_gc |
046: DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc;
047: // cílová adresa je
048: DMA.CH0.DESTADDR0 = (((uint16_t) &USARTC0.DATA) >> 0) & 0xFF;
049: // DATA registr USARTu
050: DMA.CH0.DESTADDR1 = (((uint16_t) &USARTC0.DATA) >> 8) & 0xFF;
051: DMA.CH0.DESTADDR2 = 0;
052: // zdrojová adresa je
053: DMA.CH0.SRCADDR0 = (((uint16_t) (&odesli[0])) >> 0) & 0xFF;
054: // pole v němž skladujeme text
055: DMA.CH0.SRCADDR1 = (((uint16_t) (&odesli[0])) >> 8) & 0xFF;
056: DMA.CH0.SRCADDR2 = 0;
057: DMA.CH0.TRFCNT = LEN;// bude se měnit…
058: // request pochází od USART0 Data Register Empty
059: DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_USARTC0_DRE_gc;
060: // na jeden request, pošle jeden byte
061: DMA.CH0.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm;
062: }
063:
064: void usart_init(void){
065: PORTC.DIRSET = PIN3_bm;// Tx (PC3) je výstup
066: PORTC.OUTSET = PIN3_bm;// Tx do log.1 – není nutné
067: // dolních 8 bitů 12bitové hodnoty BSEL
068: USARTC0.BAUDCTRLA = (char)BSEL;
069: // Horní 4 bity hodnoty BSEL + hodnota BSCALE
070: USARTC0.BAUDCTRLB = (BSCALE << USART_BSCALE_gp) | ((char)(BSEL>>8) & 0x0f);
071: // 1 stopbit, žádná parita, 8 datových bitů,
072: // asynchronní mód
073: USARTC0.CTRLC = USART_CHSIZE_8BIT_gc;
074: // Povolit vysílač (Tx), zapnout double speed
075: USARTC0.CTRLB = USART_TXEN_bm | USART_CLK2X_bm;
076: }
077:
078: void clock_init(void){
079: OSC.CTRL |= OSC_RC32MEN_bm;// spustit interní 32MHz oscilátor
080: // počkat než se rozběhne
081: while (!(OSC.STATUS & OSC_RC32MRDY_bm)){};
082: CCP = CCP_IOREG_gc;// odemčít zápis do registru CLK.CTRL
083: // vybrat 32MHz jako systémový clock
084: CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
085: }
Vzorové zdrojové kódy slouží pouze k jednoduché demonstraci funkce, proto často obsahují globální proměnné, neobsahují většinou ukazatele, dále také neobsahují kontroly proměnných, definování nevyužitých pinů mikrokontroléru a podobné správné programátorské návyky. Proto je nutné tyto kódy brát s patřičnou rezervou.
 

 

V následujícím díle zakončíme celý seriál příkladem použití v SPI režimu.

 
Autor: Michal Dudka
 

Jiné příspěvky v kategorii:

 
Začínáme s mikrokontroléry ATxmega – USART 1. díl (odesílání a příjem)
Začínáme s mikrokontroléry ATxmega – USART 3. díl (Práce v SPI režimu)
 
Tajned facebook
 

Za případné chyby v textu, ve zdrojovém kódě, nebo ve schématickém zapojení se omlouváme.
AUTOŘI NEBEROU ŽÁDNOU ODPOVĚDNOST ZA PŘÍPADNÉ ÚJMY NA ZDRAVÍ ČI MAJETKU.