跳至主要内容

Cortex-M3 FreeRTOS PendSV任务切换机制

. Cortex-M3 FreeRTOS PendSV Task Switching Mechanism




vListInitialise

.

 typedef struct xLIST
 {
     volatile UBaseType_t uxNumberOfItems;
     ListItem_t * configLIST_VOLATILE pxIndex;
     MiniListItem_t xListEnd;
 } List_t;
 
 struct xLIST_ITEM
 {
     configLIST_VOLATILE TickType_t xItemValue;
     struct xLIST_ITEM * configLIST_VOLATILE pxNext;
     struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
     void * pvOwner;
     struct xLIST * configLIST_VOLATILE pxContainer;
 };
 
 typedef struct xLIST_ITEM ListItem_t;
 typedef struct xLIST_ITEM MiniListItem_t;
 
 
 void vListInitialise( List_t * const pxList )
 {
     /* The list structure contains a list item which is used to mark the
      * end of the list. To initialise the list the list end is inserted
      * as the only list entry. */
     pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
 
     /* The list end value is the highest possible value in the list to
      * ensure it remains at the end of the list. */
     pxList->xListEnd.xItemValue = portMAX_DELAY;
 
     /* The list end next and previous pointers point to itself so we know
      * when the list is empty. */
     pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
     pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
 
     pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
 }

.

字节[24:21][23:20][19:16][15:12][11:8][7:4][3:0]
基地址偏移+ C+ 8+ 4+ 0
变量名pxContainerpvOwnerpxPreviouspxNextxItemValuepxIndexuxNumberOfItems

