diff --git a/Core/Src/main.c b/Core/Src/main.c index 7efecd7..359ddd6 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -58,7 +58,7 @@ void prosee1(void *data) while(1) { __disable_irq(); - printf("prosee_%d\r\n", self->task_id); + printf("prosee_%d, stack_ptr:%#x\r\n", self->task_id, self->stack_ptr); __enable_irq(); HAL_Delay(1000); } @@ -70,7 +70,7 @@ void prosee2(void *data) while(1) { __disable_irq(); - printf("prosee_%d\r\n", self->task_id); + printf("prosee_%d, stack_ptr:%#x\r\n", self->task_id, self->stack_ptr); __enable_irq(); HAL_Delay(1000); } diff --git a/thead/inc/thread.h b/thead/inc/thread.h index 73f118b..a55578e 100644 --- a/thead/inc/thread.h +++ b/thead/inc/thread.h @@ -9,7 +9,7 @@ typedef struct tcb { uint32_t *stack_ptr; // 任务栈指针 uint32_t task_id; // 任务 ID - struct tcb * next; + struct tcb * next; // 需要采用链表的方式记录任务栈 } tcb_t; void init_task(tcb_t *tcb, void (*task_entry)(void *), uint8_t *start_stack, void *arg); diff --git a/thead/src/context_switch.s b/thead/src/context_switch.s index 42de634..e9dd513 100644 --- a/thead/src/context_switch.s +++ b/thead/src/context_switch.s @@ -1,10 +1,6 @@ -; 文件名: context_switch.s -; 目标平台: ARM Cortex-M3/M4 (STM32) -; 工具链: ARM Compiler 6 (Keil MDK/ARMCLANG) -; 描述: 通过 PendSV 异常实现 RTOS 上下文切换 - PRESERVE8 ; 强制栈按 8 字节对齐 (Cortex-M 硬件要求) - THUMB ; 使用 Thumb-2 指令集 + PRESERVE8 ; 8 字节对齐 + THUMB ; 使用 Thumb 指令集 AREA |.text|, CODE, READONLY ; 定义代码段 EXPORT PendSV_Handler ; 导出 PendSV_Handler 符号 @@ -12,8 +8,9 @@ IMPORT next_task ; 从 C 代码导入 next_task 指针 IMPORT switch_to_next_task ; 从 C 代码导入 switch_to_next_task 函数 PendSV_Handler PROC + ;-------------------------------------------------- - ; 1. 关闭中断(确保上下文切换原子性) + ; 1. 关闭中断(确保不会被更高优先级任务打断) ;-------------------------------------------------- CPSID I ; 禁用中断 (PRIMASK=1) CPSID F ; 禁用快速中断 (FAULTMASK=1) @@ -23,19 +20,21 @@ PendSV_Handler PROC ;-------------------------------------------------- LDR R1, = current_task ; 加载 current_task 的地址到 R1 LDR R1, [R1] ; 获取 current_task 指针的值(TCB地址) - CBZ R1, switch_nosave ; 如果是系统的第一个运行任务,不需要保存 + CBZ R1, switch_nosave ; 如果获取到底SP为空就不需要保存,并且跳转到switch_nosave函数 + ;-------------------------------------------------- ; 3. 保存当前任务上下文(R4-R11 手动保存) ; 硬件自动保存: R0-R3, R12, LR, PC, PSR (通过 PSP) ;-------------------------------------------------- - MRS R0, PSP ; 获取当前任务的栈指针 PSP + MRS R0, PSP ; 获取当前任务的栈指针 PSP STMFD R0!, {R4-R11} ; 将 R4-R11 压入任务栈(地址递增) - STR R0, [R1] + STR R0, [R1] ; 将PSP保存进TCB的SP + switch_nosave ;-------------------------------------------------- ; 4. 切换当前任务和下一个任务(调用 C 函数) ;-------------------------------------------------- - BL switch_to_next_task ; 调用 C 函数切换 current_task 和 next_task + BL switch_to_next_task ; 调用 C 函数witch_to_next_task 获取下一个TCB ;-------------------------------------------------- ; 5. 加载下一个任务的上下文 diff --git a/thead/src/thread.c b/thead/src/thread.c index fd1b96e..dc5a96f 100644 --- a/thead/src/thread.c +++ b/thead/src/thread.c @@ -5,12 +5,15 @@ #include "thread.h" - -// 声明任务指针(需在汇编中导入) +/*** +上下文切换的指针,如果触发了上下文切换,则next_task为下一个执行目标。 +***/ tcb_t *current_task; tcb_t *next_task; -// 切换任务的函数 +/*** + 切换任务的函数,进行上下文切换的时候,会获取一下最新的任务指针。 +***/ void switch_to_next_task(void) { tcb_t *temp = current_task; @@ -18,6 +21,9 @@ void switch_to_next_task(void) next_task = temp; } +/*** + 启动切换,芯片上电默认执行的是main函数,需要切换到第一个任务上。 +***/ void start_first_task(void) { SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; @@ -25,9 +31,15 @@ void start_first_task(void) __ISB(); } +/*** + 任务调度器,目前简单描写。采用循环执行任务策略, 后续优化方向: + 1.采用任务优先级策略进行调度。 + 2.采用时间片调度。 + 3.采用信号量调度。 +***/ tcb_t *task[2]; - uint8_t tcb_cunt = 0; +static uint8_t max_tcb = 0; void tcb_scheduler(void) { if(tcb_cunt >= 1) @@ -41,7 +53,9 @@ void tcb_scheduler(void) __ISB(); } - +/*** + 初始化任务,需要对栈初始化 +***/ void init_task(tcb_t *tcb, void (*task_entry)(void *), uint8_t *start_stack, void *arg) { // 栈顶对齐到 8 字节(硬件要求) @@ -53,14 +67,14 @@ void init_task(tcb_t *tcb, void (*task_entry)(void *), uint8_t *start_stack, voi uint32_t *stack_top = (uint32_t*)((uint8_t*)tcb->stack_ptr + STACK_SIZE); stack_top = (uint32_t*)((uint32_t)stack_top & ~0x07); - *(--stack_top) = 0x01000000; // xPSR (Thumb 模式) + *(--stack_top) = 0x01000000; // xPSR *(--stack_top) = (uint32_t)task_entry; // PC *(--stack_top) = 0xDEADBEEF; // LR *(--stack_top) = 0x0000000C; // R12 *(--stack_top) = 0x00000003; // R3 *(--stack_top) = 0x00000002; // R2 - *(--stack_top) = 0x00000000; // R1 (参数) - *(--stack_top) = (uint32_t)arg; // R0 + *(--stack_top) = 0x00000000; // R1 + *(--stack_top) = (uint32_t)arg; // R0 (参数) for (int i = 0; i < 8; i++) {