FreeRTOS Lab 2: 走訪 Tasklist 並實作 task monitor

Posted by blueskyson on April 17, 2022

環境: wnidows 10, STM32CubeIDE 1.8.0

開發板: stm32f407g

環境設定

參照 在 stm32f407g 使用 uart設置好 uart4。

接下來編輯 .ioc 檔案

  • PD12PD15 設為 GPIO_Output,Label 設為 led_greenled_orangeled_redled_blue

接下來設置好 FreeRTOS 的執行環境,因為網路很多教學,例如這篇,所以就不贅述。

Lab 目標

走訪 pxReadyTasksListspxDelayedTaskListpxOverflowDelayedTaskList,並且透過 uart4 印出所有 task control block 的資訊。

TaskList 的資料結構為 Linked List,示意圖如下:

對應的宣告在 list.h

Task Control Block 的資料結構宣告在 tasks.ctskTaskControlBlock

撰寫主程式

在 task.h 的最後面引入必要的函式庫,宣告 Taskmonitor() 作為印出 task control block 的資訊的函式:

1
2
3
4
5
#include "stm32f4xx_hal.h"
#include <string.h>
#include <stdio.h>
UART_HandleTypeDef huart4;
void Taskmonitor(void);

在 tasks.c 的最後面實作 Taskmonitor()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void print_pcb(tskTCB *t, char *state) {
	char Monitor_data[130];
	memset(Monitor_data,'\0',sizeof(Monitor_data));
	sprintf(Monitor_data, "%-19s %3lu/%-19lu 0x%-9lx 0x%-14lx %s\n\r",
            t->pcTaskName, t->uxPriority, t->uxBasePriority, t->pxStack, t->pxTopOfStack, state);
	HAL_UART_Transmit(&huart4, (uint8_t *)Monitor_data, strlen(Monitor_data), HAL_MAX_DELAY);
}

void Taskmonitor(void)
{
	/* Stop scheduler */
	/* Taskmonitor() will block when UART is transmitting data */
	vTaskSuspendAll();

	/* Print title */
    char *Monitor_data = "|Name              |Priority(Base/actual)  |pxStack    |pxTopOfStack    |State    |\n\r";
	HAL_UART_Transmit(&huart4, (uint8_t *)Monitor_data, strlen(Monitor_data), HAL_MAX_DELAY);

	ListItem_t *node;
	/* pxReadyTasksLists */
	for (int i = 0; i < configMAX_PRIORITIES; i++) {
		node = listGET_HEAD_ENTRY(pxReadyTasksLists + i);
		for (uint32_t j = 0; j < listCURRENT_LIST_LENGTH(pxReadyTasksLists + i); j++) {
			print_pcb(listGET_LIST_ITEM_OWNER(node), "Ready");
			node = listGET_NEXT(node);
		}
	}

	/* pxDelayedTaskList*/
	node = listGET_HEAD_ENTRY(pxDelayedTaskList);
	for (uint32_t j = 0; j < listCURRENT_LIST_LENGTH(pxDelayedTaskList); j++) {
		print_pcb(listGET_LIST_ITEM_OWNER(node), "Blocked");
		node = listGET_NEXT(node);
	}

	/* pxOverflowDelayedTaskList */
	node = listGET_HEAD_ENTRY(pxOverflowDelayedTaskList);
	for (uint32_t j = 0; j < listCURRENT_LIST_LENGTH(pxOverflowDelayedTaskList); j++) {
		print_pcb(listGET_LIST_ITEM_OWNER(node), "Overflow");
		node = listGET_NEXT(node);
	}

	/* Resume scheduler */
	xTaskResumeAll();
}

編輯 Core/Src/main.c,引入標頭檔:

1
2
3
4
/* USER CODE BEGIN Includes */
#include "FreeRTOS.h"
#include "task.h"
/* USER CODE END Includes */

撰寫 Red_LED_AppGreen_LED_AppDelay_AppTaskMonitor_App

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/* USER CODE BEGIN 0 */
TaskHandle_t xHandle=NULL;

void Red_LED_App(void *pvParameters){
	uint32_t Redtimer = 800;
	for(;;){
		HAL_GPIO_TogglePin(GPIOD, led_red_Pin);
		vTaskDelay(Redtimer);
		Redtimer+=1;
	}
}

void Green_LED_App(void *pvParameters){
	uint32_t Greentimer = 1000;
	for(;;){
		HAL_GPIO_TogglePin(GPIOD, led_green_Pin);
		vTaskDelay(Greentimer);
		Greentimer+=2;
	}
}

void Delay_App(void *pvParameters){
	int delayflag=0;
	uint32_t delaytime;
	while(1){
		if(delayflag==0){
			delaytime = 1000;
			delayflag=1;
		}else{
			delaytime=0xFFFFFFFF;
		}
		vTaskDelay(delaytime);
	}
}

void TaskMonitor_App(void *pvParameters){
	for(;;){
		Taskmonitor();
		vTaskDelay(1000);
	}
}
/* USER CODE END 0 */

最後在 main() 函式創建這四個 App 讓 FreeRTOS 排程,注意 TaskMonior_App 的 Stack Size 要夠大才夠 sprintf 處理字串:

1
2
3
4
5
6
7
/* USER CODE BEGIN 2 */
xTaskCreate(Red_LED_App, "Red_LED_App", 128, NULL, 1, &xHandle);
xTaskCreate(Green_LED_App, "Green_LED_App", 128, NULL, 1, &xHandle);
xTaskCreate(TaskMonitor_App, "TaskMonitor_App", 512, NULL, 3, &xHandle);
xTaskCreate(Delay_App, "Delay_App", 128, NULL, 14, &xHandle);
vTaskStartScheduler();
/* USER CODE END 2 */

Demo