GNU C Compiler – sada nástrojů

Volné (bezplatné) nástroje pro vývoj aplikací na moderních jednočipových mikroprocesorech.


Úvodem.

Doba, kdy stačilo napsat aplikaci v jazyce symbolických adres (assembleru), přičemž celý zdrojový text byl obvykle v jednom souboru je zřejmě nenávratně pryč. Ceny procesorů klesají spolu s tím jak roste jejich výkon a tak se objevují nové aplikace i tam, kde by se jejich nasazení dříve vůbec nečekalo. Tak roste i složitost firmware a je nutné hledat cesty, jak si usnadnit práci. Celkem se vžila praxe, kdy je firmware psán v jazyce C, pouze pro kritické části je použit assembler. Jazyk C je vlastně takový „makroassembler“, umožňující snazší portování programu na různé architektury. A navíc pokud se dodržují určitá jednoduchá pravidla, výsledek je přehlednější a tudíž se snáze udržuje.

V neposlední řadě je tu ještě jeden důvod proč přejít z 8-bitové architektury na 32-bitovou a tím je cena. Zatímco ceny 8-bit mikroprocesorů např. oblíbené řady x51 se ustálily a těžko lze očekávat, že poklesnou, ceny např. ARM v důsledku konkurenčního boje stále klesají a již dnes se jeví jako výhodnější. A to absolutně, nejen v poměru výkon/cena. Migrace si však vždy vyžádá určité náklady – je nutné používat jiné nástroje pro vývoj, naučit se používat daleko složitější jádro. Jsou v zásadě dvě cesty, jak problém vyřešit:

Praxe je taková, že opensource nástroje jsou na určité úrovni použité i v některých komerčních. Je to prostě jen správně nastaveno, tak aby se to dalo přímo použít. A právě o tom nastavení bude ještě řeč. Nebude zde popisována žádná konkrétní architektura ani příklad, předpokládá se pouze, že daný čip nemá jednotku MMU a nebude tedy pracovat na žádném operačním systému. V podstatě je možné velmi podobně vytvořit sadu nástrojů pro ARM (v různých variantách), Atmel AVR, MIPS a jiné. Základní znalosti jazyka C a jeho použití pro nějakou rodinu jednočipových mikroprocesorů se předpokládá samozřejmě. Spíš tedy čekejte řadu upozornění, na co si dát pozor, než kompletní návod jak napsat funkční program. Pro úplnost – starší postřehy pro x51 jsou ./flip.html.


1. Co budeme potřebovat a k čemu je to dobré – sada nástrojů.

Všechny popisované nástroje jsou distribuovány ve formě zdrojových textů převážně v jazyce C, je nutné je zkompilovat a nainstalovat. Na Internetu je však možné nalézt předkompilované verze pro různé architektury a operační systémy. V OS Linux by kompilace neměla dělat větší problémy, někdy působí potíže nekompatibilita některých verzí jednotlivých částí nástrojové sady. Pro snazší instalaci na OS Linux byl vytvořen příklad skriptu, který to celé zautomatizuje. Celkem nic na tom není, pro každou část sady je potřeba stáhnout zabalené zdrojáky z Internetu, rozbalit je a nainstalovat pomocí trojice configure && make && make install. Konfigurace ovšem vyžaduje několik nezbytných parametrů a ty se zde budeme snažit popsat. Nejdůležitější jsou společné -

--prefix=/cesta/k/cílovým/souborům

--target=architektura

V příkladu je použito arm-elf, tj. cílová architektura je ARM, nástroje budou vytvářet soubory ve formátu executable-linux-format (elf). Pro jádro Cortex-Mx se nověji používá arm-none-eabi - výsledek je formát embedded-application binary interface - jakýsi standard kompatibilní s jinými překladači. Používáme-li však celou tuto sadu nástrojů, je elf plně vyhovující. Kombinace možných architektur a formátů lze najít v dokumentaci, bohužel není snadné se v tom vyznat. Je potřeba vědět, že všechny vytvořené nástroje, tedy spustitelné soubory v adresáři /cesta/k/cílovým/souborům/bin mají předponu architektura-. Tedy překladač pro jazyk C gcc se v tomto příkladu nejmenuje gcc, ale arm-elf-gcc, překladač pro jazyk C++ g++ je arm-elf-g++ atd. To, že /cesta/k/cílovým/souborům/bin musí být obsaženo v systémové proměnné PATH netřeba asi připomínat. Všechny nástroje (mimo make) jsou křížové – spouští se na PC, tedy na jiné architektuře než je cílová. Ovládání z příkazové řádky (CLI) nemusí někomu vyhovovat, ale pro daný účel je vhodné.

