commit 345be1983b21345ebba6efec8d9e0c7b8f097bd1 Author: Chen Peng Date: Fri May 29 13:18:56 2026 +0800 STM32F103C8T6 Port diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..39da000 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.15) +project(RTOS_STM32F103C8T6 C ASM) + +file(GLOB SOURCES ${CMAKE_CURRENT_LIST_DIR}/*.c) +if (CMAKE_C_COMPILER_ID MATCHES GNU) + file(GLOB ARM_SOURCES ${CMAKE_CURRENT_LIST_DIR}/*_gnu.S) +endif () +if (CMAKE_C_COMPILER_ID MATCHES ARMCC) + file(GLOB ARM_SOURCES ${CMAKE_CURRENT_LIST_DIR}/*_armcc.S) +endif () + +set(RTOS_PORT_SOURCES ${SOURCES} ${ARM_SOURCES} PARENT_SCOPE) +set(RTOS_PORT_INCLUDE_PATH ${CMAKE_CURRENT_LIST_DIR} PARENT_SCOPE) diff --git a/cpu.c b/cpu.c new file mode 100644 index 0000000..942f6ed --- /dev/null +++ b/cpu.c @@ -0,0 +1 @@ +#include diff --git a/cpu.h b/cpu.h new file mode 100644 index 0000000..1172b30 --- /dev/null +++ b/cpu.h @@ -0,0 +1,172 @@ +#ifndef INCLUDED_CPU_H +#define INCLUDED_CPU_H + +#ifndef INCLUDED_STM32F1XX_H +#define INCLUDED_STM32F1XX_H +#include +#endif /*INCLUDED_STM32F1XX_H*/ + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +#define os_port_disable_irq CMSIS_disable_irq +#define os_port_enable_irq CMSIS_enable_irq +#define os_port_save_disable_irq cpu_save_disable_irq +#define os_port_restore_irq cpu_restore_irq +#define os_port_save_disable_irq_in_isr cpu_save_disable_irq_in_isr +#define os_port_restore_irq_in_isr cpu_restore_irq_in_isr + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define CPU_SYSCALL_ID 0x00 +#define CPU_SYSCALL_OP_SAVE_DISABLE_IRQ 0x00 +#define CPU_SYSCALL_OP_RESTORE_IRQ 0x01 +#define CPU_SYSCALL_OP_SCHED 0x02 + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +#if defined(__CC_ARM) /* armcc (AC5) */ + +#define SVC_CALL_ARGS0(num, type, name) \ + __svc(num) type name(void) + +#define SVC_CALL_ARGS1(num, type, name, a0) \ + __svc(num) type name(os_uintptr_t a0) + +#define SVC_CALL_ARGS2(num, type, name, a0, a1) \ + __svc(num) type name(os_uintptr_t a0, os_uintptr_t a1) + +#define SVC_CALL_ARGS3(num, type, name, a0, a1, a2) \ + __svc(num) type name(os_uintptr_t a0, os_uintptr_t a1, os_uintptr_t a2) + +#define SVC_CALL_ARGS4(num, type, name, a0, a1, a2, a3) \ + __svc(num) type name(os_uintptr_t a0, os_uintptr_t a1, os_uintptr_t a2, os_uintptr_t a3) + + +#elif defined(__GNUC__) /* gcc */ + +#define SVC_CALL_ARGS0(num, type, name) \ +OS_STATIC_FORCE_INLINE type name(void) { \ + register os_uintptr_t r0 __asm__("r0")=0; \ + __asm__ volatile ("svc " #num : : : "memory"); \ + return (type)r0; \ +} + +#define SVC_CALL_ARGS1(num, type, name, a1) \ +OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1) { \ + register os_uintptr_t r0 __asm__("r0") = a1; \ + __asm__ volatile ("svc " #num :"=r"(r0):"r"(r0) : "memory"); \ + return (type)r0; \ +} + +#define SVC_CALL_ARGS2(num, type, name, a1, a2) \ +OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1, os_uintptr_t a2) { \ + register os_uintptr_t r0 __asm__("r0") = a1;\ + register os_uintptr_t r1 __asm__("r1") = a2;\ + __asm__ volatile ("svc " #num :"=r"(r0) :"r"(r0), "r"(r1) : "memory"); \ + return (type)r0; \ +} + +#define SVC_CALL_ARGS3(num, type, name, a1, a2, a3) \ +OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1, os_uintptr_t a2, os_uintptr_t a3) { \ + register os_uintptr_t r0 __asm__("r0") = a1; \ + register os_uintptr_t r1 __asm__("r1") = a2; \ + register os_uintptr_t r2 __asm__("r2") = a3; \ + __asm__ volatile ("svc " #num :"=r"(r0) :"r"(r0), "r"(r1), "r"(r2) : "memory"); \ + return (type)r0; \ +} + +#define SVC_CALL_ARGS4(num, type, name, a1, a2, a3, a4) \ +OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1, os_uintptr_t a2, os_uintptr_t a3, os_uintptr_t a4) { \ + register os_uintptr_t r0 __asm__("r0") = a1; \ + register os_uintptr_t r1 __asm__("r1") = a2; \ + register os_uintptr_t r2 __asm__("r2") = a3; \ + register os_uintptr_t r3 __asm__("r3") = a4; \ + __asm__ volatile ("svc " #num :"=r"(r0) :"r"(r0), "r"(r1), "r"(r2), "r"(r3) : "memory"); \ + return (type)r0; \ +} + +#endif + + +SVC_CALL_ARGS1(0, os_uint_t, cpu_svc0_args1, a1); +SVC_CALL_ARGS2(0, void, cpu_svc0_args2, a1, a2); + + +OS_STATIC_FORCE_INLINE +os_uint_t cpu_save_disable_irq_in_svc(void){ + return cpu_svc0_args1(CPU_SYSCALL_OP_SAVE_DISABLE_IRQ); +} + +OS_STATIC_FORCE_INLINE +void cpu_restore_irq_in_svc(os_uint_t level){ + cpu_svc0_args2(CPU_SYSCALL_OP_RESTORE_IRQ, level); +} + +OS_STATIC_FORCE_INLINE +void cpu_sched_in_svc(void){ + cpu_svc0_args1(CPU_SYSCALL_OP_SCHED); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +OS_STATIC_FORCE_INLINE +int is_cpu_in_privilege(void){ + // 1. 检查是否在中断/异常中 (IPSR != 0 表示 Handler 模式) + if ( __get_IPSR() != 0) { + return 1; + } + + // 2. 如果在 Thread 模式,检查 CONTROL 寄存器 + return ((__get_CONTROL() & 0x01) == 0)?1:0; +} + + +OS_STATIC_FORCE_INLINE +os_uint_t cpu_save_disable_irq_in_isr(void){ + os_uint_t level = __get_BASEPRI(); + __set_BASEPRI((OS_CFG_SYSCALL_PRIORITY+1) << 4); + return level; +} + +OS_STATIC_FORCE_INLINE +void cpu_restore_irq_in_isr(os_uint_t value){ + __set_BASEPRI(value); +} + + +OS_STATIC_FORCE_INLINE +os_uint_t cpu_save_disable_irq(void){ + if(is_cpu_in_privilege()){ + return cpu_save_disable_irq_in_isr(); + }else{ + return cpu_save_disable_irq_in_svc(); + } +} + +OS_STATIC_FORCE_INLINE +void cpu_restore_irq(os_uint_t value){ + if(is_cpu_in_privilege()){ + cpu_restore_irq_in_isr(value); + }else{ + cpu_restore_irq_in_svc(value); + } +} + + +#endif /*INCLUDED_CPU_H*/ diff --git a/os_port.c b/os_port.c new file mode 100644 index 0000000..14b5c15 --- /dev/null +++ b/os_port.c @@ -0,0 +1,147 @@ +#include "os_port.h" +#include "os_stack.h" +#include "os_macros.h" +#include "os_align.h" +#include "os_compiler.h" +#include "os_systick.h" +#include "os_sched.h" + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +volatile os_uint_t svc_exc_return; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { +#if(OS_CFG_CPU_FPU_PRESENT) + os_uintptr_t s16; + os_uintptr_t s17; + os_uintptr_t s18; + os_uintptr_t s19; + os_uintptr_t s20; + os_uintptr_t s21; + os_uintptr_t s22; + os_uintptr_t s23; + os_uintptr_t s24; + os_uintptr_t s25; + os_uintptr_t s26; + os_uintptr_t s27; + os_uintptr_t s28; + os_uintptr_t s29; + os_uintptr_t s30; + os_uintptr_t s31; +#endif +/* ==== 以下为手动压栈部分 ==== */ + os_uintptr_t exc_return; /* r2 - LR */ /* 这是地址最小的位置 */ + os_uintptr_t control; /* r3 */ + os_uintptr_t r4; + os_uintptr_t r5; + os_uintptr_t r6; + os_uintptr_t r7; + os_uintptr_t r8; + os_uintptr_t r9; + os_uintptr_t r10; + os_uintptr_t r11; +/* ==== 以下为自动压栈部分 ==== */ + os_uintptr_t r0; + os_uintptr_t r1; + os_uintptr_t r2; + os_uintptr_t r3; + os_uintptr_t r12; + os_uintptr_t lr; + os_uintptr_t pc; + os_uintptr_t xPSR; +}os_stack_frame_t; + +#define STACK_FRAME_SIZE sizeof(os_stack_frame_t) + +os_stack_t os_port_cpu_stack_init(os_task_entry_t entry, void* param + , void* stack_base, os_size_t stack_size, void(*exit_entry)(void)){ + os_uintptr_t stack_max = (os_uintptr_t)((uint8_t *) stack_base + stack_size); + os_uintptr_t real_max = OS_ALIGN_DOWN(stack_max, OS_ALIGN_SIZE); /* 实际栈顶的位置,对齐后的位置 */ + stack_size -= (stack_max - real_max); /* 实际栈大小 */ + + uint8_t flag = 0x01; + os_stack_frame_t* p_frame = (os_stack_frame_t*)(real_max - STACK_FRAME_SIZE); + for(os_size_t i=0; ir0 = (os_uintptr_t)param; /* 任务参数 */ + p_frame->pc = (os_uintptr_t)entry; /* 任务入口 */ + p_frame->lr = (os_uintptr_t)exit_entry; /* 退出地址 */ + + p_frame->xPSR = (1u << 24); /* THUMB */ + p_frame->control = 0x03; /* 任务使用用户权限,栈使用 PSP */ + p_frame->exc_return = 0xFFFFFFFDul; /* 任务在中断中切换,这里是退出中断的设置 */ + + os_stack_t stack; + stack.min = (os_uintptr_t)stack_base; + stack.max = (os_uintptr_t)real_max; + stack.type = kOsStackType_MaxToMin; + stack.sp = p_frame; + return stack; +} + +void os_port_init(void){ + +} + +void os_port_startup(void){ + NVIC_SetPriority(PendSV_IRQn, 0xff); + NVIC_SetPriority(SVCall_IRQn, OS_CFG_SYSCALL_PRIORITY); + SysTick_Config(SystemCoreClock/OS_CFG_TICKS_PER_SECOND); +} + +void os_port_send_context_switch_request(void){ + SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; +} + +void os_port_clear_context_switch_request(void){ + SCB->ICSR &= ~SCB_ICSR_PENDSVSET_Msk; +} + +void os_sched(void){ + if(is_cpu_in_privilege()){ + os_sched_in_isr(); + }else{ + cpu_sched_in_svc(); + } +} + +void SysTick_Handler(void){ + os_systick_tick(); +} + +void SVC_Handler_C(os_uintptr_t* svc_args){ + // 读取系统调用号:它存储在原本的 PC 指令前两个字节 + uint8_t svc_number = ((uint8_t *)svc_args[6])[-2]; + switch (svc_number) { + case CPU_SYSCALL_ID:{ + os_uint_t op = svc_args[0]; + switch (op) { + case CPU_SYSCALL_OP_SAVE_DISABLE_IRQ:{ + svc_args[0] = os_port_save_disable_irq_in_isr(); + break; + } + case CPU_SYSCALL_OP_RESTORE_IRQ:{ + os_port_restore_irq_in_isr(svc_args[1]); + break; + } + case CPU_SYSCALL_OP_SCHED:{ + os_sched_in_isr(); + break; + } + default: + break; + } + break; + } + default: break; + } +} + diff --git a/os_port_armcc.S b/os_port_armcc.S new file mode 100644 index 0000000..4af1b4b --- /dev/null +++ b/os_port_armcc.S @@ -0,0 +1,71 @@ + PRESERVE8 + THUMB + + AREA |.text|, CODE, READONLY + +cpu_clz PROC + EXPORT cpu_clz + CLZ R0, R0 + BX LR + ENDP + + +SVC_Handler PROC + EXPORT SVC_Handler + IMPORT svc_exc_return + IMPORT SVC_Handler_C + tst lr, #4 // 检查 EXC_RETURN (LR) 的位 2 + ite eq + mrseq r0, msp // 如果位 2 是 0,栈帧在 MSP + mrsne r0, psp // 如果位 2 是 1,栈帧在 PSP + ldr r1, =svc_exc_return + str lr, [r1] + bl SVC_Handler_C // 跳转到 C 实现,r0 作为第一个参数传入 + ldr r1, =svc_exc_return + ldr lr, [r1] + bx lr + ENDP + +PendSV_Handler PROC + EXPORT PendSV_Handler + IMPORT g_os_port_switch_from_sp + IMPORT g_os_port_switch_to_sp + IMPORT os_port_on_switch_success + mrs r1, primask // 获取值 + cpsid i // 关闭中断 + PUSH {R1} + + LDR R1, =g_os_port_switch_from_sp // 加载当前任务指针地址 + LDR R1, [R1] // 加载 g_os_port_switch_from_sp 的值 + CBZ R1, __PendSV_SwitchTo + + /* ---- 压栈 ---- */ + MRS R0, PSP + MOV R2, LR + MRS R3, CONTROL + STMDB R0!, {R2-R11} + + /* ---- sp值保存到变量中 ---- */ + STR R0, [R1] // 将 sp 的值加载到 R0 + +__PendSV_SwitchTo + BL os_port_on_switch_success // 执行切换完成后的设置 + + /* ---- 加载目标栈 ---- */ + LDR R2, =g_os_port_switch_to_sp // 获取目标任务指针变量地址 + LDR R2, [R2] // 获取切换目标任务的指针 + LDR R0, [R2] // 获取目标任务的 sp 指针 + LDMIA R0!, {R2-R11} // 恢复 R2-R11 寄存器的值 + MOV LR, R2 // 恢复 LR 寄存器值 + MSR CONTROL, R3 // 恢复 CONTROL 寄存器值, 这里是在 ISR 中,设置暂时不生效,直到退出 ISR 才生效,所以没有问题 + ISB // 设置 CONTROL 后确保生效 + + MSR PSP, R0 // 更新 PSP 指向下一个任务的栈 + POP {R1} + MSR PRIMASK, R1 // 开中断 + BX LR + + ENDP + + END + diff --git a/os_port_gnu.S b/os_port_gnu.S new file mode 100644 index 0000000..cdecec6 --- /dev/null +++ b/os_port_gnu.S @@ -0,0 +1,80 @@ +#include "os_config.h" + + .syntax unified + .thumb + + .section .text.PendSV_Handler,"ax",%progbits + .global g_os_port_switch_from_sp + .global g_os_port_switch_to_sp + .global PendSV_Handler + .thumb_func +PendSV_Handler: + mrs r1, primask // 获取值 + cpsid i // 关闭中断 + PUSH {R1} + + LDR R1, =g_os_port_switch_from_sp // 加载当前任务指针地址 + LDR R1, [R1] // 加载 g_os_port_switch_from_sp 的值 + CBZ R1, __PendSV_SwitchTo + + /* ---- 压栈 ---- */ + MRS R0, PSP +#if(OS_CFG_CPU_FPU_PRESENT) + TST LR, #0x10 // 测试第4位如果为0压栈浮点寄存器 + VSTMDBEQ R0!, {S16-S31} +#endif + MOV R2, LR + MRS R3, CONTROL + STMDB R0!, {R2-R11} + + /* ---- sp值保存到变量中 ---- */ + STR R0, [R1] // 将 sp 的值加载到 R0 + +__PendSV_SwitchTo: + BL os_port_on_switch_success // 执行切换完成后的设置 + + /* ---- 加载目标栈 ---- */ + LDR R2, =g_os_port_switch_to_sp // 获取目标任务指针变量地址 + LDR R2, [R2] // 获取切换目标任务的指针 + LDR R0, [R2] // 获取目标任务的 sp 指针 + LDMIA R0!, {R2-R11} // 恢复 R2-R11 寄存器的值 + MOV LR, R2 // 恢复 LR 寄存器值 + MSR CONTROL, R3 // 恢复 CONTROL 寄存器值, 这里是在 ISR 中,设置暂时不生效,直到退出 ISR 才生效,所以没有问题 + ISB // 设置 CONTROL 后确保生效 +#if(OS_CFG_CPU_FPU_PRESENT) + TST LR, #0x10 + IT EQ + VLDMIAEQ R0!, {S16-S31} +#endif + MSR PSP, R0 // 更新 PSP 指向下一个任务的栈 + POP {R1} + MSR PRIMASK, R1 // 开中断 + BX LR + + + .section .text.SVC_Handler,"ax",%progbits + .global SVC_Handler + .global svc_exc_return + .global SVC_Handler_C + .type SVC_Handler, %function +SVC_Handler: + tst lr, #4 // 检查 EXC_RETURN (LR) 的位 2 + ite eq + mrseq r0, msp // 如果位 2 是 0,栈帧在 MSP + mrsne r0, psp // 如果位 2 是 1,栈帧在 PSP + ldr r1, =svc_exc_return + str lr, [r1] + bl SVC_Handler_C // 跳转到 C 实现,r0 作为第一个参数传入 + ldr r1, =svc_exc_return + ldr lr, [r1] + bx lr + + .section .text.cpu_clz,"ax",%progbits + .global cpu_clz + .thumb_func +cpu_clz: + CLZ R0, R0 + BX LR + + .align 4 + .end \ No newline at end of file