Vektory přerušení
Nejdříve připravíme pole vektorů přerušení. Procesor Cortex-M3 po resetu načte do registru SP (Stack Pointer) obsah paměti na adrese 0x00000000 a do registru PC (Program Counter) obsah paměti na adrese 0x00000004.
Jinými slovy, Cortex-M3 po resetu nastaví ukazatel vrcholu zásobníku na hodnotu, která je na adrese 0x00000000 a začne provádět instrukce od adresy, která je uložena na adrese 0x00000004. Musíme se tedy postarat o to, aby na těchto dvou adresách byly uloženy správné hodnoty. Současně bychom měli mít na následujících dvou slovech adresy rutin pro obsluhu výjimek NMI a Hard Fault. Vytvoříme minimální tabulku vektorů a umístíme ji na správné místo v paměti. K tomu nám poslouží zdrojový kód, který uložíme do souboru vector.c. Pro překlad a sestavení programu budeme používat překladač GNU GCC. Použité atributy odpovídají tomuto překladači a nemusí fungovat pro jiné překladače.
extern unsigned long _stack_top;
static void handler_reset(void);
static void handler_dummy(void);
__attribute__ ((section("vectors")))
void (* const vectorTbl[])(void) = {
(void (*)(void)) (&_stack_top), /* 00 - SP initial value */
handler_reset, /* 01 - Reset handler */
handler_dummy, /* 02 - NMI handler */
handler_dummy /* 03 - Hard fault handler */
};
První položkou tabulky vektorů je adresa, která bude při resetu umístěna do registru SP (Stack Pointer). Proměnná _stack_top je deklarovaná jako externí, její umístění v paměti získá linker z linkovacího skriptu, který podrobně rozebereme v další části. Adresu proměnné _stack_top musíme přetypovat, protože tabulka vektorů je deklarovaná jako pole ukazatelů na funkce. Atribut section sděluje linkeru, aby pole vektorů umístil do paměťové sekce vectors. Skutečné umístění sekce vectors v paměti je definováno v již zmíněném linkovacím skriptu.
Následuje adresa funkce pro obsluhu resetu, která bude po resetu procesoru dosazena do registru PC (Program Counter). Procesor začne po resetu provádět funkci handler_reset() a ukazatel zásobníku bude obsahovat adresu proměnné _stack_top.
Další dvě položky jsou adresy rutin pro obsluhu výjimek NMI a HardFault, obě výjimky pro jednoduchost obsloužíme jedinou funkcí. Protože procesor Cortex-M3 provádí při obsluze výjimky úklid registrů na zásobník a pro návrat z přerušení není potřeba speciální instrukce, nemusíme použít pro zápis rutin obsluhy přerušení žádný speciální atribut a můžeme je zapisovat jako normální funkce.
extern unsigned long _text_end;
extern unsigned long _data_begin;
extern unsigned long _data_end;
extern unsigned long _bss_begin;
extern unsigned long _bss_end;
extern int main(void);
void handler_reset(void)
{
unsigned long *src;
unsigned long *trg;
/* copy initialized data values from Flash to RAM */
src = &_text_end;
for (trg = &_data_begin; trg < &_data_end; ) {
*trg++ = *src++;
}
/* clear unitialized data */
for (trg = &_bss_begin; trg < &_bss_end; ) {
*trg++ = 0;
}
/* call main() */
main();
}
Funkce handler_reset() pro obsluhu resetu je velmi jednoduchá. Provede kopírování počátečních hodnot inicializovaných proměnných z Flash paměti do RAM, potom nuluje neinicializované proměnné a nakonec zavolá hlavní program main(). Adresy konce paměťové sekce kódu (_text_end), začátku a konce sekce inicializovaných proměnných (_data_begin, _data_end) a sekce neinicializovaných proměnných (_bss_begin, _bss_end) jsou definovány také v linkovacím skriptu.
Obsluhu výjimek NMI a HardFault napíšeme velmi jednoduše pouze jako nekonečný cyklus. Pokud při běhu našeho programu dojde k některé z těchto dvou výjimek, procesor se bude točit v nekonečném cyklu ve funkci handler_dummy().
void handler_dummy(void)
{
while (1) {
}
}