.

 ; 无优化 -O0
 ; void __fastcall vListInitialise(List_t *const pxList)
     SUB      sp,sp,#4 ;栈减1,存放局部变量temp1
     STR      r0,[sp,#0] ;将R0值存放到temp1(即 pxList)
     ;
     LDR      r1,[sp,#0] ;令R1 = temp1
     ADD      r0,r1,#8 ;令R0 = R1 + 8
     STR      r0,[r1,#4] ;将R0值保存到(R1 + 4)的地址中
     LDR      r1,[sp,#0] ;
     
     ;
     ; pxList->xListEnd.xItemValue = portMAX_DELAY;
     MOV      r0,#0xffffffff
     STR      r0,[r1,#8]
     
     LDR      r1,[sp,#0]
     ADD      r0,r1,#8
     STR      r0,[r1,#0xc]
     LDR      r1,[sp,#0]
     ADD      r0,r1,#8
     STR      r0,[r1,#0x10]
     LDR      r1,[sp,#0]
     ; pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
     MOVS     r0,#0
     STR      r0,[r1,#0]
     ;
     ADD      sp,sp,#4
     BX       lr
     MOVS     r0,r0
     
 ; 最大优化 -Ofast
 ; void __fastcall vListInitialise(List_t *const pxList)
 
     MOV      r1,#0xffffffff ;令R0 = 0xffffffff
     MOV      r2,r0 ;将R2赋值pxList地址
     
     STR      r1,[r2,#8]! ;将R1的值保存到(R2 + 8)的地址中
     MOVS     r1,#0 ;令R1为0
     STR      r2,[r0,#4] ;将R2保存到(R0+4)地址中
     
     STRD     r2,r2,[r0,#0xc] ;将R2分别保存到地址(R0 + 0xC)和(R0 + 0xC + 4)中
     STR      r1,[r0,#0] ;将R1保存到(R0)地址中
     
     BX       lr ;返回
     MOVS     r0,r0 ;

SVC_Handler

.

 typedef struct tskTaskControlBlock 
 {
     volatile StackType_t * pxTopOfStack;
     ListItem_t xStateListItem;
     ListItem_t xEventListItem;
     UBaseType_t uxPriority;
     StackType_t * pxStack;
     char pcTaskName[ configMAX_TASK_NAME_LEN ];
 } tskTCB;

.

Stack Pointer

The Stack Pointer (SP) is register R13. In Thread mode, bit[1] of the CONTROL register indicates the stack pointer to use:

  • 0 = Main Stack Pointer (MSP). This is the reset value.

  • 1 = Process Stack Pointer (PSP).

On reset, the processor loads the MSP with the value from address 0x00000000.

Link Register

The Link Register (LR) is register R14. It stores the return information for subroutines, function calls, and exceptions.

On reset, the processor sets the LR value to 0xFFFFFFFF.

.

 SVC_Handler
         ; 加载pxCurrentTCB地址到R3
         LDR      r3,[pc,#28] ; LDR R3, =pxCurrentTCB
         
         ; 加载当前任务的堆栈地址到R0
         LDR      r1,[r3,#0]
         LDR      r0,[r1,#0]
         
         ; 从R0指向的堆栈中恢复R4到R11的值,并更新堆栈指针R0
         LDM      r0!,{r4-r11}
         
         ; 将当前线程的堆栈指针更改为R0中的值。
         MSR      PSP,r0
         
         ; 指令同步屏障,确保之前的所有指令完成执行
         ISB
         
         ; BASEPRI 寄存器中的值存储的是最低的允许运行中断号
         ; MSR 指令将通用寄存器的内容移动到指定的特殊寄存器中
         ; 清除基础优先级寄存器BASEPRI,允许所有优先级的中断
         MOV      r0,#0
         MSR      BASEPRI,r0
         
         ; 通过设置LR[3:0]的值为0X0D,设置堆栈指针为PSP
         ORR      lr,lr,#0xd
         
         BX       lr

.

 ORR lr,lr,#0xd
原始LR尾部执行指令后
0b00000b1101
0b01000b1101
0b10000b1101
0b11000b1101

.

SysTick_Handler

 void xPortSysTickHandler( void )
 {
     portDISABLE_INTERRUPTS();
    {
         /* Increment the RTOS tick. */
         if( xTaskIncrementTick() != pdFALSE )
        {
             /* A context switch is required.*/
             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
        }
    }
     portENABLE_INTERRUPTS();
 }

.

 SysTick_Handler
 
         PUSH     {r7,lr}
         
         ; portDISABLE_INTERRUPTS();
         MOV      r0,#0x50
         MSR      BASEPRI,r0
         ISB      
         DSB      
         
         ; if( xTaskIncrementTick() != pdFALSE )
         BL       xTaskIncrementTick ; 0x80039ac
         CBZ      r0,loc_800207a
         MOV      r0,#0xed04
         MOVT     r0,#0xe000
         MOV      r1,#0x10000000
         STR      r1,[r0,#0]
 loc_800207a:
         ; portENABLE_INTERRUPTS();
         MOVS     r0,#0
         MSR      BASEPRI,r0
         
         POP      {r7,pc}
         MOVS     r0,r0
 

.

PendSV_Handler

.

.

 PendSV_Handler
  ; MSR 指令将特殊寄存器的内容移动到指定的通用寄存器中
         MRS      r0,PSP
         ; 指令同步屏障,确保之前的所有指令完成执行
         ISB      
         
         LDR      r3,[pc,#52] ; [0x8002020] = 0x2000024c
         LDR      r2,[r3,#0]
         
         STMDB    r0!,{r4-r11}
         STR      r0,[r2,#0]
         
        PUSH.W   {r3,lr}
         
         MOV      r0,#0x50
         MSR      BASEPRI,r0
         
         BL       vTaskSwitchContext
         MOV      r0,#0
         MSR      BASEPRI,r0
         POP      {r3,lr}
         
         LDR      r1,[r3,#0]
         LDR      r0,[r1,#0]
         LDM      r0!,{r4-r11}
         MSR      PSP,r0
         
         ; 指令同步屏障,确保之前的所有指令完成执行
         ISB      
         BX       lr
 

.

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
{ \
List_t * const pxConstList = ( pxList ); \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
if( ( void * ) ( pxConstList )->pxIndex == \
( void * ) &( ( pxConstList )->xListEnd ) ) \
{ \
( pxConstList )->pxIndex = \
( pxConstList )->pxIndex->pxNext; \
} \
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
}

#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
UBaseType_t uxTopPriority = uxTopReadyPriority; \
while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \
{ \
configASSERT( uxTopPriority ); \
--uxTopPriority; \
} \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
uxTopReadyPriority = uxTopPriority; \
} /* taskSELECT_HIGHEST_PRIORITY_TASK */

void vTaskSwitchContext( void )
{
if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
{
/* The scheduler is currently suspended - do not allow a context
* switch. */
xYieldPending = pdTRUE;
}
else
{
xYieldPending = pdFALSE;
/* Select a new task to run using either the generic C or port
* optimised asm code. */
taskSELECT_HIGHEST_PRIORITY_TASK();
}
}

.

评论

此博客中的热门博文