From 8e63d2c8d181866b28c55d292f47993da6029b55 Mon Sep 17 00:00:00 2001 From: "zhibiao.xu" Date: Sun, 30 Mar 2025 14:53:28 +0800 Subject: [PATCH] mutil thread switch --- Core/Src/main.c | 37 +++- Core/Src/stm32f1xx_it.c | 1 + MDK-ARM/TEST1.uvprojx | 11 +- MDK-ARM/startup_stm32f103xb.s | 4 +- thead/inc/thread.h | 10 +- thead/src/context_switch.s | 25 ++- thead/src/thread.c | 333 ++++------------------------------ 7 files changed, 87 insertions(+), 334 deletions(-) diff --git a/Core/Src/main.c b/Core/Src/main.c index 4cd0029..7efecd7 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -52,17 +52,35 @@ void Error_Handler(void) } } -void prosee(void *data) +void prosee1(void *data) { - printf("prosee1\r\n"); + tcb_t *self = (tcb_t *)data; while(1) - { + { + __disable_irq(); + printf("prosee_%d\r\n", self->task_id); + __enable_irq(); + HAL_Delay(1000); } } +void prosee2(void *data) +{ + tcb_t *self = (tcb_t *)data; + while(1) + { + __disable_irq(); + printf("prosee_%d\r\n", self->task_id); + __enable_irq(); + HAL_Delay(1000); + } +} + +tcb_t tcb1; +tcb_t tcb2; +uint8_t statck[STACK_SIZE]; +uint8_t statck2[STACK_SIZE]; -tcb_t tcb; -uint32_t statck[128]; int main(void) { __disable_irq(); @@ -70,16 +88,15 @@ int main(void) SystemClock_Config(); MX_USART1_UART_Init(); printf("Init tasks\r\n"); - tcb.stack_ptr = statck; - tcb.task_id = 1; - init_task(&tcb,prosee, 0); - + init_task(&tcb1, prosee1, statck, (void *)&tcb1); + init_task(&tcb2, prosee2, statck2, (void *)&tcb2); + /* run the first task */ start_first_task(); __enable_irq(); while(1) { - __NOP(); + printf("idle\r\n"); }; } diff --git a/Core/Src/stm32f1xx_it.c b/Core/Src/stm32f1xx_it.c index 23788e5..89d376e 100644 --- a/Core/Src/stm32f1xx_it.c +++ b/Core/Src/stm32f1xx_it.c @@ -176,6 +176,7 @@ void SysTick_Handler(void) /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); + tcb_scheduler(); /* USER CODE BEGIN SysTick_IRQn 1 */ /* USER CODE END SysTick_IRQn 1 */ diff --git a/MDK-ARM/TEST1.uvprojx b/MDK-ARM/TEST1.uvprojx index e8cc8ca..61c28b6 100644 --- a/MDK-ARM/TEST1.uvprojx +++ b/MDK-ARM/TEST1.uvprojx @@ -10,7 +10,8 @@ TEST1 0x4 ARM-ADS - 6140000::V6.14::ARMCLANG + 6220000::V6.22::ARMCLANG + 6220000::V6.22::ARMCLANG 1 @@ -137,7 +138,7 @@ 4101 1 - BIN\UL2V8M.DLL + BIN\UL2CM3.DLL "" () @@ -186,6 +187,7 @@ 0 0 0 + 0 0 0 8 @@ -669,11 +671,6 @@ <Project Info> - - - - - 0 1 diff --git a/MDK-ARM/startup_stm32f103xb.s b/MDK-ARM/startup_stm32f103xb.s index b2cdba8..db1fec6 100644 --- a/MDK-ARM/startup_stm32f103xb.s +++ b/MDK-ARM/startup_stm32f103xb.s @@ -30,7 +30,7 @@ ; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> ; -Stack_Size EQU 0x1000 +Stack_Size EQU 0x300 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size @@ -41,7 +41,7 @@ __initial_sp ; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> ; -Heap_Size EQU 0x1000 +Heap_Size EQU 0x300 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base diff --git a/thead/inc/thread.h b/thead/inc/thread.h index be7c47c..73f118b 100644 --- a/thead/inc/thread.h +++ b/thead/inc/thread.h @@ -3,14 +3,16 @@ #define __THREAD_H #include -typedef struct +#define STACK_SIZE 512 // 每个任务的栈大小(按需调整) + +typedef struct tcb { uint32_t *stack_ptr; // 任务栈指针 uint32_t task_id; // 任务 ID - // 其他成员:优先级、状态、等待事件等... + struct tcb * next; } tcb_t; -void init_task(tcb_t *tcb, void (*task_entry)(void *), void *arg); +void init_task(tcb_t *tcb, void (*task_entry)(void *), uint8_t *start_stack, void *arg); void start_first_task(void); - +void tcb_scheduler(void); #endif \ No newline at end of file diff --git a/thead/src/context_switch.s b/thead/src/context_switch.s index 4443729..42de634 100644 --- a/thead/src/context_switch.s +++ b/thead/src/context_switch.s @@ -17,22 +17,21 @@ PendSV_Handler PROC ;-------------------------------------------------- CPSID I ; 禁用中断 (PRIMASK=1) CPSID F ; 禁用快速中断 (FAULTMASK=1) - + + ;-------------------------------------------------- + ; 2. 更新当前任务的栈指针到 TCB + ;-------------------------------------------------- + LDR R1, = current_task ; 加载 current_task 的地址到 R1 + LDR R1, [R1] ; 获取 current_task 指针的值(TCB地址) + CBZ R1, switch_nosave ; 如果是系统的第一个运行任务,不需要保存 ;-------------------------------------------------- - ; 2. 保存当前任务上下文(R4-R11 手动保存) + ; 3. 保存当前任务上下文(R4-R11 手动保存) ; 硬件自动保存: R0-R3, R12, LR, PC, PSR (通过 PSP) ;-------------------------------------------------- MRS R0, PSP ; 获取当前任务的栈指针 PSP - SUBS R0, R0, #0x20 ; 预留空间保存 R4-R11 (8寄存器 * 4字节 = 0x20) - STMIA R0!, {R4-R11} ; 将 R4-R11 压入任务栈(地址递增) - - ;-------------------------------------------------- - ; 3. 更新当前任务的栈指针到 TCB - ;-------------------------------------------------- - LDR R1, =current_task ; 加载 current_task 的地址到 R1 - LDR R2, [R1] ; 获取 current_task 指针的值(TCB地址) - STR R0, [R2] ; 将更新后的 PSP 保存到 TCB 的 stack_ptr 成员 - + STMFD R0!, {R4-R11} ; 将 R4-R11 压入任务栈(地址递增) + STR R0, [R1] +switch_nosave ;-------------------------------------------------- ; 4. 切换当前任务和下一个任务(调用 C 函数) ;-------------------------------------------------- @@ -41,7 +40,7 @@ PendSV_Handler PROC ;-------------------------------------------------- ; 5. 加载下一个任务的上下文 ;-------------------------------------------------- - LDR R1, =current_task ; 重新加载 current_task(此时已切换为新任务) + LDR R1, = current_task ; 重新加载 current_task(此时已切换为新任务) LDR R2, [R1] ; 获取新任务的 TCB 地址 LDR R0, [R2] ; 从 TCB 中获取新任务的栈指针 PSP diff --git a/thead/src/thread.c b/thead/src/thread.c index dfacf2e..fd1b96e 100644 --- a/thead/src/thread.c +++ b/thead/src/thread.c @@ -25,318 +25,55 @@ void start_first_task(void) __ISB(); } -#define STACK_SIZE 512 // 每个任务的栈大小(按需调整) +tcb_t *task[2]; -void init_task(tcb_t *tcb, void (*task_entry)(void *), void *arg) +uint8_t tcb_cunt = 0; +void tcb_scheduler(void) { - // 栈顶对齐到 8 字节(硬件要求) - 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) = (uint32_t)task_entry; // PC (任务入口) - *(--stack_top) = 0xDEADBEEF; // LR (通常无意义,但需占位) - *(--stack_top) = 0x0000000C; // R12 - *(--stack_top) = 0x00000003; // R3 - *(--stack_top) = 0x00000002; // R2 - *(--stack_top) = (uint32_t)arg;// R1 (参数) - *(--stack_top) = 0x00000000; // R0 - - // 手动保存的寄存器(R4-R11)初始值(通常为0) - for (int i = 0; i < 8; i++) + if(tcb_cunt >= 1) { - *(--stack_top) = 0x00000000; // R4-R11 - } - - // 保存栈顶到 TCB - tcb->stack_ptr = stack_top; -} - -#if 0 -void trigger_context_switch(void) -{ - SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; // ?? PendSV ??? - __DSB(); // ?????? - __ISB(); // ?????? -} - -#define STACK_SIZE 32 - - -struct exception_stack_frame -{ - uint32_t r0; - uint32_t r1; - uint32_t r2; - uint32_t r3; - uint32_t r12; - uint32_t lr; - uint32_t pc; - uint32_t psr; -}; - -typedef struct -{ - /* r4 ~ r11 register */ - uint32_t r4; - uint32_t r5; - uint32_t r6; - uint32_t r7; - uint32_t r8; - uint32_t r9; - uint32_t r10; - uint32_t r11; - struct exception_stack_frame exception_stack_frame; -}stack_frame_t; - - -struct Thread { - unsigned long ip; - unsigned int *sp; -}; - -typedef struct PCB { - struct Thread thread; - int pid; - volatile long state; /* -1 idle, 0 runnable */ - uint32_t stack[STACK_SIZE]; - struct PCB *next; -} tPCB; - -static tPCB task[MAX_TASK_NUM]; -static tPCB *current_task = NULL; -static uint32_t *current_task_sp = NULL; -static uint32_t *next_task_sp = NULL; - - -void tTaskRunFirst(void); -void tTaskSwitch(void); -void tTask_schedule(void); - -void my_process(void) -{ - uint32_t i = 0; - while (1) { - i++; - if (i % 1000000 == 0) { - printf("this is process %d - \r\n", current_task->pid); - } + tcb_cunt = -1; } -} - -#define RT_ALIGN_DOWN(size, align) ((size) & ~((align) - 1)) -void StackInit(tPCB * task, void (*entry)(void), unsigned int * stack_addr) -{ - stack_frame_t * stack_frame; - uint32_t *stk; - unsigned long i; - - stk = stack_addr + sizeof(uint32_t); - stk = (uint32_t *)RT_ALIGN_DOWN((uint32_t)stk, 8); - stk -= sizeof(stack_frame_t); - stack_frame = (stack_frame_t *)stk; - - /* init all register */ - for (i = 0; i < sizeof(stack_frame_t) / sizeof(uint32_t); i ++) - { - ((uint32_t *)stack_frame)[i] = 0xdeadbeef; - } - - stack_frame->exception_stack_frame.r0 = 0; /* r0 : argument */ - stack_frame->exception_stack_frame.r1 = 0; /* r1 */ - stack_frame->exception_stack_frame.r2 = 0; /* r2 */ - stack_frame->exception_stack_frame.r3 = 0; /* r3 */ - stack_frame->exception_stack_frame.r12 = 0; /* r12 */ - stack_frame->exception_stack_frame.lr = 0; /* lr */ - stack_frame->exception_stack_frame.pc = (unsigned long)entry; /* entry point, pc */ - stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */ - -} - -void tTaskInit(int task_num) -{ - int i = 0; - - task[i].pid = i; - task[i].state = 0; - task[i].thread.ip = (unsigned long)my_process; - task[i].thread.sp = &task[i].stack[STACK_SIZE - 1]; - task[i].next = &task[i]; - for (i = 1; i < task_num; i++) { - task[i].pid = i; - task[i].state = 0; - task[i].thread.ip = (unsigned long)my_process; - task[i].thread.sp = &task[i].stack[STACK_SIZE - 1]; - task[i].next = task[i - 1].next; - task[i - 1].next = &task[i]; - StackInit(&task[i], my_process, task[i].stack); - } - current_task = &task[0]; - current_task_sp = (uint32_t *)__get_MSP(); -} - - -void tTask_schedule(void) -{ - current_task_sp = current_task->thread.sp; - current_task = current_task->next; - next_task_sp = current_task->thread.sp; + tcb_cunt++; + next_task = task[tcb_cunt]; SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; __DSB(); __ISB(); - return; } -void tTaskRunFirst(void) -{ - tTask_schedule(); - __enable_irq(); - while(1); -} -// PendSV 쳣 -void PendSV_Handler(void) +void init_task(tcb_t *tcb, void (*task_entry)(void *), uint8_t *start_stack, void *arg) { - - extern unsigned int *next_task_sp; - extern unsigned int *current_task_sp; - __asm volatile ( - // жϣȷԭӲ - "CPSID I\n" - - // current_task ĵַ R - "LDR R0, = current_task_sp\n" - "STR R0, [R0]\n" - - // 浱ǰ - "MRS R1, MSP\n" // ջָ루MSP浽 R0 - "STMDB R1!, {R4-R11}\n" // ֶ R4-R11 - - - - - // лһ - "LDR R1, = next_task_sp\n" - "LDR R0, [R1]\n" - - // ָһ - "LDMIA R0!, {R4-R11}\n" // ֶָ R4-R11 - "MSR MSP, R0\n" // ָջָд PSP - - // ж - "CPSIE I\n" - - // 쳣 - "BX LR\n" - ); -} - -/* -void tTaskSwitch(void) -{ - extern tPCB *current_task; - extern tPCB *next_task; - - __asm volatile ( - "CPSID I\n" - // R0 = current_task->thread.ip - "LDR r0, =current_task\n" // current_task ĵַ r0 - "LDR r0, [r0]\n" // current_task ֵ r0 - "LDR r0, [r0, #4]\n" // current_task->thread.ip r0 - - // PUSH {LR} - "STMDB r0!, {lr}\n" // LRR14ѹջ r0 - - // ˢ current_task->thread.ip - "LDR r1, =current_task\n" // current_task ĵַ r1 - "LDR r1, [r1]\n" // current_task ֵ r1 - "STR r0, [r1, #4]\n" // º r0 洢 current_task->thread.ip - - // current_task = next_task - "LDR r0, =current_task\n" // current_task ĵַ r0 - "LDR r1, =next_task\n" // next_task ĵַ r1 - "LDR r1, [r1]\n" // next_task ֵ r1 - "STR r1, [r0]\n" // next_task ֵ洢 current_task - - // R0 = next_task->thread.ip - "LDR r0, =next_task\n" // next_task ĵַ r0 - "LDR r0, [r0]\n" // next_task ֵ r0 - "LDR r0, [r0, #4]\n" // next_task->thread.ip r0 - - // POP {LR} - "LDMIA r0!, {lr}\n" // r0 ָĵַ LRR14 r0 - - // ˢ next_task->thread.ip - "LDR r1, =next_task\n" // next_task ĵַ r1 - "LDR r1, [r1]\n" // next_task ֵ r1 - "STR r0, [r1, #4]\n" // º r0 洢 next_task->thread.ip - - // ת LR ָĵַ - "BX lr\n" // ת LR ָĵַ - ); -} - + // 栈顶对齐到 8 字节(硬件要求) + static uint8_t tcb_id = 0; + task[tcb_id] = tcb; + tcb_id++; + tcb->task_id = tcb_id; + tcb->stack_ptr = (uint32_t *)start_stack; + uint32_t *stack_top = (uint32_t*)((uint8_t*)tcb->stack_ptr + STACK_SIZE); + stack_top = (uint32_t*)((uint32_t)stack_top & ~0x07); -__asm void tTaskRunFirst(void) -{ - IMPORT current_task + *(--stack_top) = 0x01000000; // xPSR (Thumb 模式) + *(--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 - // R0 = current_task->thread.ip - LDR R0, =current_task - LDR R0, [R0] - LDR R0, [R0, #4] - - // POP - LDMIA R0!,{R14}; - - // refresh current_task->thread.ip - LDR R1, =current_task - LDR R1, [R1] - STR R0, [R1, #4] + for (int i = 0; i < 8; i++) + { + *(--stack_top) = 0x12345678; // R4-R11 + } + tcb->stack_ptr = stack_top; - BX R14 + printf("init_tch:%d\r\n", tcb_id); + if(tcb_id == 1) + { + printf("start_tch:%d\r\n", tcb_id); + next_task = tcb; + } } -__asm void tTaskSwitch(void) -{ - IMPORT current_task - IMPORT next_task - - // R0 = current_task->thread.ip - LDR R0, =current_task - LDR R0, [R0] - LDR R0, [R0, #4] - - // PUSH - STMDB R0!, {R14}; - - // refresh current_task->thread.ip - LDR R1, =current_task - LDR R1, [R1] - STR R0, [R1, #4] - - // current_task = next_task; - LDR R0, =current_task - LDR R1, =next_task - LDR R1, [R1] - STR R1, [R0] - - // R0 = next_task->thread.ip - LDR R0, =next_task - LDR R0, [R0] - LDR R0, [R0, #4] - - // POP - LDMIA R0!,{R14}; - - // refresh next_task->thread.ip - LDR R1, =next_task - LDR R1, [R1] - STR R0, [R1, #4] - - BX R14 -} -*/ -#endif