Nástroje pro Windows by měly jít úplně stejně zkompilovat v prostředí MinGW a MSYS, ale nezkoušel jsem to, předkompilované nástroje lze najít na Internetu. To je možná lepší varianta, kompilace není nic pro začátečníka a je rovněž potřeba dobré připojení i Internetu, stahují se řádově desítky MB.


1.0 Binutils.

Dost důležitá součást. Obsahuje překladač z jazyka symbolických adres dané architektury (assembler as), spojovací program (linker ld), nástroje pro práci s knihovnami a manipulaci s výsledným binárním kódem.


1.1 Překladač z jazyka C.

GCC čili GNU Compiler Collection je mocný nástroj. Podporuje celou řadu různých architektur, včetně x86, ARM, MIPS či oblíbené Atmel AVR. Navíc může překládat i z jazyků C++, Objective-C, Objective-C++, Java, Fortran a Ada. Vnitřně to funguje (zhruba) tak, že se zdrojový text v některém z těchto jazyků přeloží se do jazyka symbolických adres dané architektury, ten se pomocí assembleru (as z binutils) převede na spustitelný kód – vzniká tak objekt (soubor s příponou .obj nebo .o). Nakonec se spustí linker (ld z binutils) a ten z objektů vytvoří výsledný elf. Spouštění as a ld většinou není zvnějšku vidět, gcc si toto řídí sám. Takže např. jednoduchý příkaz:

gcc main.c

přeloží soubor main.c a vytvoří soubor a.out (defaultní jméno), který je již ve formátu elf.

GCC se při instalaci překládá dvakrát. Poprvé je vytvořen jen jakýsi polotovar, použitý pro překlad knihoven, finální verze pak již musí správně spolupracovat s danou knihovnou (parametr --with-newlib). Parametr --disable-shared zakazuje vytvářet sdílené knihovny (obdoba dll ve windows), protože ty nejsou u jednočipového procesoru potřeba, --with-float=soft říká, že čísla v plovoucí řádové čárce budou zpracována normální celočíselnou aritmetickou jednotkou, architektura tedy neobsahuje FPU. Za zmínku stojí ještě parametr --enable-interwork, specifický pro ARM – povolí spolupráci s instrukční sadou THUMB.


1.2 Knihovny.

Zde je použita jako standardní C knihovna newlib. Je dost ořezaná, většinou se stejně moc nepoužívá, protože např. použijeme-li funkci printf, stejně je nutné jí nějak říct, kam má směrovat výstup (a mimo to i tak zabírá dost místa). Ale matematické funkce, práce s řetězci, metody malloc(), free() a podobně použít lze. Stále však musíme mít na paměti, že především paměti máme poměrně málo, proto je nutné postupovat opatrně. Většina příkladů z Internetu knihovny používá velmi opatrně, potřebné metody jsou v nějaké zjednodušené formě součástí těchto příkladů. Pro úplnost – standardně se používá knihovna glibc, v případě embedded zařízení uClibc (existují ale i jiné). Tyto knihovny poskytují interface mezi uživatelským programem a jádrem operačního systému (Linux), tady se jimi zabývat nebudeme.


1.3 Linker skript, startovací kód a HAL.

Popsaná sada nástrojů je určena především pro spolupráci s operačním systémem. Jenže v jednočipu běžně žádný k dispozici není a je třeba nastavit několik důležitých parametrů, které jsou jinak právě plně v režii jádra operačního systému.

