FreeRTOS task source code analysis and the relationship between program stack and task stack

Publisher:平凡的梦想Latest update time:2024-07-10 Source: elecfansKeywords:FreeRTOS Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

In the previous article, we learned about the operations of ARM function calls and returns, but we didn’t know much about the task stack under the operating system and the stack switching when switching tasks. Therefore, we first analyzed the source code of the task, including the process of creating the stack when creating the task, and the task scheduling process. Later, we found that after this analysis was clear, we could also sort out the program stack and the task stack, so we continued to sort out the relationship between the program stack and the task stack.


Taking the STM32F4x7_ETH_LwIP_V1.1.1 project as an example, the version used is FreeRTOSV7.3.0.


The startup task in STM32F4x7_ETH_LwIP_V1.1.1ProjectFreeRTOSudptcp_echo_server_netconnsrcmain.c is as follows


1 int main(void)

2 {

3  /* Configures the priority grouping: 4 bits pre-emption priority */

4   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

5

6   /* Init task */

7   xTaskCreate(Main_task, (int8_t *)"Main", configMINIMAL_STACK_SIZE * 2, NULL,MAIN_TASK_PRIO, NULL);

8

9   /* Start scheduler */

10 vTaskStartScheduler();

11

12   /* We should never get here as control is now taken by the scheduler */

13   for( ;; );

14 }


In main, a main task or startup task is usually started, and then task scheduling is started. In the main task, other tasks are created. (Why do we need this mode? Isn't it possible to create all tasks directly in main and then start task scheduling?)


The task control block TCB, the first member is the top address of the task stack, and line 17 indicates the start of the task stack (the stack is like a bucket, the bottom of the bucket is the high address, the top of the bucket is the low address, the bottom of the bucket is the "start of the task stack" pxStack, and the last data position in the bucket is the "top address of the task stack" pxTopOfStack).


xGenericListItem is a list member used to string tasks into a list. When the task is subsequently added to the ready task list or other task lists, the list member is inserted into the task list.


xEventListItem is used to record whether the task is waiting for an event, such as whether data is sent to the queue but the queue is full, whether data is read from the queue but the queue is empty, and a waiting time or infinite waiting is set. For example, if data is sent to the queue but the queue is full, the xEventListItem of the task will be inserted into the xTasksWaitingToSend list of the queue; at the same time, the xGenericListItem will be deleted from the ready task list and inserted into the suspended task queue (if the waiting time is infinite) or the delayed task queue (if the waiting time is limited) (this process is completed by vTaskPlaceOnEventList). If the queue is not full, the task's xEventListItem will be removed from xTasksWaitingToSend; at the same time, the task's xGenericListItem will be removed from the suspended task queue or the delayed task queue and added to the ready queue (this process is completed by xTaskRemoveFromEventList).


1 /*

2  * Task control block.  A task control block (TCB) is allocated for each task,

3  * and stores task state information, including a pointer to the task's context

4  * (the task's run time environment, including register values)

5  */

6 typedef struct tskTaskControlBlock

7 {

8     volatile portSTACK_TYPE    *pxTopOfStack;        /*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */

9

10     #if ( portUSING_MPU_WRAPPERS == 1 )

11         xMPU_SETTINGS xMPUSettings;                /*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */

12     #endif

13

14     xListItem                xGenericListItem;        /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */

15     xListItem                xEventListItem;        /*< Used to reference a task from an event list. */

16     unsigned portBASE_TYPE    uxPriority;            /*< The priority of the task.  0 is the lowest priority. */

17     portSTACK_TYPE            *pxStack;            /*< Points to the start of the stack. */

18     signed char                pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */

19

20     #if ( portSTACK_GROWTH > 0 )

21         portSTACK_TYPE *pxEndOfStack;            /*< Points to the end of the stack on architectures where the stack grows up from low memory. */

22     #endif

23

24     #if ( portCRITICAL_NESTING_IN_TCB == 1 )

25         unsigned portBASE_TYPE uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */

26     #endif

27

28     #if ( configUSE_TRACE_FACILITY == 1 )

29         unsigned portBASE_TYPE    uxTCBNumber;    /*< Stores a number that increments each time a TCB is created.  It allows debuggers to determine when a task has been deleted and then recreated. */

30         unsigned portBASE_TYPE  uxTaskNumber;    /*< Stores a number specifically for use by third party trace code. */

31     #endif

32

33     #if ( configUSE_MUTEXES == 1 )

34         unsigned portBASE_TYPE uxBasePriority;    /*< The priority last assigned to the task - used by the priority inheritance mechanism. */

35     #endif

36

37     #if ( configUSE_APPLICATION_TASK_TAG == 1 )

38         pdTASK_HOOK_CODE pxTaskTag;

39     #endif

40

41     #if ( configGENERATE_RUN_TIME_STATS == 1 )

42         unsigned long ulRunTimeCounter;            /*< Stores the amount of time the task has spent in the Running state. */

43     #endif

44

45 } tskTCB;


Task creation

Let's look at the task creation function. xTaskCreate actually calls xTaskGenericCreate.


E:projectrtosSTM32F4x7_ETH_LwIP_V1.1.1UtilitiesThird_PartyFreeRTOSV7.3.0includetask.h


1 #define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )

E:projectrtosSTM32F4x7_ETH_LwIP_V1.1.1UtilitiesThird_PartyFreeRTOSV7.3.0tasks.c,486


View Code

Allocate TCB and stack space

1     /* Allocate the memory required by the TCB and stack for the new task,

2     checking that the allocation was successful. */

3     pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );

Line 9 first allocates TCB space. Line 11, TCB allocation is successful, and then the stack space is allocated. Line 16 allocates a stack of input parameters * 4 bytes and assigns it to "task stack start" pxStack. If the allocation is successful, then line 27 will initialize the stack to a fill pattern, which is 0xa5 here.


1 /*-----------------------------------------------------------*/

2

3 static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )

4 {

5 tskTCB *pxNewTCB;

6

7     /* Allocate space for the TCB.  Where the memory comes from depends on

8     the implementation of the port malloc function. */

9     pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );

10

11     if( pxNewTCB != NULL )

12     {

13         /* Allocate space for the stack used by the task being created.

14         The base of the stack memory stored in the TCB so the task can

15         be deleted later if required. */

16         pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );

17

18         if( pxNewTCB->pxStack == NULL )

19         {

20             /* Could not allocate the stack.  Delete the allocated TCB. */

21             vPortFree( pxNewTCB );

22             pxNewTCB = NULL;

23         }

24         else

25         {

26             /* Just to help debugging. */

27             memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( portSTACK_TYPE ) );

28         }

29     }

30

31     return pxNewTCB;

32 }


task.c, 204, the defined stack filling pattern is a5, which is only used to detect the high address watermark of the task.


1 /*

2  * The value used to fill the stack of a task when the task is created.  This

3  * is used purely for checking the high water mark for tasks.

4  */

5 #define tskSTACK_FILL_BYTE    ( 0xa5U )

Pointer to the top of the computation task stack

Line 5 will calculate according to the direction of stack generation. For arm stack, it grows downwards, and the allocated pxStack is at a low address. Therefore, in line 7, the top of the stack is pxStack + depth - 1 (-1 is because it is a full stack, and the stack pointer points to the last data). Line 8 will perform alignment, because ARM is 4-byte aligned, so this sentence will not change the address.


1         /* Calculate the top of stack address.  This depends on whether the

2         stack grows from high memory to low (as per the 80x86) or visa versa.

3         portSTACK_GROWTH is used to make the result positive or negative as

4         required by the port. */

5         #if( portSTACK_GROWTH < 0 )

6         {

7             pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 );

8             pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK  ) );

9

10             /* Check the alignment of the calculated top of stack is correct. */

11             configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

[1] [2] [3] [4] [5]
Keywords:FreeRTOS Reference address:FreeRTOS task source code analysis and the relationship between program stack and task stack

Previous article:Camera driver learning
Next article:ARM processor base Cortex-M4

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号