CMSIS a hlavičkové soubory
CMSIS
znamená Common Microcontroller Software Interface Standard.
Je to standard od firmy Arm pro čipy s jádry Arm Cortex.
Jeho cíl je jednoduchý:
aby základní věci kolem procesoru vypadaly podobně u různých výrobců.
CMSIS tedy není univerzální vrstva pro úplně všechny mikrokontroléry. U AVR ATtiny ho běžně nepotkáte. U STM32, některých čipů od Microchipu, NXP nebo Nordic už ano, protože ty používají jádra Arm Cortex. Samotný projekt je dostupný i na GitHubu.
Co CMSIS typicky řeší
CMSIS pomáhá hlavně s věcmi kolem samotného jádra procesoru:
- názvy registrů jádra,
- přerušení,
- start programu po resetu,
- základní funkce pro práci s procesorem,
- jednotný způsob, jak popsat zařízení v hlavičkových souborech.
Vedle CMSIS často existují ještě hlavičkové soubory od výrobce čipu.
Ty obsahují názvy konkrétních periférií:
například GPIOA, USART1, TIM2 nebo ADC1.
Proč je to užitečné
Bez hlavičkových souborů byste museli psát adresy registrů ručně. Třeba něco jako:
*(volatile uint32_t *)0x40020000 = 0x01;
To fungovat může, ale čte se to dost špatně. S pojmenovanými registry je program srozumitelnější:
GPIOA->MODER = 0x01;
Pořád pracujete nízko nad hardwarem, ale už nemusíte mít v hlavě číselné adresy. Mozek se potom může věnovat programu místo telefonního seznamu adres.
Kdy CMSIS použít
CMSIS se hodí, když chcete psát blízko hardwaru,
ale nechcete všechno definovat sami.
Často je také základem pro další vrstvy.
HAL
i
LL
knihovny u Arm čipů obvykle stojí právě na CMSIS a hlavičkách od výrobce.
Co místo toho používá ATtiny
U ATtiny se obvykle používá AVR toolchain:
avr-gcc, avr-libc
a hlavičkové soubory jako <avr/io.h>.
Není to CMSIS, protože ATtiny není Arm Cortex.
Prakticky to ale řeší podobnou část problému:
dává programu názvy registrů, bitů a přerušení.
V prostředí projektu se musí říct,
pro jaký konkrétní čip se program překládá.
U avr-gcc se to dělá volbou -mmcu.
Například:
avr-gcc -mmcu=attiny1626 ...
Překladač podle toho nastaví makro pro konkrétní zařízení.
Soubor <avr/io.h>
pak vybere správnou hlavičku,
třeba <avr/iotn1626.h>
pro ATtiny1626.
V ní jsou definice jako:
PORTA.DIRSET = PIN1_bm;
USART0.BAUD = UART_BAUD_REGISTER;
CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_6X_gc | CLKCTRL_PEN_bm;
Tohle je vrstva těsně nad registry. Neříká vám ještě "pošli zprávu po UARTu". Říká spíš: "Tady máš pojmenované registry a bity, ať nemusíš psát adresy ručně."
Co je uvnitř hlaviček
Hlavičkové soubory nejsou kouzlo. Hodně často jsou to hlavně definice adres v paměti a názvů bitů.
Zjednodušeně může definice registru vypadat takto:
#define PORTA (*(PORT_t *) 0x0400)
#define USART0 (*(USART_t *) 0x0800)
#define PIN5_bm 0x20
To znamená,
že PORTA není obyčejná proměnná.
Je to pojmenovaný přístup na adresu 0x0400,
kde má daný ATtiny namapované registry portu A.
Když program zapíše do PORTA.DIRSET,
ve skutečnosti zapisuje na konkrétní adresu v paměťové mapě čipu.
Takže zápis:
PORTA.DIRSET = PIN5_bm;
je pro člověka čitelnější způsob,
jak říct:
"Na správnou adresu registru pro port A zapiš masku bitu 5."
Bez těchto hlaviček by programátor musel vědět,
že port A začíná třeba na adrese 0x0400.
To by šlo,
ale bylo by to zbytečně náchylné na chyby.
Jedno špatné číslo a program píše jinam,
než si myslíte.
CMSIS a AVR hlavičky nejsou totéž.
Obě vrstvy ale pomáhají s tím,
aby programátor nepsal holé adresy registrů.
U Arm Cortex čipů tuto roli často plní CMSIS.
U ATtiny ji plní hlavně avr-libc a hlavičky pro konkrétní čip.