Při složitosti moderních mikrokontrolérů s mnoha vestavěnými periferiemi by to znamenalo správně nastavit hodnoty v několika desítkách registrů. Tuhle nesnadnou práci je možné si hodně zjednodušit, pokud najdeme na WEBu výrobce základní knihovnu pro spolupráci s hardware – HAL (hardware abstract layer). Bývá obvykle společná pro určitou produktovou řadu čipů, dostupné jsou většinou zdrojové kódy v jazyce C, někdy bývá startovací kód přímo v jazyce symbolických adres. Je to taková hrubá, jednoduchá kostra nahrazující (velice zhruba) vstupně/výstupní funkce operačního systému. Navíc každý výrobce k tomu přistupuje poněkud jinak, snad se časem dočkáme nějakého standardu třeba v podobě jednoduchého operačního systému. Pro ARM Cortex-Mx je určitým standardem CMSIS (Cortex Microcontroller Software Interface Standard), leč moc použitelně to zatím nevypadá. Na webu lze najít i různé RTOS (např. freertos), jednoduché operační systémy pro práci v reálném čase, umožňující do jisté míry i multitasking. Možností jak si usnadnit práci je tedy celkem dostatek.

Nicméně kód HAL výrobce bývá poměrně dobře dokumentován, takže se v tom dá docela dobře vyznat. Pro každou periferii je vytvořeno několik funkcí – zpravidla inicializace, nastavení parametrů, zápis a čtení dat – bývá to v jednom souboru *.c, definice *.h. Tyto funkce je možné použít ve vlastním programu (include *.h). Problém nastane jen pokud periferie používá přerušení – jeho obsluhu musí uživatel zvládnout sám a k tomu je potřeba vědět, jak to funguje. Takže ani tady se bez podrobného datasheetu neobejdeme.

Startovací kód má za úkol především přivést správnou taktovací frekvenci do jádra, provést základní nastavení a zavolat uživatelem vytvořenou funkci main().

Linker skript je pak předpis pro spojovací program kam umístit kód, data, zásobník, vektory přerušení a hromadu (heap) v níž je možné alokovat paměť pomocí metody malloc(). Je to jeden nebo několik souborů s koncovkou .ld nebo .lds, kde definice sekcí je společná pro danou produktovou řadu, mapa paměti je pak trochu odlišná pro každý typ mikroprocesoru. Pro představu příklad:


Obsah souboru „script.ld“ :


OUTPUT_FORMAT (binary) /* možnosti zjistíme příkazem "objdump -i" (lze i ihex) */

ENTRY (entry) /* odtud se začne (např. start po resetu) */

/* popis pamětí celkem komentář nepotřebuje */

MEMORY {

rom (RX) : ORIGIN = 0x0, LENGTH = 0x1000 /* délky jsou příklad */

ram (RW) : ORIGIN = 0x2000, LENGTH = 0x1000

}

/* popis sekcí */

SECTIONS {

.fixed : { /* výstupní sekce v rom - nazveme např. .fixed */

entry = .; /* symbol začátku programu viz "start.asm", zde 0 (začátek ROM) */

*(.startsec) /* .startsec je startovací sekce viz "start.asm"

syntaxe je filename( section ), * znamená cokoli */

. = ALIGN (4); /* zarovnání příští sekce na 4 byty (celkem zbytečné) */

*(.text*) /* gcc pojmenovává sekce s kódem jako .text, pokud je použito

-ffunction-sections,pak bude každá funkce v jiné

sekci s názvy .text.jmeno_funkce, proto ta * na konci */

*(.rodata*) /* .rodata* - stejně jako .text*, ale pro const proměnné (data)

(předpokládá použití -fdata-sections) */

} > rom /* tady je řečeno, že to má být v rom */

.relocate : { /* výstupní sekce v ram - nazveme např. .relocate */

*(.data*) /* .data* - stejně jako .text*, ale pro proměnné (data, nenulová) */

*(.bss*) /* .bss* - stejně jako .text*, ale pro proměnné (data nulová) */

relocate_end = .; /* konec dat v sekci .relocate - podle toho se

např. nějak určí hodnota SP, heap atd. */

} > ram /* tady je řečeno, že to má být v ram */

}


Symboly entry a relocate_end jsou definovány právě v linker skriptu, lze je však použít ve zdrojových kódech. Obsah souboru „start.asm“ je pak třeba (velmi zjednodušeně):


   GLOBAL     entry

   EXTERN     main, relocate_end


   SECTION   .startsec        ; pojmenování stejné jako první sekce ve script.ld !

