设计一个简易的多任务 rtos 4 - 实现一个可以运行多任务的简易rtos

  1.创建任务

  创建任务的主要工作是对任务的stack进行初始化,也就是伪造一个现场。

/**********************************************************************************
    创建任务
**********************************************************************************/
int
osTaskCreate(OsTcb *tcb_ptr, TaskFunc task_ptr, char *name, void *param, CPU_STAK *stak_base, uint32_t stak_size)
{
    if(tcb_ptr == NULL) return -1;
    if(task_ptr == NULL) return -1;
    if(stak_base == NULL) return -1;
    
    /** 初始化堆栈,伪造现场 **/
    tcb_ptr->stak_ptr = _osTaskStakInit(task_ptr, param, stak_base, stak_size);
    
    /** 将任务加入就序列表 **/
    osTaskAddReadyList(tcb_ptr);
    return 0;
}

/**********************************************************************************
    堆栈初始化操作完任务栈空间的现场伪造,保证任务第一次执行时能正常运行。
**********************************************************************************/
static inline CPU_STAK *
_osTaskStakInit(TaskFunc task_ptr, void *param, CPU_STAK *stak_base, uint32_t stak_size)
{
    CPU_STAK * stak_ptr = &stak_base[stak_size];
    
    stak_ptr = (CPU_STAK *)((CPU_STAK)stak_ptr & 0xFFFFFFF8);
    
    * --stak_ptr = (CPU_STAK)0x01000000;        /** xPSR, bit24 = 1, use thumb instruction **/
    * --stak_ptr = (CPU_STAK)task_ptr;          /** R15/PC, enter point **/
    * --stak_ptr = (CPU_STAK)_osTaskReturn;     /** R14/LR, task return function **/
    * --stak_ptr = (CPU_STAK)0x12121212;        /** R12, do not care **/
    * --stak_ptr = (CPU_STAK)0x03030303;        /** R3, do not care **/
    * --stak_ptr = (CPU_STAK)0x02020202;        /** R2, do not care **/
    * --stak_ptr = (CPU_STAK)0x01010101;        /** R1, do not care **/
    * --stak_ptr = (CPU_STAK)param;             /** R0, parameter **/
    
    * --stak_ptr = (CPU_STAK)0x11111111;        /** R11, do not care **/
    * --stak_ptr = (CPU_STAK)0x10101010;        /** R10, do not care **/
    * --stak_ptr = (CPU_STAK)0x09090909;        /** R9, do not care **/
    * --stak_ptr = (CPU_STAK)0x08080808;        /** R8, do not care **/
    * --stak_ptr = (CPU_STAK)0x07070707;        /** R7, do not care **/
    * --stak_ptr = (CPU_STAK)0x06060606;        /** R6, do not care **/
    * --stak_ptr = (CPU_STAK)0x05050505;        /** R5, do not care **/
    * --stak_ptr = (CPU_STAK)0x04040404;        /** R4, do not care **/
    
    return stak_ptr;
}

  2. 任务切换

  任务切换在 SysTick_Handler 中执行,每次中断都进行一次任务切换。这里强调一点,由于任务切换是在systick中断中执行,因此在恢复完成新任务的现场之后,需要通过将进入中断时写入LR寄存器中的EXC_RETURN数据来触发中断返回,从而恢复现场,也即由硬件将R0 - R3、R12、LR、PC、xPSR寄存器的值从栈中恢复,而在中断执行过程中,又有函数调用会将LR中的值破坏掉,因此在进入 SysTick_Handler 时要第一时间把 EXC_RETURN 数据保存起来,已备触发中断返回时使用。

SysTick_HandlerAsm PROC
                IMPORT  os_running
                IMPORT  g_cur_task
                IMPORT    osTick
                                
                ;进入中断时,硬件完成 xPSR, PC, LR, R12, R3-R0的入栈保存操作
                ;并在 LR 中写入 EXC_RETURN
                
                ;判断是否需要保存现场
                LDR   R1,  =g_cur_task
                LDR   R1,  [R1]
                CBZ   R1,  NO_SAVE    ;如果为空,说明是第一次切换任务,无需保存现场
                
                ;保存现场
                MRS   R0,  MSP
                STMDB R0!, {R4 - R11} ;保存R4-R11寄存器到堆栈
                
                ;保存当前任务的SP指针
                LDR   R1,  =g_cur_task
                LDR   R1,  [R1]
                STR   R0,  [R1]       ;g_cur_task->stak_ptr = R0
                MSR   MSP, R0         ;MSP = R0
                
NO_SAVE
                ;执行osTick
                PUSH  {LR}              ;备份LR,以便osTick退出后触发中断返回
                BL    osTick          ;在osTick中切换任务
                POP   {LR}            ;恢复LR
                
                ;获取新任务的SP指针
                LDR   R1,  =g_cur_task
                LDR   R1,  [R1]
                LDR   R0,  [R1]       ;R0 = g_cur_task->stak_ptr
                
                ;恢复现场
                LDMIA R0!, {R4 - R11} ;将 R4-R11从堆栈中写入寄存器
                MSR   MSP, R0         ;跟新SP指针
                BX    LR              ;将 EXC_RETURN 写入PC,触发中断返回
                
                ENDP

 完整代码:https://gitee.com/ivan1024/os.git

posted @ 2022-04-09 20:21  Ivan0512  阅读(263)  评论(0)    收藏  举报