środa, 4 lipca 2018

[25] STM32F7 - FreeRtos - Kolejka

W tym poście opiszę zastosowanie mechanizmu kolejki w systemie FreeRTOS oraz mikrokontrolerze STM32F7.

[Źródło: http://www.st.com/en/evaluation-tools/32f746gdiscovery.html]


Kolejka jest wykorzystywana do wymiany informacji pomiędzy zadaniami. Można ją wykorzystać do przysyłania wiadomości pomiędzy zadaniami czy przerwaniami a zadaniami. Najczęściej są one wykorzystywane jako bufory FIFO.

Na zdefiniowaną kolejkę składa się jej długość oraz rozmiar pojedynczego elementu jaki może zostać wpisany. Każdy element jaki jest umieszczany w kolejce jest kopią danych źródłowych. Oznacza to, że zadania nie mogą bezpośrednio uzyskać dostępu do pamięci. Mechanizm kolejek posiada obsługę zagadnień związanych z wzajemnymi wykluczeniami.

Stworzenie kolejki pozwalającej na wymianę informacji pomiędzy poszczególnymi zadaniami można wykonać następującą funkcją:

  1. osMessageQDef(name, queue_sz, type);

Tworzy atrybuty wiadomości, do parametrów wprowadza się nazwę kolejki, jej wielkość, oraz typ danych pojedynczego elementu.

  1. osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id);

Funkcja pozwala na uruchomienie kolejki. W argumentach podawana jest nazwa kolejki oraz wątek odpowiedzialny za obsługę danych. Jeśli nie ma żadnego wątku zdefiniowanego to w argumencie podawana jest wartość NULL.

Teraz tworzę dwa zadania które będą wymiały dane między sobą oraz jedno wykonujące inne zadanie:

  1. osThreadDef(defaultTask, reciveDataQue, osPriorityNormal, 0, 128);
  2. defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
  3.  
  4. osThreadDef(myTask02, sendDataToQue, osPriorityIdle, 0, 128);
  5. myTask02Handle = osThreadCreate(osThread(myTask02), NULL);
  6.  
  7. osThreadDef(myTask03, StartTask03, osPriorityIdle, 0, 128);
  8. Task03Handle = osThreadCreate(osThread(myTask03), NULL);
  9.  
  10. osMessageQDef(myQueue01, 32, uint32_t);
  11. queueHandle = osMessageCreate(osMessageQ(myQueue01), NULL);


Funkcja wyświetlająca informacje na ekranie:

  1. void StartTask03(void const * argument)
  2. {
  3.     for(;;)
  4.     {
  5.         ROCKTECH_DisplayString(120, 230, (uint8_t *)"      ", LEFT_MODE);
  6.         ROCKTECH_DisplayString(120, 200, (uint8_t *)"Task3", LEFT_MODE);
  7.         HAL_Delay(2000);
  8.         ROCKTECH_DisplayString(120, 200, (uint8_t *)"      ", LEFT_MODE);
  9.         ROCKTECH_DisplayString(120, 230, (uint8_t *)"Task2", LEFT_MODE);
  10.         HAL_Delay(2000);
  11.     }
  12. }

Teraz funkcje wymieniające się danymi. Najpierw wprowadzanie danych do kolejki:

  1. void sendDataToQue(void const * argument)
  2. {
  3.     char displayBuffer[15];
  4.  
  5.     for(;;)
  6.     {
  7.         newData.exchangeData++;
  8.         sprintf(displayBuffer, "Que write = %lu", newData.exchangeData);
  9.  
  10.         ROCKTECH_DisplayString(120, 100, (uint8_t *)displayBuffer, LEFT_MODE);
  11.  
  12.         osMessagePut(queueHandle, newData.exchangeData, 500);
  13.         osDelay(100);
  14.     }
  15. }

Odczytywanie danych z kolejki:

  1. void reciveDataQue(void const * argument)
  2. {
  3.     osEvent evt;
  4.     for(;;)
  5.     {
  6.         char displayBuffer[15];
  7.         evt = osMessageGet(queueHandle, 1000);
  8.  
  9.         if(evt.status == osEventMessage)
  10.         {
  11.             sprintf(displayBuffer, "Data rec: = %lu", evt.value.p);
  12.             TFT_DisplayString(120, 50, (uint8_t *)buffer, LEFT_MODE);
  13.         }
  14.         else
  15.         {
  16.             TFT_DisplayString(120, 50, (uint8_t *)"Failed", LEFT_MODE);
  17.         }
  18.         osDelay(1);
  19.   }
  20. }

Kolejka jest tworzona przez wywołanie funkcji:

  1. osMailQId osMailCreate (const osMailQDef_t *queue_def, osThreadId thread_id)

Tutaj podobnie jak poprzednio możliwa jest wymiana informacji pomiędzy wątkami. Różnica polega na tym, że wcześniejszy przykład może jedynie przesłać wskaźnik lub 32 bitową wartość. W tym przypadku wykorzystywane są przygotowane bloki danych do których przekazywany jest wskaźnik. Dane przechowywane są w jednym bloku, natomiast wskaźnik jest przesyłany pomiędzy wątkami.

