programy Dodatkowe materiały ISIX-RTOS na CD i FTP Podstawy obsługi wątków Dodatkowe informacje na temat systemu ISIX-RTOS oraz Artykuł poświęcony prostemu systemowi prezentacje multimedialne są dostępne na stronie www.stm32.eu operacyjnemu ISIX-RTOS, jaki opublikowaliśmy w EP3/2010, zainteresował wielu Czytelników. Wracamy więc do tego tematu, pokazując przykład jego praktycznego wykorzystania z zestawem STM32Butterfly popularną platformą sprzętową propagowaną przez firmę STMIcroelectronics podczas warsztatów STM32TechDays. Pokażemy sposób przygotowania kodu startowego dla mikrokontrolera oraz dwa wątki, które będą wykorzystane do sterowania diodami LED. Start systemu zrealizowany jest w bibliotece lib-stm32, odpo- wiedzialnej za inicjalizację systemu zgodnie z wymogami ANSI C/ C++. Przed wywołaniem globalnych konstruktorów obiektów wy- używanych przez system ISIX-RTOS (PENDSV, SVC, SYSTICK) na woływana jest funkcja __external_startup(), następnie funkcja głów- najniższy możliwy. Kolejna wywoływana funkcja isix_init jest od- na main(). powiedzialna za inicjalizację systemu, jako argument przyjmuję ona liczbę priorytetów wykorzystywanych przez scheduler. Licz- List. 1. Kod funkcji __external_startup ba dostępnych priorytetów jest dowolna (ograniczona wielkością void __external_startup(void) dostępnej pamięci), w praktyce wystarcza najczęściej kilkanaście { priorytetów. Następnie wywoływana jest funkcja timer_setup(), //Initialize system perhipheral która jest odpowiedzialna za konfigurację przerwania zegarowego uc_periph_setup(); SYSTICK, tak aby było ono generowane z częstotliwością ISIX_HZ. //1 bit for preemtion priority Wartość tej częstotliwości w przykładzie ustalono na 1000 Hz. Po nvic_priority_group(NVIC_PriorityGroup_1); wykonaniu funkcji startowej oraz wywołaniu konstruktorów glo- //System priorities balnych, wykonywana jest funkcja główna main() (list. 2). nvic_set_priority(PendSV_IRQn,1,0x7); Najpierw jest tworzony obiekt klasy ledblink, której zadaniem //System priorities jest cykliczne miganie diodą LED1 (patrz dokumentacja zestawu nvic_set_priority(SVCall_IRQn,1,0x7); STM32Butterfly), następnie obiekt klasy ledkey, której zadaniem //Set timer priority jest cykliczna zmiana stanu diody LED2 w wyniku naciśnię- nvic_set_priority(SysTick_IRQn,1,0x7); cia manipulatora joysticka. Następnie jest wywoływana funkcja //Initialize isix isix::isix_init(ISIX_NUM_PRIORITIES); List. 3. Implementacja klasy blinker //Setup the systick timer /* ------------------------------------------------------ timer_setup(); ------------ */ } //Default constructor, construct base object ledblink::ledblink():task_base(STACK_SIZE,TASK_PRIO) { //Enable PE in APB2 Kod funkcji __external_startup pokazano na list. 1. RCC->APB2ENR |= RCC_APB2Periph_GPIOE; Funkcja uc_periph_setup() jest też odpowiedzialna za konfi- io_config(LED_PORT,LED_PIN,GPIO_MODE_10MHZ,GPIO_ CNF_GPIO_PP); gurację kontrolera pamięci oraz ustawienie pętli PLL mikrokon- } trolera tak, aby rdzeń był taktowany z maksymalną dozwoloną częstotliwością (72 MHz). Następnie konfigurowany jest kontro- /* ------------------------------------------------------ ------------ */ ler przerwań NVIC, w trybie jeden bit priorytetu przerwania oraz //Main task/thread function trzy bity podpriorytetu. Dodatkowo ustalono priorytet przerwań void ledblink::main() { while(true) List. 2. główna funkcja main() { //Enable LED //App main entry point io_clr( LED_PORT, LED_PIN ); int main() //Wait time { isix::isix_wait( isix::isix_ //The blinker class ms2tick(BLINK_TIME) ); static app::ledblink led_blinker; //Disable LED //The ledkey class io_set( LED_PORT, LED_PIN ); static app::ledkey led_key; //Wait time isix::isix_wait( isix::isix_ //Start the isix scheduler ms2tick(BLINK_TIME) ); isix::isix_start_scheduler(); } } } 86 ELEKTRONIKA PRAKTYCZNA 6/2010 Podstawy obsługi wątków List. 4. Fragmenty implementacji klasy ledkey odpowiedzialnej za cykliczne miganie diodą LED1 przedstawiono /Default constructor initialize GPIO and var na list. 3. ledkey::ledkey():task_base(STACK_SIZE,TASK_PRIO),is_ enabled(false) W liście inicjalizacyjnej konstruktora wywoływany jest kon- { //Enable PE in APB2 struktor klasy bazowej task_base(), który jest odpowiedzialny za RCC->APB2ENR |= RCC_APB2Periph_GPIOE; tworzenie nowego zadania (wątku). Jako argumenty przyjmuje on io_config(LED_PORT,LED_PIN,GPIO_MODE_10MHZ,GPIO_ CNF_GPIO_PP); rozmiar stosu zadania oraz jego priorytet. W konstruktorze jest } także konfigurowany port GPIO PE.14, do którego w zestawie STM- /* ------------------------------------------------------ 32Butterfly podłączono diodę LED1. Wątek realizowany jest w pę- ------------ */ tli nieskończonej metody wirtualnej main(). Wątek zmienia stan void ledkey::main() { LED, a następnie wywołuje funkcję isix_wait(), której zadaniem //Last key state bool p_state = true; jest uśpienie wątku na czas określony przez stałą BLINK_TIME. //Task/thread main loop Najistotniejsze fragmenty implementacji klasy ledkey przed- while(true) { stawiono na list. 4. //Change state on rising edge Podobnie jak poprzednio w liście inicjalizacyjnej jest wywo- if(io_get(KEY_PORT, KEY_PIN) && !p_ state) ływany konstruktor klasy bazowej oraz inicjalizowane są porty { GPIO. Wątek odpowiedzialny za wspomniane wcześniej zadanie is_enabled = !is_enabled; } zrealizowany jest przez metodę wirtualną main() w pętli nieskoń- //Get previous state p_state = io_get(KEY_PORT, KEY_PIN); czonej. Zmiana stanu diody LED2 następuje w momencie pusz- //If enabled change state czenia manipulatora joysticka (zbocze narastające na wejściu mi- if(is_enabled) io_clr( LED_PORT, LED_PIN ); krokontrolera). Detekcję zrealizowano w sposób klasyczny przez else io_set( LED_PORT, LED_PIN ); porównanie bieżącego stanu klawisza ze stanem poprzednim. //Wait short time isix::isix_wait( isix::isix_ W momencie, gdy wykryjemy zbocze, jest zmieniany stan zmien- ms2tick(DELAY_TIME) ); nej is_enabled, następnie na podstawie stanu zmiennej dioda } } LED2 jest włączana lub wyłączana. Na koniec cyklu wywoływana jest funkcja isix_wait() z argumentem DELAY_TIME (25 ms), która isix_start_scheduler(), która powoduje uruchomienie szeregowa- usypia bieżący wątek na krótki czas, tak aby wyeliminować drga- nia zadań przez system ISIX-RTOS. Obie klasy (ledblink, ledkey) nia zestyków. dziedziczą z klasy bazowej isix::task_base. Każda klasa dziedzi- Lucjan Bryndza, Ep cząca z klasy task_base musi implementować metodę wirtualną lucck@boff.pl main(), która jest wykonywana w oddzielnym wątku tworzonym przez konstruktor klasy task_base. Implementację klasy blinker R E K L A M A ELEKTRONIKA PRAKTYCZNA 6/2010 87