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