poniedziałek, 3 maja 2021

STM32G0 - EXTI , konfiguracja przerwania zewnętrznego.


Konfiguracja przerwania zewnętrznego w STM32G0 dla wybranego źródła może być nie lada wyzwaniem dla osoby , która po raz pierwszy zetknie się z tym zagadnieniem. STM pogmatwał tutaj trochę i przynajmniej na początku odczujemy dyskomfort konfigurując ten moduł. W artykule postaram się pokazać jak poprawnie skonfigurować wybrany pin do współpracy z przerwaniem zewnętrznym.

 

Zacznę trochę od tyłu. W STM32G0 mamy do dyspozycji trzy funkcje obsługujące przerwania zewnętrzne EXTI. Są to EXTI0_1_IRQHandler, EXTI2_3_IRQHandler i EXTI4_15_IRQHandler. Nazwy tych funkcji znajdziemy w pliku STM32G07x_Vectors.s a plik ten jest standardowo dołączany przy tworzeniu nowego projektu np. w IDE SEGGERA

EXTI to podmoduł systemu przerwań NVIC. Te trzy wymienione powyżej funkcje, obsługują linie od 0 do 15 , linie to nic innego jak numerki pinów dowolnego portu. PA0, PB0 to linia nr 0 a PA1,PB1 to linia nr 1. Od razu rzuca się w oczy pewna ułomność takiego rozwiązania, która polega na tym, że nie możemy jednocześnie użyć przerwań na np. pinie PA1 i PB1 czyli linii nr 1 na różnych portach. Nie możemy bo nie mamy mechanizmów rozstrzygnięcia w ramach jednej linii z którego portu przyszło przerwanie. Trochę kiepsko z tym, no ale cóż, jest jak jest trzeba z tym jakoś żyć. No dobra wiemy jakie mamy ograniczenia idźmy dalej.

Załóżmy , że naszym celem jest skonfigurowanie dwóch pinów np. PA1 i PB9. Pin PA1 będzie reagował na zbocze narastające, PB9 na zbocze opadające.

Ogólny schemat czynności wygląda mniej więcej tak :

1. Włącz zegar dla GPIOA i GPIOB

2. Skonfiguruj PA1 i PB9 jako wejście (Input), ustaw rezystory podciągające dla PA1 - Pull Down, PB9 - Pull Up

3. Przyporządkuj PA1 i PB9 do modułu EXTI

4. Ustaw rodzaj reakcji na poszczególnych pinach (PA1 - zbocze narastające, PB9 zbocze opadające)

5. Odmaskuj a może nawet odczaruj :) ,przerwanie EXTI dla PA1 i PB9

6. Ustaw i włącz NVIC-a dla modułu EXTI

7. Ustaw funkcję przerwania.

Mój zestaw do zabawy to płytka z STM32G071KBT6 , programator J-LINK EDU Mini i IDE SEGGER-a.

Tworzę sobie nowy projekt w środowisku SEGGER-a i wstępnie wypełniam plik main.c :

Pierwszą czynnością niech będzie włączenie zegarów dla GPIOA i GPIOB, złapałem się ostatnio, że zapominam o tym , przyzwyczaiłem się do ATSAM-ów Microchipa gdzie takiej czynności nie trzeba było wykonywać :) :

Stwórzmy sobie funkcję konfigurującą poszczególne piny , ja dodam do niej jeden pin więcej tj. PA8 bo tam mam diodę LED podłączoną na mojej płytce a przyda się w eksperymencie naukowym:

Powyżej skonfigurowałem PA8 gdzie mam LED-a oraz na razie tylko PA1.  Trzema czerwonymi kropkami oznaczyłem całą esencję konfiguracji PA1 do współpracy z modułem EXTI. Szczególną trudność może przyspożyć zrozumienie zapisu do rejestru EXTI_EXTICRx:

/*set EXTI for PA - 1(EXTI1) PA(0b00)*/
EXTI->EXTICR[0] &= ~EXTI_EXTICR1_EXTI1 ;

gdzie EXTI_EXTICR1_EXTI1 = 7<<8 = 0x700 maskuje nam trzy bity nr 8,9,10, ponieważ dla PA musimy wpisać 0x00 do rejestru EXTI_EXTICRx dlatego zerujemy w efekcie końcowym bity w naszej masce nie ruszając pozostałych bitów rejestru.

Pierwsza rzecz którą trzeba mieć na uwadze to :

EXTICR[0] / EXTICR1 dotyczy linii EXTI0...3

EXTICR[1] / EXTICR2 dotyczy linii EXTI4...7

EXTICR[2] / EXTICR3 dotyczy linii EXTI8...11

EXTICR[3] / EXTICR4 dotyczy linii EXTI12...15  

druga rzecz to już z opisu rejestru EXTI_EXTICRx dowiadujemy się, że:

0x00: PA
0x01: PB
0x02: PC
0x03: PD
0x04: reserved
0x05: PF

