FreeRTOS-port.c

FreeRTOS-port.c文件分析

StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStackTaskFunction_t pxCodevoid *pvParameters )

功能:初始化任务堆栈

参数:

1. pxTopOfStack   栈顶指针

2. pxCode  任务指针

3. pvParameters  任务参数指针

返回:

返回当前栈顶

 

static void prvTaskExitError( void )

功能:任务退出处理代码,在任务堆栈初始化时会保存在LR寄存器关联位置。

 

 

void vPortSVCHandler( void )

功能:SVC中断处理代码,实际是个空函数,没有使用,只是为了

兼容以前的代码而存在。

 

__asm void prvPortStartFirstTask( void )

功能:调度器启动后,执行第一个任务。

BaseType_t xPortStartScheduler( void )

功能:启动调度器,配置PENDSVSYSTICK中断,设置低功耗定时器中断

执行第一个任务。

返回值:返回0。

其实这是个不会返回的函数,执行不到返回位置。系统中至少存在一个空闲任务,启动调度器后就会有任务执行。

 

void vPortEndScheduler( void )

功能:结束调度器

 

void vPortYield( void )

功能:触发一次任务调度

 

void vPortEnterCritical( void )

功能:进入临界区

 

void vPortExitCritical( void )

功能:退出临界区

 

__asm uint32_t ulSetInterruptMaskFromISR( void )

功能:中断上下文进入临界区

__asm void vClearInterruptMaskFromISR( uint32_t ulMask )

功能:中断上下文退出临界区

 

__asm void xPortPendSVHandler( void )

功能:PendSVC中断处理函数,保存旧任务上下文,恢复最高就绪任务

上下文,即实现了任务切换的功能。

 

void xPortSysTickHandler( void )

功能:systickz中断处理函数,给系统时间增加一个tick,如果有更高优先级

的就绪任务则触发一次任务调度。

 

__weak void vPortSetupTimerInterrupt( void )

功能:设置systick定时器中断

 

void LPTIM32Init(void)

功能:低功耗定时器初始化

 

void LPTIM_IRQHandler()

功能:低功耗定时器中断处理函数

void prvStopTickInterruptTimer ( void )

功能:停止systick中断

 

__INLINE void disable_interrupts ( void )

功能:禁止中断

 

void prvStartTickInterruptTimer ( void )

功能:启动systick中断

 

__INLINE void enable_interrupts ( void )

功能:使能中断

 

void vSetWakeTimeInterrupt(TickType_t xExpectedIdleTime)

功能:设置低功耗定时器唤醒时间

参数:

  1. xExpectedIdleTime 能够进入休眠的时间

 

void DeepSleep(void)

功能:进入深度休眠

 

void vApplicationSleep ( TickType_t xExpectedIdleTime )

功能:根据xExpectedIdleTime 指示的时间进行休眠,并在被唤醒时

补偿systick

参数:

 1.xExpectedIdleTime 能够进入休眠的时间

 

重点解析:

 

StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStackTaskFunction_t pxCodevoid * pvParameters )

{

    /* Simulate the stack frame as it would be created by a context switch

     * interrupt. */

    pxTopOfStack--;     因为堆栈类型是满减栈,先把减栈指针再存内容。                            

    *pxTopOfStack = portINITIAL_XPSR;            /* 初始的进程状态寄存器值*/

    pxTopOfStack--;

    *pxTopOfStack = ( StackType_t ) pxCode;       /* PC 指针*/

    pxTopOfStack--;

    *pxTopOfStack = ( StackType_t ) prvTaskExitError;  /* LR 指针*/

    pxTopOfStack -= 5;                         /* R12, R3, R2 and R1. */

    *pxTopOfStack = ( StackType_t ) pvParameters;    /* R0 */

    pxTopOfStack -= 8;                   /* R11..R4. */

 

    return pxTopOfStack;

}

 

任务堆栈初始化后,堆栈中保存的内容如下:

1

XPSR

2

PC

3

LR

4

R12

5

R3

6

R2

7

R1

8

R0

9

R11

10

R10

11

R9

12

R8

13

R7

14

R6

15

R5

16

R4

 

 

 

__asm void prvPortStartFirstTask( void )

{

    extern pxCurrentTCB;

 

    PRESERVE8

 

    ldr r3, = pxCurrentTCB /* 把当前任务控制块指针拷贝到R3 */

    ldr r1, [ r3 ]                 /*把任务控制块的堆栈指针的指针拷贝到R1*/

    ldr r0, [ r1 ]    /*把堆栈指针拷贝到R0*/

    adds r0, # 32     /* 舍弃掉堆栈中的R4 - R11*/

    msr psp, r0        /* 把计算出来的堆栈指针拷贝到PSP寄存器 */

    movs r0, # 2     /* */

    msr CONTROL, r0                 /*切换到使用PSP模式*/

    isb

    pop { r0 - r5 }  /* 把堆栈中的6个值弹出到R0 - R5*/

    mov lr, r5       /*R5的值赋值给LR*/

    pop { r3 }      /* 把堆栈中的PC值弹出到R3*/

    pop { r2 }      /* 把堆栈中的XPSR弹出R2并舍弃*/

    cpsie i          /* 使能中断 */

    bx r3           /* 调转到用户定义的代码*/

 

    ALIGN

/* *INDENT-ON* */

}

 

__asm void xPortPendSVHandler( void )

{

    extern vTaskSwitchContext

    extern pxCurrentTCB

 

/* *INDENT-OFF* */

    PRESERVE8

 

    mrs r0, psp                              /*把进程堆栈指针拷贝到R0*/

 

    ldr r3, = pxCurrentTCB /* 把当前任务控制块指针拷贝到R3 */

    ldr r2, [ r3 ]                    /*把任务控制块的堆栈指针的指针拷贝到R2*/

 

    subs r0, # 32       /*为保存寄存器创造8个字的空间 */

    str r0, [ r2 ]      /* 把任务控制块的堆栈指针拷贝到堆栈 */

    stmia r0 !, { r4 - r7 } /*保存R4 - R7到值到堆栈*/

    mov r4, r8          /* Store the high registers. */

    mov r5, r9

    mov r6, r10

    mov r7, r11

    stmia r0 !, { r4 - r7 } /*保存R8 - R11 的值到堆栈*/

 

    push { r3, r14 }               /*TCB指针和LR入栈*/

    cpsid I                                       /*关中断*/

    bl vTaskSwitchContext         /*切换上下文,把当前优先级最高的就绪任务控制块赋值给pxCurrentTCB,即R3*/

    cpsie i

    pop { r2, r3 }     /* 把当前任务控制块指针弹出到R2,连接指针弹到R3 */

 

    ldr r1, [ r2 ]

    ldr r0, [ r1 ]    /* R0指向当前任务控制块指针*/

    adds r0, # 16      /* Move to the high registers. */

    ldmia r0 !, { r4 - r7 } /* 弹出R8 - R11 */

    mov r8, r4

    mov r9, r5

    mov r10, r6

    mov r11, r7

 

    msr psp, r0        /* 任务控制块指针赋值给PSP寄存器 */

 

    subs r0, # 32      /* Go back for the low registers that are not automatically restored. */

    ldmia r0 !, { r4 - r7 } /* 弹出R4 - R7 */

 

    bx r3    /*调整到当前任务上次执行的断点处继续执行。*/

    ALIGN

}

 

posted @ 2022-08-08 20:45  明er  阅读(170)  评论(0)    收藏  举报