9, FreeRTOS -- idle task hook function

Keywords: stm32 FreeRTOS

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:

  1. Open macro definition configure_ IDLE_ HOOK
  2. 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

Posted by billborric on Mon, 27 Sep 2021 06:18:55 -0700