rtos 3 - 实现一个可以运行多任务的简易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_Handler\ PROC IMPORT osTick ;保存 LR = EXC_RETURN ;将LR作为参数输入osTick,否则中断程序的过程调用会将LR中的值破坏 MOV R0, LR BL osTick ENDP
void osTick(uint32_t lr) { if(!os_running) return; /** 保存现场 **/ if(g_cur_task != NULL) pushCtxAsm(g_cur_task->stak_ptr); /** 获取下一个就绪任务 **/ osGetNextReadyTask(); /** 切换任务 **/ popCtxAsm(g_cur_task->stak_ptr, lr); }
pushCtxAsm PROC ;保存R4-R11寄存器到堆栈 STMDB R0!, {R4 - R11} BX LR ENDP popCtxAsm PROC ;将 R4-R11从堆栈中写入寄存器 ;R0 :任务的栈顶地址 ;R1 :LR = EXC_RETURN LDMIA R0!, {R4 - R11} MSR MSP, R0 ;跟新SP指针 BX R1 ;将 EXC_RETURN 写入PC,触发中断返回 ENDP
完整代码:https://gitee.com/ivan1024/os.git
标签:STAK,do,多任务,--,rtos,CPU,简易,ptr,stak 来源: https://www.cnblogs.com/ivan0512/p/16123325.html