Vaja 4: EXTI

Namen tokratne vaje je, da se spoznate s prekinitvami, ki jih lahko preko periferne naprave EXTI prožijo GPIO pini.

Naprava EXTI

Extended Interrupt and Event Controller (EXTI) omogoča generiranje prekinitev z zaznavanjem front na vhodnih linijah. Omogoča tudi zbujanje procesorja iz stanje nizke porabe (low-power modes). Poenostavljena shema je prikazana na Slika 4.1.

Slika 4.1: Shema EXTI

Vhodna linija je povezana v enoto, ki zaznava fronti na vhodu. Zaznavamo lahko prvo (angl. rising edge) in/ali zadnjo fronto (angl. falling edge). Zaznavanje prve fronte se vklopi v registru EXTI_FTSR (Falling trigger selection register), zaznavanje zadnje fronte pa v registru EXTI_RTSR (Rising trigger selection register). V registru EXTI_IMR (Interrupt mask register) omogočimo, da se zaznana fronta zabeleži v register EXTI_PR (Pending register). V primeru, da je bit v tem registru postavljen, to sproži zahtevo po prekinitvi prekinitvenemu krmilniku NVIC za EXTI linijo.

Naprava SYSCFG

Kot smo povedali na vaji 2, ima STM32H750 176 GPIO pinov. Vsak pin nima svoje EXTI linije, pini so namreč preko naprave SYSCFG (System Configuration) združeni v 16 EXTI linij. Kot prikazuje Slika 4.2, so vsi pini z oznako 0 (PA0, PB0, PC0, …, PK0) preko multiplekserja povezani na linijo EXTI0. Vsi pini z oznako 1 so povezani na linijo EXTI1, in tako dalje do linije EXTI15, na katero so povezani vsi pini z oznako 15.

Slika 4.2: SYSCFG - povezava GPIO pinov v EXTI linije

Prekinitve EXTI

Naprava EXTI uporablja 7 prekinitvenih vhodov prekinitvenega krmilnika NVIC. Linije EXTI0, EXTI1, EXTI2, EXTI3 in EXTI4 imajo vsak svojo prekinitveno linijo, linije EXTI5 do EXTI9 so skupaj povezane na skupno linijo, preostale linije EXTI10 do EXTI15 pa na drugo skupno linijo. Spodnja tabela povzema informacije o EXTI linijah ter pripadajočih prekinitvenih oznakah in imeni prekinitveno servisnih programov.

EXTI linija Prekinitvena oznaka Prekinitveno servisni programi
EXTI0 EXTI0_IRQn EXTI0_IRQHandler
EXTI1 EXTI1_IRQn EXTI1_IRQHandler
EXTI2 EXTI2_IRQn EXTI2_IRQHandler
EXTI3 EXTI3_IRQn EXTI3_IRQHandler
EXTI4 EXTI4_IRQn EXTI4_IRQHandler
EXTI5, EXTI6, EXTI7, EXTI8, EXTI9 EXTI9_5_IRQn EXTI9_5_IRQHandler
EXTI10, EXTI11, EXTI12, EXTI13, EXTI14, EXTI15 EXTI15_10_IRQn EXTI15_10_IRQHandler

Programski vmesnik EXTI

Vklop in uporabo prekinitve EXTI naredimo v treh korakih, ki so prikazani spodaj. Za primer je uporabljen pin PD4.

1. vklop zaznavanja prve in/ali zadnje fronte na EXTI liniji

Zaznavanje fronte v napravi EXTI vklopimo tako, da pri inicializacija GPIO pina nastavimo Mode na eno izmed možnosti: GPIO_MODE_IT_RISING, GPIO_MODE_IT_FALLING, GPIO_MODE_IT_RISING_FALLING. Prva možnost zaznava prvo fronto, druga zadnjo fronto, tretja pa obe fronti.

__HAL_RCC_GPIOD_CLK_ENABLE ();

GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOD , &GPIO_InitStruct);

2. vklop prekinitve v NVIC

Prekinitev vklopimo tako kot smo spoznali na zadnji vaji, z uporabo funkciji za nastavitev prioritete in vklopa prekinitve.

HAL_NVIC_SetPriority(EXTI4_IRQn, 12, 0);
HAL_NVIC_EnableIRQ(EXTI4_IRQn);

3. implementacija prekinitveno servisnega programa.

V prekinitveno servisnem programu moramo ob koncu pobrisati prekinitveno zahtevo v EXTI napravi. To storimo z makrojem __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_x), ki pobriše bite v registru EXTI_PR. Če zahteve ne pobrišemo, se bomo v prekinitveno servisni program vrnili takoj po izhodu. Naprava EXTI namreč zahteve po prekinitvi ne umakne samodejno.

Pri prekinitvah, ki se prožijo iz več linij, je smiselno preveriti katera izmed linij je sprožila prekinitev. To storimo z __HAL_GPIO_EXTI_GET_IT(GPIO_PIN_x).

Primer PSP-ja:

void EXTI4_IRQHandler(void) {
  // Preverimo, da je pin 4 sprozil prekinitev
  // Nujno potrebno pri liniah 5 do 15
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_4)) {
    // Pobrisemo EXTI4 pending bit in EXTI pending register
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);
  }
}

Odboj gumba

Pri enkratnem pritisku gumba bi pričakovali, da na vhodu preberemo eno fronto, ki se zgodi ob prehodu iz logične ničle na logično enico. V realnosti pa se zgodi, da zaradi t.i. odboja gumba (angl. button bounce) na vhodu preberemo več front. Slika 4.3 prikazuje primer odboja gumba ob enkratnem pritisku. Kot vidimo se na vhodu zgodijo tri fronte, relativno hitro ena za drugo. Na to moramo biti pozorni pri realizaciji prekinitveno servisnega programa.

Odpravljanju tega pojava rečemo button debounce. Najenostavnejša rešitev je, da ob prekinitvi, ki jo sproži gumb, preverimo da je od zadnje prekinitve minilo zadosti časa (npr. več kot 50ms). Prekinitev, ki se zgodi nekaj milisekund po zadnji prekinitvi enostavno ignoriramo (zgolj pobrišemo zahtevo).

Slika 4.3: Odboj gumba - button bounce

Naloga 4

Napišite program v katerem naj se proži prekinitev ob pritisku gumba. Ob prvem pritisku (prvi fronti) gumba naj se prižgeta zeleni LED diodi, ob drugem pritisku naj se ugasnita, pri tretjem zopet prižgeta, in tako dalje. Ob koncu pritiska gumba preverite ali je od pritiska minilo več kot 5 sekund. Če je, prižgite rdečo LED. Odpravite tudi odboj gumba.