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 ) );
Previous article:Camera driver learning
Next article:ARM processor base Cortex-M4
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- CGD and Qorvo to jointly revolutionize motor control solutions
- CGD and Qorvo to jointly revolutionize motor control solutions
- Keysight Technologies FieldFox handheld analyzer with VDI spread spectrum module to achieve millimeter wave analysis function
- Infineon's PASCO2V15 XENSIV PAS CO2 5V Sensor Now Available at Mouser for Accurate CO2 Level Measurement
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- A new chapter in Great Wall Motors R&D: solid-state battery technology leads the future
- Naxin Micro provides full-scenario GaN driver IC solutions
- Interpreting Huawei’s new solid-state battery patent, will it challenge CATL in 2030?
- Are pure electric/plug-in hybrid vehicles going crazy? A Chinese company has launched the world's first -40℃ dischargeable hybrid battery that is not afraid of cold
- Dissecting a small chip
- MSP430 Introduction and Software Installation
- TMS320C6748 Fixed-point and Floating-point DSP
- BlueNRG-LP sometimes cannot enter low power consumption
- 10 Tips for Writing Better Embedded Software Code
- FPGA Timing Constraints Practice: Multi-Cycle Path Constraints
- Didn’t Vicor apply for a Chinese patent?
- Engineers tell you how to do PCB design——[Worthy of collection]
- Big disaster! HP Japan accidentally deleted 77TB of important data from Kyoto University's supercomputer system
- Configuration and use of TI C2000 TMS320F28379D SCID SCIB