entry:                        ; vstupní bod je definován opět ve script.ld

        mov    sp, #relocate_end     ; nastavení stack pointeru za konec datové části

        …                            ; další kód – nastavení jádra procesoru

        call   main                  ; volání hlavní metody (ta může být kdekoli v paměti)

                                     ; pokud není zajištěno, že se to z main nevrátí

loop:   jmp    loop                  ; nekonečná smyčka -> zastavení


To jen tak pro představu, jak to funguje. Je vidět, že některé symboly, které jsou použity jako „extern“ ve zdrojových souborech mohou být definovány právě v linker-scriptu.


1.4 Makefile.

V další části budou popsány nástroje, které sice nejsou nezbytné ale právě make je dost dobré používat. V Linuxu bývá již nainstalován, ve Windows lze použít mingw32-make nebo je podobný nástroj již součástí vývojového prostředí. Program make pomocí předpisu v souboru Makefile (nebo makefile - defaultní názvy) řídí překlad – tedy nejenže spouští překladač s potřebnými parametry ale zároveň určuje, kdy se má překlad daného souboru spustit, protože překládat soubor, který se nezměnil není nutné. Podrobný popis činnosti zde nebude uveden, lze jej nalézt na webu, poměrně slušné jsou i některé popisy v češtině. Je dobré se naučit psát ručně tyto makefile, některá vývojová prostředí je generují automaticky, ale pokud vznikne problém, špatně se dohledává. Bude lépe se věnovat popisu některých parametrů překladu, které se v makefile objevují.

-Os optimalizace běhu programu (s jako size, tedy na velikost). To bývá zdrojem mnoha neočekávaných problémů. Je dobré si uvědomit, že některé sekvence příkazů, pokud není použito ve zdrojovém textu klíčové slovo volatile, může překladač ignorovat, protože je považuje za zbytečné. To je právě situace, která právě u jednočipových mikrokontrolérů zhusta nastává. Tato chyba se pak velmi špatně hledá.

-ggdb přidá do výstupu ladící informace pro GNU debuger gdb. Takže výsledný soubor bude větší, ale to v zásadě nevadí, do flash procesoru se stejně tyto informace nenahrávají. Pokud budeme muset ladit, je tato volba nutná. Zde je na místě poznamenat, že při ladění pomocí gdb je vhodné vypnout optimalizaci (-O0). Pokud je tato zapnutá, může se např. při krokování programu po řádcích jazyka C stát, že se bude zdát jakoby se některé instrukce neprovedly, případně se mohou zdánlivě provést vícekrát. Je to ale pravdu jen fikce, stačí se pak podívat do listingu a ihned je zřejmé, že tento zmatek pochází jen z toho, jak gcc kód zoptimalizoval.

-ffunction-section -fdata-section umístí jednotlivé funkce případně proměnné do samostatných pojmenovaných sekcí. To souvisí s parametrem linkeru (resp. gcc při linkování) -Wl,--gc-section, který uklidí nepotřebné sekce. Tyto parametry se používají právě v úlohách, kdy máme omezené prostředky (především paměť).

-Wa,-adhlns=soubor.lst říká assembleru, že má vytvářet listing s názvem soubor.lst (v makefile je tento název tvořen zpravidla nějakým makrem). Přepínače -adhlns určují, co bude do listingu zahrnuto (zde vše). To je dobrá volba pro ty, co chtějí vědět, jak přesně věci fungují.

-nostartfiles -nodefaultlibs -nostdlib parametry linkeru, jež mu říkají aby nepoužíval standardní postupy určené pro operační systém. Pro jednočipy je to dobrá volba.

-Wl,-Map=soubor.map,--cref říká linkeru, aby vytvořil mapu paměti s křížovými referencemi. To je dobré při ladění, lze z toho vyčíst, kde je přesně která metoda nebo proměnná umístěna v paměti.

-T"soubor.lds" informuje linker, že má použít skript soubor.lds (viz výše).


Parametry překladu jako je -mthumb, -mcpu=cortex-m3 jsou závislé na konkrétní architektuře, -I/adresář (použití hlavičkových souborů z adresáře), -L/adresář (použití knihoven z adresáře), -lknihovna (přilinkování knihovny) asi není třeba komentovat.

