Produkty Novinky Články Návody Kontakty

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) {
    }
}
​