Tworzenie kolejki wygląda następująco:

  1. osMailQDef(mailQueue, QUEUE_SIZE, dataStructure_t);
  2. mailQueue = osMailCreate(osMailQ(mailQueue), NULL);

Dane do poszczególnych zadań przechowuję w strukturze opisanej w poprzedniej poście (FreeRtos - Zadania):

  1. typedef struct taskStruct{
  2.   char taskName[10];
  3.   taskFuncPointer taskFunct;
  4.   osPriority priority;
  5.   uint8_t instances;
  6.   uint16_t stackSize;
  7.   uint16_t screenPosi_y;
  8.   uint16_t delayTime;
  9. }taskStruct_t;

Wobec tego stworzone zadania będą wyglądały następująco:

  1. osThreadDef(taskNorm1, task1_Definition.taskFunct, task1_Definition.priority, task1_Definition.instances, task1_Definition.stackSize);
  2. Task01Handle = osThreadCreate(osThread(taskNorm1), (void*)&task1_Definition);
  3.  
  4. osThreadDef(taskNorm2, task2_Definition.taskFunct, task2_Definition.priority, task2_Definition.instances, task2_Definition.stackSize);
  5. Task02Handle = osThreadCreate(osThread(taskNorm2), (void*)&task2_Definition);
  6.  
  7. osThreadDef(taskNorm3, task3_Definition.taskFunct, task3_Definition.priority, task3_Definition.instances, task3_Definition.stackSize);
  8. Task03Handle = osThreadCreate(osThread(taskNorm3), (void*)&task3_Definition);
  9.  
  10. osThreadDef(taskNorm4, task4_Definition.taskFunct, task4_Definition.priority, task4_Definition.instances, task4_Definition.stackSize);
  11. Task04Handle = osThreadCreate(osThread(taskNorm4), (void*)&task4_Definition);
  12.  
  13. osThreadDef(taskNorm5, task5_Definition.taskFunct, task5_Definition.priority, task5_Definition.instances, task5_Definition.stackSize);
  14. Task05Handle = osThreadCreate(osThread(taskNorm5), (void*)&task5_Definition);

Do obsługi zdarzeń wykorzystuje dwie funkcje:

  1. void TaskPut(void const * argument)
  2. {
  3.     volatile taskStruct_t *taskStructPtr;
  4.     taskStructPtr = (taskStruct_t*) argument;
  5.     uint8_t i = 0;
  6.  
  7.     dataStructure_t *dataStructPointer;
  8.  
  9.     for(;;)
  10.     {
  11.         dataStructPointer = osMailAlloc(mailQueue, 1000);
  12.  
  13.         if(i==0)
  14.         {
  15.             dataStructPointer->screenPosition = 0;
  16.             dataStructPointer->countSystemTick = 0;
  17.             dataStructPointer->someCounter = 0;
  18.             i++;
  19.         }
  20.  
  21.         dataStructPointer->someCounter += 1;
  22.         dataStructPointer->countSystemTick = osKernelSysTick();
  23.         dataStructPointer->screenPosition = taskStructPtr->screenPosi_y;
  24.  
  25.         sprintf(dataStructPointer->displayDataBuffer, "%s %d", taskStructPtr->taskName, osThreadGetPriority(NULL));
  26.         osMailPut(mailQueue, dataStructPointer);
  27.     }
  28. }

Funkcja TaskPut wprowadza dane do kolejki na początku alokowane jest blok danych przechowujący strukturę. Drugi parametr jest to czas oczekiwania w milisekundach. W przypadku jego pominięcia timeout nie jest wykorzystywany. Dalej wprowadzane są dane do elementów struktury. Na końcu wprowadzane są dane do kolejki. 

  1. void TaskStringOut(void const * argument)
  2. {
  3.     osEvent event;
  4.     dataStructure_t *dataStructPointer;
  5.  
  6.     ROCKTECH_SetTextColor(LCD_COLOR_BLUE);
  7.  
  8.     for(;;)
  9.     {
  10.         char displayData[40];
  11.         event = osMailGet(mailQueue, osWaitForever);
  12.         if (event.status == osEventMail)
  13.         {
  14.             dataStructPointer = event.value.p;
  15.             sprintf(displayData,"%s %lu %lu",
  16.                     dataStructPointer->displayDataBuffer,
  17.                     dataStructPointer->countSystemTick,
  18.                     dataStructPointer->someCounter);
  19.             ROCKTECH_DisplayString(20, dataStructPointer->screenPosition, (uint8_t *)displayData, LEFT_MODE);
  20.         }
  21.     }
  22. }

Bibliografia:


[1] STM32 - Free RTOS dla dociekliwych
[2] Wbudowane systemy czasy rzeczywistego