Konečná úprava spočívá v tom, že se výsledný soubor ve formátu elf upraví programem objcopy do binárního, případně intel-hex formátu (parametr -O binary nebo ihex), který je už přímo určen pro nahrání do flash mikroprocesoru. Při tom se zároveň oříznou ladící informace (parametr –strip-unneeded). Je však možné zvolit výstupní formát přímo v linker skriptu (jako v příkladu výše). Nicméně pokud chceme ladit, GDB formát elf vyžaduje, takže ho musíme vytvořit.


1.5 Vývojové prostředí.

Je předmětem ostrých diskuzí, každý na to má jiný názor, takže jen stručně. Pokud zvládneme předchozí nástroje, pak je možné vzít jednoduchý textový editor jako je notepad a dát se do práce. Ovšem integrované vývojové prostředí je samosebou velkou výhodou. Přináší do práce určitý komfort a zvyšuje tak její efektivitu. Dnes se jako určitý standard začíná prosazovat Eclipse. Je to ale poměrně veliký moloch a ještě k tomu v javě - něco jako dělo na komára. Má však množství pluginů, které do značné míry automatizují to, co bylo řečeno v předchozím textu.

V zásadě je však možné použít jakékoli IDE pro C, C++. Výhodou je pokud prostředí podporuje debugger gdb, pak bude možné ladit přímo v IDE a není nutné se učit tu spoustu příkazů, které gdb podporuje. Pro gdb existuje i samostatné opensource GUI – Insight.


1.6 JTAG server.

Konečně se dostáváme k tomu, jak hotový program dostat do flash paměti mikroprocesoru. Postupně se začala objevovat rozhraní ISP (in system programming), různé bootloadery - programy uložené v ROM procesoru, až se ustálilo univerzální ladící rozhraní JTAG. I když nyní je i toto nahrazováno jednodušším SWD, ale to je spíš budoucnost a principiálně se od JTAG zase tak moc neliší. Bootloader je používán i dnes, pro čip disponující USB je to dobrá volba, i když jen pro nahrání firmware do čipu. Pro tento způsob buď výrobce dodává speciální software nebo se čip chová jako mass-storage a firmware se prostě zkopíruje pod systémem. Bootloader může fungovat i po standardním sériovém portu, ale je nutný převodník úrovní.

JTAG je vhodnější, pokud chceme program i ladit. Vlastní JTAG rozhraní používá 4 vývody mikroprocesoru (a případně ještě reset), ty pak již nelze použít jako vstupně/výstupní porty. Pro spojení s PC je nutné použít speciální hardware. Nemusí to být nic složitého, stačí adaptér na paralelní port s jedním 74HC125, příp. HC245, funguje i obvod FT2232 přes USB. Lze vyrobit svépomocí nebo koupit hotové. Software ale není úplně triviální. Opět – v komerčním řešení bude již nakonfigurovaný JTAG server, pokud použijeme open source software, je nutné ho nainstalovat a nakonfigurovat.

OpenOCD je použitelné řešení i když v současné verzi 0.4 nepodporuje SWD, ve verzi 0.5 by měla být podpora již zabudována. Při instalaci postupujeme podle návodu (soubor INSTALL), jednotlivé verze se dost liší. OpenOCD běží jako server, potřebuje konfigurační soubor, specifický pro daný adaptér a laděný čip. Tento čip musí být fyzicky připojen a funkční. Příklady jsou pro většinu architektur v adresáři tcl. Po přečtení manuálu (je k dispozici i v pdf) lze server zprovoznit i když postup se opravdu nedá označit za jednoduchý. Server je dostupný pomocí gdb (viz dále) i přes telnet, sada příkazů je poměrně bohatá – lze zapisovat do a číst z registrů, mazat, zamykat, odemykat a programovat flash a mnoho jiného.


1.7 GDB – GNU debugger.

