STM32 - Free RTOS dla dociekliwych.pdf
(
220 KB
)
Pobierz
untitled
Free RTOS dla dociekliwych
PODZESPOŁY
Free RTOS dla dociekliwych
W EP5/09 zostało przedstawione zagadnienie systemu operacyjnego
FreeRTOS w odniesieniu do mikrokontrolerów STM32. Wykorzystując
te informacje, w niniejszym artykule przedstawiono sposób tworzenia
nieco bardziej zaawansowanych aplikacji z użyciem systemu FreeRTOS
i mikrokontrolerów STM32. Pokazano m. in. jak nawiązać wymianę
danych pomiędzy uruchomionymi w systemie zadaniami oraz jak
zabezpieczyć zasoby mikrokontrolera przed nieuprawnionym dostępem.
odpowiada oddzielne zadanie, a więc sumie
w systemie są uruchomione trzy zadania:
vTa-
skLD1()
,
vTaskLD2()
,
vTaskLD3()
. Kod zadania
vTaskLD1()
został zamieszczony na
list. 1
, na-
tomiast funkcja obsługi przerwania dla lewego
położenia joysticka znajduje się na
list. 2
. Pozo-
stałe zadania i funkcje obsługi przerwań są róż-
nią się tylko sterowanymi lub monitorowany-
mi wyprowadzeniami. Pozycja lewa joysticka
jest podłączona do wyprowadzenia PE1, stąd
wykorzystana jest funkcja obsługi przerwania
EXTI1_IRQHandler()
. Główna funkcja progra-
mu
main()
, która została zamieszczona na
list.
3
, ma za zadanie skon
fi
gurować mikrokontroler
wraz z wszystkimi wykorzystywanymi peryfe-
riami do pracy – funkcja
prvSetupHardware()
.
Ponadto następuje tutaj uruchomienie zadań
oraz planisty, ten ostatni jest aktywowany przez
wywołanie funkcji
vTaskStartScheduler()
.
Każdy semafor jest tworzony przed wej-
ściem danego zadania do nieskończonej pętli.
Zmienna
xSemaphoreLD1
jest zadeklarowa-
na jako globalna, tak jak pozostałe semafory.
Sprawdzenie stanu semafora odbywa się wraz
z wywołaniem funkcji
xSemaphoreTake()
.
W nieco ściślejszym rozumowaniu wymieniona
funkcja próbuje „
wziąć
” semafor, co oznacza, że
jeśli jest on ustawiony to następuje wykonanie
dotychczas zablokowanej części zadania, a se-
mafor zostaje dezaktywowany (skasowany).
Jeśli funkcja
xSemaphoreTake()
zwróci war-
tość
pdTRUE
, to wtenczas następuje zmiana
stanu wyprowadzenia na przeciwny. Jako argu-
menty do funkcji należy przekazać nazwę se-
mafora oraz (pośrednio) czas, przez jaki zadanie
będzie oczekiwać, aż semafor stanie się aktyw-
ny. W omawianym przy-
padku wartość ta wynosi
0, ponieważ zadanie
zajmuje się tylko spraw-
dzaniem stanu semafora
i niczym więcej.
Głównym zadaniem
mikrokontrolera w funk-
cji obsługi przerwania
jest aktywowanie se-
mafora, dzięki czemu zadanie
będzie wiedziało, że należy
zmienić stan wyprowadzenia,
do którego podłączona jest dio-
da LED. Odpowiada za to funk-
cja
xSemaphoreGiveFromISR()
,
której należy przekazać dwa
argumenty, pierwszy to uchwyt
(nazwa) semafora. Drugi, prze-
kazywany przez referencję,
System operacyjny czasu rzeczywistego
FreeRTOS udostępnia programistom w sumie
pięć mechanizmów wykorzystywanych do ko-
munikacji pomiędzy zadaniami (lub przerwa-
niami i zadaniami) oraz do zabezpieczania za-
sobów mikrokontrolera. Są to: semafory binar-
ne, kolejki, semaforów licznikowe, muteksy,
muteksy rekurencyjne. Każdy przedstawiony
w artykule mechanizm został poparty stosow-
nym przykładem, przygotowanym dla płytki
ewaluacyjnej STM3210B-EVAL, która jest
wyposażona w mikrokontroler
STM32F103
.
Szczegółowych informacji na temat systemu
operacyjnego FreeRTOS należy szukać na jego
stronie internetowej
www.freertos.org
.
W praktyce systemów wbudowanych se-
mafory binarne są zazwyczaj wykorzystywane
od synchronizacji zadań lub zadania i prze-
rwania. Zagadnienie synchronizacji zadania
za pomocą przerwania przedstawiono na
rys.
1
. Dopóty, dopóki w systemie nie jest zareje-
strowane przerwanie, zadanie pozostaje w sta-
nie „
ZABLOKOWANE
”. W chwili, gdy wystąpi
przerwanie, a w funkcji jego obsługi nastąpi
uaktywnienie semafora, system operacyjny
wprowadzi zablokowane zadanie w stan „
GO-
TOWE DO WYKONANIA
”. Od tego momentu
zadanie oczekuje na zwolnienie zasobów, a je-
śli to nastąpi, to zacznie być realizowane.
Aplikacja działająca w oparciu o identycz-
ny mechanizm została omówiona poniżej, jej
zadaniem jest reagowanie na zmiany stanów
przycisków zapalaniem lub gaszeniem diod
LED na płytce ewaluacyjnej. Sterowane mają
być diody LD1, LD2, LD3, za pomocą położe-
nia joysticka odpowiednio: lewo, góra, prawo.
Schemat działania programu został przedsta-
wiony na
rys. 2
.
Do komunikacji pomiędzy funkcjami ob-
sługi przerwań i zadaniami wykorzystano trzy
semafory binarne, dla każdego zestawu, przy-
cisk i dioda, po jednym. Za stan każdej z diod
Semafory binarne
Semafory binarne, służą do sterowania
wykonywaniem zadań. Gdy semafor jest nie-
aktywny, to wykonywanie czynności (zadania)
jest zablokowane. Innymi słowy, aby zadanie,
którego działanie jest uzależnione od semafo-
ra, mogło się wykonać, to semafor musi zostać
aktywowany.
List. 1.
void vTaskLD1(void * pvParameters)
{
vSemaphoreCreateBinary(xSemaphoreLD1);
// Nieskonczona petla zadania
for(;;)
{
if(xSemaphoreTake(xSemaphoreLD1, 0) == pdTRUE)
{
vhToggleLD1();
}
}
}
mafora
Rys. 1.
List. 2.
void EXTI1_IRQHandler(void)
{
static portBASE_TYPE xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
if(EXTI_GetITStatus(EXTI_Line1) != RESET)
{
xSemaphoreGiveFromISR(xSemaphoreLD1,
&xHigherPriorityTaskWoken);
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
Rys. 2.
ELEKTRONIKA PRAKTYCZNA 7/2009
109
STM32
PODZESPOŁY
List. 3.
int main( void )
{
// Konfi guracja sprzetu
prvSetupHardware();
// Uruchomienie zadan
vStartLDTasks( TASK_PRIORITY );
jakie można do niej wpisać, oraz rozmiar po-
jedynczego elementu. Obydwa parametry są
określane na etapie tworzenia (deklarowania)
kolejki.
Elementy w kolejce są umieszczane jako
kopie danych źródłowych, dzięki czemu ko-
munikujące się zadania nie mogą bezpośred-
nio uzyskać dostępu do pamięci, w której
znajdują się dane źródłowe. Mechanizm ko-
lejek w systemie FreeRTOS ma zaimplemen-
towaną obsługę wszystkich zagadnień zwią-
zanych z wzajemnymi wykluczeniami, zatem
programista nie musi już o to zabiegać.
Jeśli zaistnieje potrzeba kolejkowania da-
nych o większym rozmiarze, niż to przewi-
duje zadeklarowana kolejka, to wtedy można
użyć wskaźnika na element. W takich wypad-
kach należy się zawsze upewniać, kto (które
zadanie) jest właścicielem danej zmiennej,
oraz ostrożnie wykonywać operacje na otrzy-
manym adresie elementu tak, aby nie zdesta-
bilizować pracy całego systemu.
Niekiedy może się zdarzyć, że w kolejce
nie ma żadnych danych do odebrania przez
określone zadanie. W takich sytuacjach mocy
nabiera możliwość ustawienia czasu, a kon-
kretniej liczby taktów zegara systemu opera-
cyjnego, po jakim, jeśli żadne ważne dane nie
pojawią się w kolejce, zadanie przejdzie do
stanu „
ZABLOKOWANE
”. Sytuacja może być
również odwrotna: kolejka może być zapeł-
niona, wtenczas zadanie, które chce wpisać
dane do kolejki, oczekuje zadeklarowaną ilość
taktów zegara na zwolnienie się miejsca w ko-
lejce, gdy to nie nastąpi to również przechodzi
do stanu „
ZABLOKOWANE
”. Zasada działania
kolejki została omówiona w EP5/09.
Sposób użycia kolejek zostanie przed-
stawiony na przykładzie aplikacji, której za-
daniem będzie przetwarzanie A/C i pokazy-
wanie wyniku na gra
fi
cznym wyświetlaczu
LCD zamontowanym na płytce ewaluacyjnej
STM3210B-EVAL. Mierzone napięcie pocho-
dzi od potencjometru podłączonego do wy-
prowadzenia PC4.
Kon
fi
guracja ADC została dokładnie omó-
wiona w EP, zatem tutaj nie będziemy się tym
bliżej zajmować, podobnie jak w przypadku
aplikacji demonstrującej działanie semafo-
rów, również tutaj wszystkie czynności zwią-
zane z kon
fi
guracją są umieszczone w funkcji
prvSetupHardware()
.
W systemie są utworzone dwa zadania, na-
tomiast jedyna kolejka – xQueueLCD – została
utworzona jako zmienna globalna (uchwyt)
typu
xQueueHandle
. Na
list. 4
został zamiesz-
czony kod zadania
vTaskADC()
, które tworzy
za pomocą wywołania funkcji
xQueueCreate()
kolejkę. Następnie już w pętli nieskończonej
w 300 ms odstępach odczytuje wartość z prze-
twornika A/C, by w kolejnym kroku zapisać ją
do kolejki. Do tego celu użyta jest funkcja
xQu-
eueSend()
, której w argumentach należy podać
kolejno: nazwę kolejki, zmienną do wysłania,
oraz liczbę cykli systemowych, jakie będą od-
czekane w razie pełnej kolejki.
Drugie uruchomione w systemie zadanie
–
vTaskLCD()
– jest przedstawione na
list. 5
.
Pierwszą czynnością, jaką zadanie wykonuje,
jest inicjalizacja wyświetlacza LCD, po czym
w pętli nieskończonej, również co 300 ms, na-
stępuje odbieranie danych z kolejki i wyświe-
tlanie ich na LCD.
Efektem pracy aplikacji jest pokazywanie
wyniku przetwarzania, którym jest liczba z za-
kresu od 0 do 4096. Czas odświeżania został
tak dobrany, aby można było dobrze zaobser-
wować efekt kolejkowania danych. Zmieniając
dość szybko położenie potencjometru P1 wi-
dać, jak dopiero po chwili wynik osiąga swoją
właściwą wartość.
// Uruchomienie planisty
vTaskStartScheduler();
return 0;
}
argument jest zmienną, która otrzyma wartość
pdTRUE
, jeśli odblokowane przez semafor za-
danie będzie miało wyższy priorytet, niż aktu-
alnie wykonywane. Wszystkie nazwy funkcji
API systemu FreeRTOS, jakie są używane pod-
czas obsługi przerwań muszą kończyć się przy-
rostkiem „
ISR
”. Jest to niezbędne dla poprawnej
pracy mikrokontrolera.
Kolejki
Kolejki są głównym mechanizmem, jaki
jest wykorzystywany do wymiany informacji
pomiędzy zadaniami. Mogą być wykorzy-
stywane do przesyłania wiadomości między
zadaniami oraz pomiędzy przerwaniami i za-
daniami. W większości przypadków kolejki
są wykorzystywane jako bezpieczne bufory
FIFO.
Każda zde
fi
niowana w systemie kolejka
ma ustaloną długość, czyli liczbę elementów,
List. 4.
void vTaskADC(void * pvParameters)
{
u16 wynik_adc;
xQueueLCD = xQueueCreate(10, sizeof(u16));
// Nieskonczona petla zadania
for(;;)
{
vTaskDelay(300 / portTICK_RATE_MS); // Odczekanie 300 ms
wynik_adc = ADC_GetConversionValue(ADC1);
xQueueSend(xQueueLCD, (void *) &wynik_adc, (portTickType) 10);
}
}
List. 5.
void vTaskLCD(void * pvParameters)
{
u16 wynik;
char wynik_lcd[5];
STM3210B_LCD_Init();
LCD_Clear(Blue);
// Nieskonczona petla zadania
for(;;)
{
xQueueReceive(xQueueLCD, &wynik, (portTickType) 10);
vTaskDelay(300 / portTICK_RATE_MS); // Odczekanie 300 ms
sprintf(wynik_lcd, „%4d”, wynik);
LCD_DisplayStringLine(0, (u8*) wynik_lcd);
}
}
Semafory licznikowe
Semafory licznikowe (
Counting Semapho-
res
) są hybrydą zwykłej kolejki i semafora binar-
nego, zatem nie niosą ze sobą więcej informacji
poza aktualną wartością semafora. Mechanizm
semaforów licznikowych jest wykorzystywany
przede wszystkim w implementacji zadań, któ-
re wymagają zliczania zdarzeń.
Od strony praktycznej wygląda to tak, że
np. Zadanie A „daje” (
give
), czyli inkrementuje
semafor licznikowy, natomiast Zadanie B „za-
biera” (
take
) ten sam semafor – dekrementuje
go. Tym sposobem wartość semafora liczniko-
List. 6.
void vTaskSemphr(void * pvParameters)
{
u8 wynik_sem = 0;
xQueueLCD = xQueueCreate(10, sizeof(xSemaphoreHandle));
xSemaphoreCnt = xSemaphoreCreateCounting( 50, 0 );
// Nieskonczona petla zadania
for(;;)
{
vTaskDelay(1000 portTICK_RATE_MS); //Odczekanie 1 sek
xQueueSend(xQueueLCD, (void *) &wynik_sem, 0);
if(xSemaphoreTake(xSemaphoreCnt,0) == pdPASS)
wynik_sem = 1;
else
wynik_sem = 0;
}
}
110
ELEKTRONIKA PRAKTYCZNA 7/2009
110
Free RTOS dla dociekliwych
List. 7.
void vTask25PWM(void * pvParameters)
{
xSemaphoreMuteks = xSemaphoreCreateMutex();
// Nieskonczona petla zadania
for(;;)
{
if(xSemaphoreTake( xSemaphoreJoyUp, 0 ) == pdTRUE)
{
if(xSemaphoreTake(xSemaphoreMuteks, 0) == pdTRUE)
{
vhSetPWM();
vTaskDelay(500 / portTICK_RATE_MS);
xSemaphoreGive(xSemaphoreMuteks);
}
}
}
}
void vTask75PWM(void * pvParameters)
{
// Nieskonczona petla zadania
for(;;)
{
if(xSemaphoreTake( xSemaphoreJoyDown, 0 ) == pdTRUE)
{
if(xSemaphoreTake(xSemaphoreMuteks, 0) == pdTRUE)
{
vhSetPWM();
vTaskDelay(500 / portTICK_RATE_MS);
xSemaphoreGive(xSemaphoreMuteks);
}
}
}
}
w przypadku tego ostat-
niego. Dopiero podczas
tworzenia semafora
licznikowego należy
użyć innej funkcji API,
ściślej –
xSemaphore-
CreateCounting()
. Funk-
cji tej należy przekazać
dwa argumenty: pierw-
szy to maksymalna war-
tość semafora, a druga
wartość początkowa.
W omawianej aplika-
cji tworzenie semafora
odbywa się w zadaniu
vTaskSemphr()
, przed-
stawionym na
list. 6
.
W pętli nieskończonej
odczekuje 1 sekundę, po
czym sprawdza semafor
licznikowy
xSemapho-
reCnt
i wysyła do kolejki
jego wartość. Zawartość
kolejki jest odbierana przez za-
danie
vTaskLCD()
, które zajmuje
się obsługą wyświetlacza gra-
fi
cznego. Naciskając przycisk
użytkownika np. 10 razy widzi-
my na LCD, że przez czas około
10 sekund semafor będzie jesz-
cze ustawiony, a dopiero po tym czasie nastąpi
jego skasowanie.
lenie jakiegoś zasobu sprzętowego pomiędzy
kilka zadań.
Zasada działania
muteksów
została wyjaśnio-
na na
rys. 4
. Zadanie A, w chwili, gdy potrze-
buje dostępu do chronionego zasobu, sprawdza
stan
muteksa
, jeśli jest ustawiony, to wtenczas
wiadomo, że zasób jest wolny i można z niego
skorzystać. W trakcie wykorzystywania chronio-
nego zasobu przez Zadanie A
muteks
jest „
pusty
”.
Jeśli w takiej sytuacji Zadanie B podejmie próbę
skorzystania z danego zasobu to z racji „
pustego
”
muteksa
dostęp do zasobu nie będzie możliwy.
Dopiero po oddaniu
muteksa
przez Zadanie A,
Zadanie B może wykorzystać do swoich celów
chroniony zasób mikrokontrolera.
Przedstawimy teraz przykład aplikacji dzia-
łającej z wykorzystaniem
muteksów
do ochrony
zasobów. Załóżmy sytuację, w której dwa zada-
nia, jeśli zaistnieje taka potrzeba, zmieniają wy-
pełnienie generowanego przez mikrokontroler
sygnału PWM. Nowowprowadzony współczyn-
nik wypełnienia nie może się zmieniać przez
czas 500 ms, a jeśli zostanie zmieniony to może
to spowodować nieprawidłowe działanie całego
systemu. Aby zabezpieczyć timer TIM3 pracują-
cy w roli generatora PWM, przed nieuprawnio-
nym dostępem zostanie wykorzystany muteks.
W systemie uruchomione są dwa zadania:
vTask25PWM()
oraz
vTask75PWM()
. Wychylnie
joysticka na płytce ewaluacyjnej w górę powo-
duje odblokowanie pierwszego zadania i, jak
nietrudno się domyślić, zmianę współczynnika
wypełnienia sygnału PWM na 25%. Przeciwna
pozycja joysticka (w dół) odblokowuje drugie
zadania, a tym samym ustawia wypełnienie
na 75%. Generator PWM – timer TIM3 – po
pełnym przemapowaniu steruje wyprowadze-
niem PC6, a więc diodą LD1. Efektem działania
aplikacji jest zmiana intensywności świecenia
diody w takt zmian położenia joysticka. Obec-
ność w systemie pracującego
muteksa
można
zaobserwować próbę zmian położenia joysticka
z częstotliwością większą niż 1 Hz.
Muteks
chro-
niący zasób w postaci timera TIM3 nie pozwoli
na częstsze zmiany intensywności świecenia
diody LED niż co 500 ms.
Kod zadań
vTask25PWM()
i
vTask75PWM()
został zamieszczony na
list. 7
. Do synchroni-
zacji z wyprowadzeniami mikrokontrolera wy-
korzystano omówione już wcześniej semafory
binarne.
Muteks
jest tworzony w zadaniu
vTa-
sk25PWM()
za pomocą wywołania funkcji
xSe-
maphoreCreateMutex()
, jeszcze przed wejściem
zadania do pętli nieskończonej. Sprawdzenie
i próba zabrania
muteksa
odbywa się wraz z wy-
wołaniem znanej już funkcji
xSemaphoreTake()
.
Wywołanie to następuje tylko wtedy, kiedy se-
mafor
xSemaphoreJoyUp
jest aktywny, co jest
jednoznaczne z położeniem górnym joysticka.
Jeśli
muteks
jest dostępny to wtenczas wypełnie-
nie generowanego przebiegu zostanie ustawione
na 25%, w przeciwnym wypadku współczynnik
wypełnienia pozostanie niezmieniony.
Krzysztof Paprocki
paprocki.krzysztof@gmail.com
kolejki j
Rys. 3.
wego określa różnicę w liczbie wystąpień zda-
rzenia i jego przetworzeń.
Sposób implementacji semaforów liczniko-
wych prezentuje niżej omówiona przykładowa
aplikacja. Jej zadaniem jest utworzenie w sys-
temie semafora licznikowego, który ma być in-
krementowany przez przerwanie pochodzące
od wyprowadzenia PB9, do którego podłączo-
ny jest przycisk użytkownika. Proces dekre-
mentowania semafora należy do uruchomione-
go w systemie zadania
vTaskSemphr()
. Zadanie
w odstępach 1 sekundowych sprawdza stan
semafora i jeśli nie jest zerowy to go dekremen-
tuje. Dodatkowo aplikacja wykorzystuje omó-
wione poprzednio kolejki do pokazywania na
LCD wartości semafora. Schematycznie sposób
pracy mikrokontrolera w tym przykładzie ilu-
struje
rys. 3
.
Semafor licznikowy jest identycznym
typem zmiennej jak zwykły semafor binar-
ny, a więc jego deklaracja jest taka sama jak
Muteksy
Nazwa
„muteks”
jest określeniem angiel-
skim i raczej nieprzetłumaczalnym na język
polski. Słowo „
MUTEX”
powstało z połączenia
wyrazów „
mutual
” oraz „
exclusion
”. Można,
zatem mechanizm działania
muteksów
okre-
ślić jako „wzajemne wykluczanie”, które dość
dobrze oddaje istotę ich działania.
Muteksy
są
nieco podobne do binarnych semaforów, wy-
korzystują te same funkcje API, lecz zostały
wzbogacone o system priorytetów. Najistot-
niejsze jest to, że wykorzystanie semaforów
i
muteksów
jest zupełnie różne. O ile semafory,
jak już to zostało wyżej napisane, służą naj-
częściej do synchronizacji zadań, to
muteksy
zostały stworzone przede wszystkim z myślą
o implementacjach, w których występuje dzie-
Rys. 4.
ELEKTRONIKA PRAKTYCZNA 7/2009
111
Plik z chomika:
zoobee
Inne pliki z tego folderu:
Zewnętrzne pamięci statyczne i mikrokontrolery STM32.pdf
(1596 KB)
Alternatywna metoda programowania pamięci Flash mikrokontrolerów STM32.pdf
(2108 KB)
Atollic TrueSTUDIO - Sposób na mikrokontrolery STM32.pdf
(1555 KB)
Bootloader dla mikrokontrolerów STM32 - Aktualizacja oprogramowanie z zastosowaniem karty SD lub przez USB.pdf
(640 KB)
Darmowe narzędzia programowe dla mikrokontrolerów STM32.pdf
(1063 KB)
Inne foldery tego chomika:
CNC
Dokumenty
Galeria
Prywatne
zachomikowane
Zgłoś jeśli
naruszono regulamin