środa, 20 czerwca 2018

[25] STM32F7 - FreeRtos - Zadania

W tym poście chciałbym opisać sposób przygotowania przykładowej aplikacji pozwalającej

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


Na samym początku przykład tworzący nowe zadania wraz z priorytetami. Należy pamiętać o tym, że zadania można przypisać w dowolnym momencie działania programu.

Każde z zadań może znajdować w jednym z czterech stanów (Running, Ready, Blocked and Suspended). W stanie Running może znajdować się tylko jedno zadanie. Jeśli chodzi o stan Ready, to kolejność wywołania kilku zadań w tym stanie jest określana przez ich priorytety.

Aby stworzyć zadania należy wywołać następującą instrukcje:

Na samym początku tworzymy domyślne zadanie które będzie wykonywane ciągiem:

  1. void createDefaultTask()
  2. {
  3.     osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 1280);
  4.     defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
  5. }

Ma ono najwyższy z priorytetów przydzielonych pozostałym zadaniom. W nim odbywają się główne zadania przydzielone zadaniom.

Dalej uruchomienie głównych zadań:

  1. void createAllTask(void)
  2. {
  3.     defineDataForAllTasks();
  4.     osThreadDef(vtsk1, task1_Propert.taskFunct,
  5.                         task1_Propert.priority,
  6.                         task1_Propert.instances,
  7.                         task1_Propert.stackSize);
  8.     Task1_Handle = osThreadCreate(osThread(vtsk1), (void*)&task1_Propert);
  9.     osThreadDef(vtsk2, task2_Propert.taskFunct,
  10.                         task2_Propert.priority,
  11.                         task2_Propert.instances,
  12.                         task2_Propert.stackSize);
  13.     Task2_Handle = osThreadCreate(osThread(vtsk2), (void*)&task2_Propert);
  14.     osThreadDef(vtsk3, task3_Propert.taskFunct,
  15.                         task3_Propert.priority,
  16.                         task3_Propert.instances,
  17.                         task3_Propert.stackSize);
  18.     Task3_Handle = osThreadCreate(osThread(vtsk3), (void*)&task3_Propert);
  19.     osThreadDef(vtsk4, task4_Propert.taskFunct,
  20.                         task4_Propert.priority,
  21.                         task4_Propert.instances,
  22.                         task4_Propert.stackSize);
  23.     Task4_Handle = osThreadCreate(osThread(vtsk4), (void*)&task4_Propert);
  24. }

Parametry dla nich definiowane są w strukturze:

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

Wszystkie zadania z zdefiniowanymi parametrami wyglądają następująco:

  1. taskStruct_t task1_Propert =
  2. {
  3.         .taskName = "task1",
  4.         .taskFunct = task1Function,
  5.         .priority = osPriorityIdle,
  6.         .instances = 0,
  7.         .stackSize = 128,
  8.         .screenPosi_y = 60,
  9.         .delayTime = 1000
  10. };
  11. taskStruct_t task2_Propert  =
  12. {
  13.         .taskName = "task2",
  14.         .taskFunct = task2Function,
  15.         .priority = osPriorityIdle,
  16.         .instances = 0,
  17.         .stackSize = 128,
  18.         .screenPosi_y = 110,
  19.         .delayTime = 677
  20. };
  21. taskStruct_t task3_Propert =
  22. {
  23.         .taskName = "task3",
  24.         .taskFunct = task3Function,
  25.         .priority = osPriorityLow,
  26.         .instances = 0,
  27.         .stackSize = 128,
  28.         .screenPosi_y = 160,
  29.         .delayTime = 439
  30. };
  31. taskStruct_t task4_Propert =
  32. {
  33.         .taskName = "task4",
  34.         .taskFunct = task4Function,
  35.         .priority = osPriorityBelowNormal,
  36.         .instances = 0,
  37.         .stackSize = 128,
  38.         .screenPosi_y = 210,
  39.         .delayTime = 329
  40. };

Każde zadanie ma osobne funkcje obsługujące. Poniżej przykładowa obsługa dla zadania nr 1:

  1. void task1Function(void const * task1Structure)
  2. {
  3.   volatile taskStruct_t *pointer;
  4.   char displayString[60];
  5.   pointer = (taskStruct_t*)task1Structure;
  6.   for(;;)
  7.   {
  8.     ROCKTECH_SetTextColor(LCD_COLOR_RED);
  9.     sprintf(displayString,"%lu %s %d ", countTask1Enable, pointer->taskName, osThreadGetPriority(NULL));
  10.     ROCKTECH_DisplayString(30, pointer->screenPosi_y, (uint8_t *)displayString, LEFT_MODE);
  11.     countTask1Enable++;
  12.     osDelay(pointer->delayTime);
  13.   }
  14. }

Tutaj ustawiane są parametry z danymi do struktury, następnie w głównej pętli która jest wywoływana co zadane opóźnienie wyświetlana jest informacja o zadaniu, wraz z ilością jego uruchomienia przechowywanego w zmiennej countTask1Enable.

Jeśli chcemy dynamicznie zmieniać priorytety danego zadania to należy wykorzystać funkcje osThreadSetPriority. W nim podawany jest uchwyt do danego zadania wraz z nowym priorytetem:

  1. osThreadSetPriority(Task1_Handle,osPriorityHigh);

Aby uruchomić w projekcie zadanie domyślne oraz 5 zadać zwykłych należy w funkcji main wywołać następujące elementy:

  1. Task_createDefault();
  2. Task_createMyTask();
  3. createAllTask();
  4. /* Start scheduler */
  5. osKernelStart();
  6. while(1) {}
  7. }

Elementy do projektu można pobrać z dysku Google pod tym linkiem.