W STM32G0 obsługa EXTI trochę odbiega w szczegółach od innych linii STM32 i ta zmiana jest na niekorzyść użytkownika, który będzie się próbował w tym module połapać. Ktoś kto projektował ten moduł od strony rejestrów zasługuje na naganę . Proponuję aby zajrzeć sobie w manualu do rejestru EXTI_EXTICRx i spróbować z marszu rozszyfrować co poeta miał na myśli. Ja do rozszyfrowania tego podszedłem od "dupy strony" czyli od zapisów w pliku nagłówkowym MCU i tam próbowałem się połapać o co biega. Jakoś to mi się udało, choć dla zmyłki w pliku nagłówkowym mamy trzy bity opisane w każdym EXTIx podczas gdy jak wynika z opisu w rejestrze EXTI_EXTICRx potrzebujemy dla PA, PB etc zapis złożony tylko z dwóch bitów. No tak trochę nam STM zrobił pod górę w rozszyfrowaniu modułu EXTI. Jak to się mówi im głebiej w las tym ciemniej a potem się okaże jeszcze , że król jest nagi :).

Oczywiście ktoś kto ustawi sobie moduł EXTI w HAL nie odczuje żadnego dyskomfortu no wogóle nic nie odczuje :) Programowanie bez emocji i wysiłku umysłowego ? nudaaa.... :). 

Kolejny zapis :

/*set EXTI Rising triger for Line no. 1 (PA1)*/
EXTI->RTSR1 |= EXTI_RTSR1_RT1 ;

Ustawia nam rodzaj reakcji na Linii numer 1 (bo PA1). W moim przypadku ustawiam reakcję na zbocze narastające. Tutaj żadnej filozofi nie ma , rejestr jest prosty.

Ostatni zapis :

/*set EXTI Interrupt no-masked for Line no.1 (PA1)*/
EXTI->IMR1 |= EXTI_IMR1_IM1 ;

Odmaskowuje nam zamaskowane przerwanie dla Linii nr 1. Czyli maska Zorro zostanie zdjęta z pacjenta .Początkowo myślałem , że to ustawienie dotyczy tylko przypadku gdy chcemy zrobić wakeup dla Core  z trybu uśpienia no ale nie tylko się okazuje, musimy to ustawić i tyle.

Mając skonfigurowany pin PA1 , dodajemy zapis włączający NVIC-a dla przerwań EXTI0_1 czyli dla Lini 0 i 1 i na końcu programu dodajemy ciało funkcji handlera dla przerwania, która zostanie wywołana jeśli zajdzie jakieś zdarzenie na linii 0 lub 1. W ciele tej funkcji rozpoznajemy czy przerwanie przyszło z Linii nr 1 i czy to było zbocze narastające. Jeśli tak to zapalimy diodę LED na pinie PA8.

Wgrywam program do MCU i sprawdzam czy to działa. W tym celu kabelek podłączam do +3.3V i drugim końcem wkładam w dziurkę pinu PA1. Efektem jest zapalenie się diody LED. Wszystko działa jak powinno.

Teraz dodamy do programu konfigurację dla PB9.

Poniżej fragmenty kodu dotyczące konfiguracji PB9 :



PB9 zostało ustawione jako wejście Pull-up (podciągamy do +3.3V) z reakcją na zbocze opadające. Aby wyzwolić przerwanie musimy tym razem kabelek podpiąć do masy i takim kabelkiem potraktować PB9. W przerwaniu reagujemy na Linię nr 9 i zbocze opadające. Dodatkową czynnością będzie zgaszenie diody LED na pinie PA8.

Teraz zabawa po wgraniu programu polega na tym, że podłączonym do +3.3V kabelkiem dotykamy PA1 , efektem jest zapalenie diody LED na pinie PA8. Przepinamy kabelek do masy i teraz dotykamy PB9, efektem będzie zgaszenie diody LED. Ot i cała zabawa :)

Jeszcze może po krótce omówię zapis do tego nieszczęsnego rejestru EXTI_EXTICRx dla PB9. Bo tutaj mamy dwa wpisy :

/*set EXTI for PB9 - 9(EXTI9) PB(0b01)*/
EXTI->EXTICR[2] &= ~EXTI_EXTICR3_EXTI9 ; //clear
EXTI->EXTICR[2] |=  EXTI_EXTICR3_EXTI9_0 ; //set 0b01

Dlaczego dla PB9 odwołujemy się poprzez EXTICR[2] i potem EXTICR3 ,tutaj patrz szablon jaki podałem wyżej w artykule.. Pierwszym wpisem zeruję pole bitowe dla Linii nr 9 a drugim ustawiam pierwszy bit w polu, bo dla PB przysługuje wpis 0b01. dla PA było to 0b00

I to by było na tyle . Pokazany przykład powinien znacząco ułatwić konfigurację pinów do współpracy z modułem EXTI w STM32G0. Pomimo, że jest to najbardziej beznadziejna forma implementacji w rejestrach z jaką się dotychczas spotkałem w MCU. Ale nie ma co się zrażać tylko przeć do przodu i cieszyć się , że rebus rozwiązany.

Kolejny test mojej płytki i współpracy z programatorem J-LINK EDU Mini oraz IDE SEGGERA zaliczony. Bardzo mnie cieszy, że nie poszedłem na łatwiznę i nie użyłem płytki Nucleo, to nie byłaby taka zabawa jaką mam  :).


Pozdrawiam

PICmajster
picmajster.blog@gmail.com

Linki :

Kod projektu dla IDE SEGGER-a na GitHub

Brak komentarzy:

Prześlij komentarz