poniedziałek, 10 października 2016

[2] STM32F1 - Przerwania EXTI

W tym poście chciałbym przedstawić sposób obsługi przerwania zewnętrznego na rejestrach STM32. Trochę teorii i opisu części programowania tego opisu dla STM32 M3.

Teraz przejdę tylko do opisu rejestów oraz sposobu wywołania przerwania.

W formie przypomnienia to należy pamiętać o tym iż przerwania mają współdzielone wektory np. dla PA1 oraz PC1, czy dla linii od 10 do 15. Wobec tego trzeba będzie dokonywać sprawdzenia, która z linii dokonała wyzwolenia przerwania.

Rejestry


Z rejestrów układu EXTI można wyróżnić:

EXTI_IMR - rejestr wystąpień przerwań dla układu


Każda z pinów może przyjmować jeden stan 0 lub 1 (bity od 0 do 19). Zero oznacza, że przerwanie na linii zostało maskowane, 1 że zostało niezamaskowane Pozostałe są ustawione domyślnie na 0. Bit 19 jest używany tylko dla układów z liniami connectivity, dla innych układów należy go zostawić na 0.

EXTI_EMR - rejestr wystąpień zdarzeń

Wygląda on dokładnie tak samo jak IMR. Zero oznacza, że zdarzenie na linii jest maskowane, jedynka natomiast, że jest niemaskowane.

EXTI_RTSR - wybranie zbocza rosnącego dla danego pinu:

Jedynka ustawia wyzwalanie zboczem rosnącym.

EXTI_FTSR - ustawia wyzwalanie zboczem opadającym:

Zbocze opadające włączone gdy ustawiona jedynka.

EXTI_SWIER - ustawienie przerwania systemowego na określonej linii. Budowa wewnętrzna taka jak wcześniej wymienionych rejestrów.

Gdy przerwanie jest włączone dla EXTI_IMR to zmiana stanu z 0 na 1 powoduje ustawienie bitu w rejestrze EXTI_PR. Powoduje to wygenerowanie żądanego przerwania.

EXTI_PR - pozwala na zweryfikowanie czy wystąpiło przerwanie. 0 oznacza że przerwanie nie miało miejsca, jedynka natomiast, że wystąpiło przerwanie wyzwolone wcześniej ustawionym zboczem.

W tym rejestrze jak już wspomniałem jest ustawiana jedynka po pojawieniu się przerwania. Czyszczenie natomiast następuje poprzez wpisanie jedynki do bitu.

Program


Komentarz umieściłem przy każdej z linii kodu. Jego działanie polega na zapaleniu oraz zgaszeniu diody dołączonej do PA5 poprzez naciskanie przycisku.

  1. #include "stm32f10x.h"
  2. volatile uint8_t zmienna = 0;
  3. int main(void)
  4. {
  5.     RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //Zegar dla GPIOA
  6.     RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //Zegar dla GPIOC
  7.     RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; //Zegar funkcji alternatywnych
  8.    
  9.     //Ustawienie pinu 5 jako wyjście pushpull z czestotliwoscia 2MHz
  10.     GPIOA->CRL = 1<<21;
  11.    
  12.     //Ustawienie pinu 13 jako input_floating
  13.     GPIOC->CRH = 1<<22;
  14.    
  15.     //wybranie portu odpowiedzialnego za przerwanie
  16.     AFIO->EXTICR[3] = AFIO_EXTICR4_EXTI13_PC;
  17.    
  18.     //ustawienie rejestru IMR, wlaczenie 13
  19.     EXTI->IMR = EXTI_IMR_MR13;
  20.     //Zbocze rosnące rejestr RTSR
  21.     //Zbocze opadajace rejestr FTSR
  22.     EXTI->FTSR = EXTI_FTSR_TR13;
  23.    
  24.     //Wlaczenie przerwania
  25.     NVIC_EnableIRQ(EXTI15_10_IRQn);
  26.     while (1){}
  27. }
  28. //Obsluga przerwania
  29. __attribute__((interrupt)) void EXTI15_10_IRQHandler(void)
  30. {
  31.     //Sprawdzenie wywolania przerwania
  32.     if (EXTI->PR & EXTI_PR_PR13)
  33.     {
  34.         //Kasowanie flagi
  35.         EXTI->PR = EXTI_PR_PR13;
  36.         //
  37.         if(zmienna == 0)
  38.         {
  39.             GPIOA->BSRR |= GPIO_BSRR_BS5;
  40.             zmienna = 1;
  41.         }
  42.         else if(zmienna == 1)
  43.         {
  44.             GPIOA->BSRR |=~ GPIO_BSRR_BS5;
  45.             zmienna = 0;
  46.         }
  47.     }
  48. }

Na końcu chciałbym jeszcze zaznaczyć, że kasowanie flagi przerwania powinno się odbywać jak najszybciej jak to tylko możliwe. Czyli najlepiej zaraz po jej sprawdzeniu. Spowodowane jest to tym, że z przerwanie może zostać ponownie wywołane, ponieważ flaga nie zdąży zostać skasowana. Można też pominąć jakieś przerwanie jeśli zostanie ona za szybko skasowana.