Je nutné přeložit pro cílovou architekturu jako ostatní nástroje, i když běží většinou na PC. Ladící nástroj GDB lze v tomto případě použít jako klienta OpenOCD serveru. Výhoda je, že ladíme přímo na cílovém hardware takže jsou k dispozici i příslušné periferie. Vidíme, co se tam opravdu děje a to je výhoda oproti simulátoru. I když pro některé architektury je v gdb přítomen i ten simulátor. Gdb toho umí opravdu hodně, program lze krokovat, nastavovat breakpointy, vyčítat hodnoty proměnných, trasování atd. Oceníme to hlavně, pokud máme podporu gdb v IDE.


Závěr.

Celý postup jsem vyzkoušel na vývojovém kitu AT91SAM7S256-KIT firmy Kramara ve spolupráci s JTAG adaptérem od stejné firmy pod OS Linux (Ubuntu). Kramara dodává k tomuto kitu software pro OS Windows spolu s návodem, jak ho zprovoznit. Z toho lze vycházet při nastavení OpenOCD. HAL jsem použil přímo ze stránek fy Atmel (softpack-1.15). Je to docela dobře napsané i když trochu moc rozsekané, takže se v tom člověk může docela zamotat. Nicméně i bez předchozí zkušenosti s ARM architekturou to bylo jen několik dnů práce a první jednoduchý program byl funkční. A to šlo zřejmě ještě hodně zjednodušit, pokud bych použil Eclipse. Jenže jsem zvyklý na kdevelop a tak jsem musel vše konfigurovat ručně. Eclipse jsem kdysi zkoušel a moc mě nezaujalo. Nejvíc času zabralo vyzkoumat, jaké verze nástrojů spolu budou bez problémů kooperovat (ne každá verze jde přeložit a žádná vlastně není bez chyb) a pochopit, jak vlastně funguje to OpenOCD. Proti architektuře x51, kterou jsem používal léta je to významný posuv vpřed. Je to úplně jiný způsob práce a tomu je nutné přizpůsobit i styl kódování. Ladění v podstatě probíhá stejně jako ladění pod OS, s JTAG od Kramara lze snadno použít i ladící výpisy přes sériovou konzoli (DBGU na čipu). Výkon a prostředky čipu jsou také úplně na jiné úrovni přičemž cena je srovnatelná. V plánu je vyzkoušet LPC1343 od NXP. Má novější jádro Cortex-M3, je tedy rychlejší, celkem dost periferií včetně USB device a lepší cenu. Zatím je problém se SWD ale zřejmě než to budu potřebovat, OpenOCD už to bude umět.


Další zkušenosti.

Listopad 2011. Konečně jsem se dostal k tomu přilepit LPC1343 na destičku a vyzkoušet. Domácí výroba plošného spoje pro rozteč 0,5 mm je trochu náročná, ale vlastní připájení čipu bylo nakonec jednodušší, než jsem očekával. SWD jsem zatím vzdal, celkem není potřeba. Základ je ze serveru microbuilder.eu – reference design, upload firmware probíhá přes USB – čip se chová při bootu jako standardní mass storage s jediným souborem firmware.bin. V Linuxu jsou s tím drobné potíže, napsal jsem si na to jednoduchý vlastní prográmek, který je řeší. NXP totiž emuluje FAT dost zjednodušeně a tak se s tím spokojí pouze Windows, Linux musí původní firmware přepsat definovaným způsobem aby to bylo alespoň trochu korektní. Bootloader kromě toho kontroluje součet prvních osmi vektorů (musí být nula), což gcc nedokáže zajistit, takže je nutné provést to externě. Nicméně gcc toolchain chodí, lze použít arm-elf-gcc původně používaný pro ARM7TDMI bez problémů. Firmware z microbuilderu funguje celkem slušně, je to celkem dobrý základ. Dneska už to prostě psát od podlahy asi moc nejde. A také proč. Rozblikání ledky zabralo zhruba 2 hodiny práce.

Duben 2012. Tak mě přinutili napsat cosi do Atmel AVR, asi protože ARM má moc nožiček a obyčejná x51 se už holt nenosí. Fakt je, že popsaný toolchain, který jsem také kompiloval ze zdrojáků funguje bez problémů i pro tuto rodinu procesorů. Pro tuto rodinu je GCC připraveno o něco lépe, není třeba celkem se starat o linker scripty (i když je třeba např. kontrolovat délku kódu aby nepřesáhla velikost flash), defaulty jsou celkem použitelné, balík obsahuje i startovací kódy pro jednotlivé procesory, kde je vyřešeno naplnění vektorů, inicializace stack pointeru a globálních proměnných. Takže práci to rozhodně zjednoduší. Bohužel registry a funkci periférií jsem se musel naučit, ale ani to není zase tak velké drama, jsou k dispozici příklady a mnoho je toho na webu.

