Idle task hook function
To: detailed explanation of idle task hook function
Note: the idle task hook function will also occupy cpu resources. The idle task hook function should be used reasonably
Experiment 1: continuously create tasks
Circle focus
- First, a task flag1 is created_ Task
- Task 1 created Flag2_Task, pay attention to priority flag1 here_ Task priority is 1, Flag2_ The priority of a task is 2. After it is created successfully, it can be preempted for execution. The task here is delayed
Created task Flag2_ After the task is created successfully, you commit suicide (Flag1_Task: I can save you, you can kill yourself)
Experimental results: the task will be created all the time (I'll wait here for a while to ensure the correctness of the experiment). If you want to ask me why my serial port is printed completely, yes, I increase the round robin scheduling time.
Then experiment 2
Experiment 2: continuously create tasks
Only a small change has been made here, and the task flag1_ The delay function in the task is masked
Looking at the experimental results, the task hangs after it has been created for a period of time, which is caused by insufficient stack space
So what conclusion can be drawn here? The space cleaning of tasks must be released by other tasks. The first experiment adds a delay function to have time to clean up, and the second experiment has no delay function and no time to clean up.
- Let's look at the hook function of idle tasks
Experiment 3: tasks with priority 0 can also be executed
Now I found a problem. Based on Experiment 2, I set flag1_ Flag1 will always be created when the priority task of task is 0_ The task will not fail, and there is no delay function. It proves that there is an idle task under the same priority (priority 0) to clean up the space secretly???
Transfer: explanation
Transfer: explanation
After consulting the data, an idle task function with priority 0 is created when starting the scheduler
To find the task entry function and see what you've done
static portTASK_FUNCTION( prvIdleTask, pvParameters ) { /* Stop warnings. */ ( void ) pvParameters; /** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE SCHEDULER IS STARTED. **/ for( ;; ) { /* See if any tasks have deleted themselves - if so then the idle task is responsible for freeing the deleted task's TCB and stack. */ prvCheckTasksWaitingTermination(); #if ( configUSE_PREEMPTION == 0 ) { /* If we are not using preemption we keep forcing a task switch to see if any other task has become available. If we are using preemption we don't need to do this as any task becoming available will automatically get the processor anyway. */ taskYIELD(); } #endif /* configUSE_PREEMPTION */ #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) { /* When using preemption tasks of equal priority will be timesliced. If a task that is sharing the idle priority is ready to run then the idle task should yield before the end of the timeslice. A critical region is not required here as we are just reading from the list, and an occasional incorrect value will not matter. If the ready list at the idle priority contains more than one task then a task other than the idle task is ready to execute. */ if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 ) { taskYIELD(); } else { mtCOVERAGE_TEST_MARKER(); } } #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */ #if ( configUSE_IDLE_HOOK == 1 ) { extern void vApplicationIdleHook( void ); /* Call the user defined function from within the idle task. This allows the application designer to add background functionality without the overhead of a separate task. NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK. */ vApplicationIdleHook(); } #endif /* configUSE_IDLE_HOOK */ /* This conditional compilation should use inequality to 0, not equality to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when user defined low power mode implementations require configUSE_TICKLESS_IDLE to be set to a value other than 1. */ #if ( configUSE_TICKLESS_IDLE != 0 ) { TickType_t xExpectedIdleTime; /* It is not desirable to suspend then resume the scheduler on each iteration of the idle task. Therefore, a preliminary test of the expected idle time is performed without the scheduler suspended. The result here is not necessarily valid. */ xExpectedIdleTime = prvGetExpectedIdleTime(); if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) { vTaskSuspendAll(); { /* Now the scheduler is suspended, the expected idle time can be sampled again, and this time its value can be used. */ configASSERT( xNextTaskUnblockTime >= xTickCount ); xExpectedIdleTime = prvGetExpectedIdleTime(); if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) { traceLOW_POWER_IDLE_BEGIN(); portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); traceLOW_POWER_IDLE_END(); } else { mtCOVERAGE_TEST_MARKER(); } } ( void ) xTaskResumeAll(); } else { mtCOVERAGE_TEST_MARKER(); } } #endif /* configUSE_TICKLESS_IDLE */ } }
Excuse me, excuse me, I don't understand. I probably know that an empty function declaration is provided. We can write this function ourselves, that is, we can add functions to this function, but remember what we can't do. Look at the above here and don't review - they call it hook function - how can it be called hook function? It's really interesting.
Next, let's take a look at Experiment 4. Let's use this idle task hook function
Experiment 4: idle task hook function
/** FreeRTOS v9.0.0 + STM32 Create task dynamically Experimental platform: weidongshan STM32F103ZE development board **/ #include "FreeRTOS.h" #include "task.h" #include "queue.h" /* Development board hardware bsp header file */ #include "bsp_led.h" #include "bsp_usart.h" /* task handle */ static TaskHandle_t AppTaskCreate_Handle = NULL; /* Start task handle */ static TaskHandle_t Task1_Handle = NULL; /* Task1 handle*/ static TaskHandle_t Task2_Handle = NULL; /* Task2 handle*/ /* Function declaration */ static void AppTaskCreate(void);/* Used to create the start task */ static void Flag1_Task(void* pvParameters);/* Flag1_Task Task function */ static void Flag2_Task(void* pvParameters);/* Flag2_Task Task function */ static void BSP_Init(void);/* Used to initialize onboard related resources */ /***************************************************************** * @brief Main function * @param nothing * @retval nothing * @note Step 1: development board hardware initialization Step 2: create APP application task Step 3: start FreeRTOS and start multi task scheduling ****************************************************************/ int main(void) { BaseType_t xReturn = pdPASS;/* Define a return value of creation information. The default value is pdPASS */ /* Development board hardware initialization */ BSP_Init(); printf("This is a STM32F103ZE Development board-FreeRTOS-Queue set experiment!\r\n"); /* Create AppTaskCreate task */ xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* Task entry function */ (const char* )"AppTaskCreate",/* Task name */ (uint16_t )512, /* Task stack size */ (void* )NULL,/* Task entry function parameters */ (UBaseType_t )2, /* Priority of task */ (TaskHandle_t* )&AppTaskCreate_Handle);/* Task control block pointer */ /* Start task scheduling */ if(pdPASS == xReturn) vTaskStartScheduler(); /* Start task and start scheduling */ else return -1; while(1); /* Normal will not be executed here */ } /*********************************************************************** * @ Function name: AppTaskCreate * @ Function Description: to facilitate management, all task creation functions are placed in this function * @ Parameter: None * @ Return value: None **********************************************************************/ static void AppTaskCreate(void) { BaseType_t xReturn = pdPASS;/* Define a return value of creation information. The default value is pdPASS */ taskENTER_CRITICAL(); //Enter critical zone /* Create Flag1_Task */ xReturn = xTaskCreate((TaskFunction_t )Flag1_Task, /* Task entry function */ (const char* )"Flag1_Task",/* Task name */ (uint16_t )512, /* Task stack size */ (void* )NULL, /* Task entry function parameters */ (UBaseType_t )1, /* Priority of task */ (TaskHandle_t* )&Task1_Handle);/* Task control block pointer */ if(pdPASS == xReturn) printf("establish Flag1_Task Mission success!\r\n"); // /*Create Flag2_Task*/ // Xreturn = xtaskcreate ((taskfunction_t) flag2_task, / * task entry function*/ // (const char *) "flag2_task", / * task name*/ // (uint16_t) 512, / * task stack size*/ // (void* )NULL, /* Task entry function parameters*/ // (UBaseType_t )2, /* Priority of task*/ // (TaskHandle_t* )&Task2_Handle);/* Task control block pointer*/ // if(pdPASS == xReturn) // printf("flag2#u task created successfully! \ r\n"); vTaskDelete(NULL); //Delete AppTaskCreate task // vTaskDelete(AppTaskCreate_Handle); // Delete apptaskcreate task taskEXIT_CRITICAL(); //Exit critical zone } /********************************************************************** * @ Function name: LED_Task * @ Function Description: LED_Task subject ********************************************************************/ uint8_t flag1; uint8_t flag2; uint8_t IdleHook; /*Task 1 continuously creates task 2, which consumes stack space*/ static void Flag1_Task(void* parameter) { static int xReturn; while (1) { flag1=1; flag2=0; IdleHook=0; xReturn = xTaskCreate(Flag2_Task, /* Task entry function */ "Flag2_Task", /* Task name */ 64, /* Task stack size */ NULL, /* Task entry function parameters */ 2, /* Priority of task */ &Task2_Handle); /* Task control block pointer */ if(pdPASS == xReturn) printf("establish Flag2_Task Mission success!\r\n"); else printf("establish Flag2_Task Task failed!\r\n"); vTaskDelay(1); /* Delay 1 tick */ } } /*Task 2 constantly delete itself*/ static void Flag2_Task(void* parameter) { while (1) { flag1=0; flag2=1; IdleHook=0; printf("Flag2_Task running!\r\n"); vTaskDelete(NULL);/*commit suicide*/ printf("Has committed suicide,If I can print, I'll pretend to be a corpse!\r\n"); //vTaskDelay(1); /* Delay 1 tick*/ } } /*Idle task hook function, run hook function to clean up garbage space*/ void vApplicationIdleHook( void ) { flag1=0; flag2=0; IdleHook=1; printf("IdleHook running!\r\n"); } /*********************************************************************** * @ Function name: BSP_Init * @ Function Description: board level peripheral initialization. Initialization on all boards can be placed in this function * @ Parameters: * @ Return value: None *********************************************************************/ static void BSP_Init(void) { /* * STM32 The interrupt priority group is 4, that is, 4 bits are used to represent the preemption priority, ranging from 0 to 15 * Priority grouping only needs to be grouped once. If other tasks need interrupts in the future, * Use this priority group uniformly. Do not group again. Avoid by all means. */ NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); /* LED initialization */ LED_GPIO_Config(); /* Serial port initialization */ USART_Config(); } /********************************END OF FILE****************************/
Before using the hook function, you can see that you need to turn on a macro definition switch to use it
configUSE_ IDLE_ Hook function is valid when hook = 1
Prerequisites for running hook function:
- Open macro definition configure_ IDLE_ HOOK
- The task priority of the hook function is 0. You have to consider making the task with priority 0 execute.
Do not understand the current experimental source code
Running effect (a little messy, but you can see that the hook function is running)
It's almost ten o'clock. Go back to the dormitory
Git warehouse source code address: https://gitee.com/he-dejiang/free-rtos.git