Nezkoušel jsem gdb a openocd i když pro některé typy Atmega by to fungovat mělo. Já jsem měl k dispozici jen osminohý Attiny a jednoduchý JTAG na paralelní port (Xilinx kompatibilní), který je podporován programem avrdude. Trochu plavu v těch divných bitech fuses, ale i tak blikání ledkou chodilo na první pokus.

Tedy pro začátečníky nic moc, ty periférie (třeba časovače) jsou už docela složité, ale asi když si opatří nějakou vhodnou českou knížku, proč ne. Ono je to děláno docela vtipně, takže i ta složitá periferie se dá obsluhovat celkem jednoduše, pokud si nevymýšlíme kraviny. Co se mi líbí je, že i ty malé Attiny jsou docela vybavené – A/D převodník, interní oscilátor, EPROM, PWM – to všechno se může hodit. Ovšem co se ceny týká, v poslední době se zdá, že Cortex-M0 to vše převálcuje (LPC1111 od NXP pod 1$ je už něco, s čím se tyhle tintítka nemůžou dost dobře srovnávat. A dokonce se to dá sehnat i v kusovce – u Farnella za 35 Kč.). Jenže tohle domácí bastlíř těžko zapájí. Uvidíme, kam se vývoj vrtne.

Duben 2013. Tak jsme se za rok zase posunuli o něco dál. Když už všichni začali používat ty Discovery kity od ST, tak jsem vyžebral na prodejci od Arrow STM32F4 a STM32F0. Ten Cortex-M3 jsem vynechal, není pro něj použití. Popravdě ono není použití ani pro Cortex-M4F, ale bylo to zadarmo a možnosti tohoto čipu jsou obrovské. A protože doba pokročila, OpenOCD podporuje už nejen SWD jako takové, ale dokonce i ST-Link adaptér na Discovery kitech umístěný. Takže zase o problém míň. Jen je nutné použít gcc min. 4.7.2. Je docela škoda, že ST používá ve svých příkladech různé divné nástroje, takže pro použití gnu toolchainu je potřeba napsat si vlastní makefile, ale dá se to a příklady fungují. Tedy pokud se týká STM32F4. Architektura Cortex-M0 a gnu gcc-4.7.2 má trochu problémy.

  1. Pokud používáme celočíselné dělení, gcc pro něj vygenerovalo ARM kód, který samosebou na této architektuře nepoběží (umí jen thumb). Existuje na to patch do gcc, ale jednodušší je použít pro dělení vlastní knihovnu. Obojí lze najít na webu.

  2. Pro datové přesuny je třeba v jazyce C dávat trochu víc pozor na zarovnání dat. Takže třeba kód jako např.


extern const uint8_t pole[];

extern uint32_t gi;

int main (void) {

uint8_t const* ptr = pole;

ptr += 1; // dáme si tam lichou adresu

gi = *(uint32_t*) ptr;

return 0;

}

fungovat nebude. Právě kvůli té liché adrese. Ona to není chyba, i když gcc si s tím pro jiné architektury poradí a se správným výsledkem. Specifikace jazyka C však říká, že výsledek v tomto případě nemusí být správný, chování takovéhoto přetypování není definováno. Takže kopírovat byte po bytu a do celočíselné proměnné ukládat pomocí násobení (shiftů) a sčítání.

Možná se objeví ještě nějaké problémy, ale i tak je architektura Cortex-M0 použitelná, za tu cenu má opravdu dobré vybavení, asi bude lepší používat to i místo těch maličkých Atmelů. Přece jen má to daleko větší možnosti. Vlastně jsem potřeboval filtrovat data z AD převodníku a zjistil jsem, že Attiny nemá hw násobičku a znásobit dvě 32-bitová čísla je dost utrpení. Takže jsem se dostal na hranici možností tohoto čipu a to je pak lépe se poohlédnout po něčem jiném.

Strana 8