
因项目需要使用STM32F417的硬件浮点单元,但当时Micrium的官方移植µC/OS-III V3.03.01 (2013/01/23)不支持FPU,因此需要修改代码添加FPU支持。 首先,为了便于控制是否使用FPU,定义一个宏 USE_FPU。需要使用FPU时在MDK的工程选项中定义这个宏,要在”C/C++“和”Asm“选项卡中都定义,这样无论C代码还是汇编代码中都可以使用这个宏了。需要注意的是,预定义宏__TARGET_FPU_VFP只能在C文件中使用,汇编文件中不能使用。 然后,在CPU初始化代码中设置FPU。在官方移植中,设置代码已经有了,但被注释掉了,只要取消注释即可,然后再设置代码前后添加条件编译: IF ![]() ;Enable FPU ;Use reset settings: automatic lazy FPU state preservation LDR R0, =0xE000ED88 ; Enable CP10,CP11 LDR R1,[R0] <span lang="EN-US" style="font-size: 9pt; font-family: Arial, sans-serif;"> ORR R1,R1,#(0xF |
RE:【MCU实战经验】向μC/OS-III在STM32F4xx上的移植中添加FPU支持
CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task,
void *p_arg,
CPU_STK *p_stk_base,
CPU_STK *p_stk_limit,
CPU_STK_SIZE stk_size,
OS_OPT opt)
{
CPU_STK *p_stk;
(void)opt; /* Prevent compiler warning */
p_stk = &p_stk_base[stk_size]; /* Load stack pointer */
/* Align the stack to 8-bytes. */
p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8);
/* Registers stacked as if auto-saved on exception */
#ifdef USE_FPU
*--p_stk = (CPU_STK)0xABCD1234u; /* Reserved */
*--p_stk = (CPU_STK)0x00000000u; /* FPSCR */
*--p_stk = (CPU_STK)0x7FC01515u; /* S15 */
*--p_stk = (CPU_STK)0x7FC01414u; /* S14 */
*--p_stk = (CPU_STK)0x7FC01313u; /* S13 */
*--p_stk = (CPU_STK)0x7FC01212u; /* S12 */
*--p_stk = (CPU_STK)0x7FC01111u; /* S11 */
*--p_stk = (CPU_STK)0x7FC01010u; /* S10 */
*--p_stk = (CPU_STK)0x7FC00909u; /* S9 */
*--p_stk = (CPU_STK)0x7FC00808u; /* S8 */
*--p_stk = (CPU_STK)0x7FC00707u; /* S7 */
*--p_stk = (CPU_STK)0x7FC00606u; /* S6 */
*--p_stk = (CPU_STK)0x7FC00505u; /* S5 */
*--p_stk = (CPU_STK)0x7FC00404u; /* S4 */
*--p_stk = (CPU_STK)0x7FC00303u; /* S3 */
*--p_stk = (CPU_STK)0x7FC00202u; /* S2 */
*--p_stk = (CPU_STK)0x7FC00101u; /* S1 */
*--p_stk = (CPU_STK)0x7FC00000u; /* S0 */
#endif /* USE_FPU */
*--p_stk = (CPU_STK)0x01000000u; /* xPSR */
*--p_stk = (CPU_STK)p_task; /* Entry Point */
*--p_stk = (CPU_STK)OS_TaskReturn; /* R14 (LR) */
*--p_stk = (CPU_STK)0x12121212u; /* R12 */
*--p_stk = (CPU_STK)0x03030303u; /* R3 */
*--p_stk = (CPU_STK)0x02020202u; /* R2 */
*--p_stk = (CPU_STK)p_stk_limit; /* R1 */
*--p_stk = (CPU_STK)p_arg; /* R0 : argument */
/* Remaining registers saved on process stack */
#ifdef USE_FPU
*--p_stk = (CPU_STK)0x7FC03131u; /* S31 */
*--p_stk = (CPU_STK)0x7FC03030u; /* S30 */
*--p_stk = (CPU_STK)0x7FC02929u; /* S29 */
*--p_stk = (CPU_STK)0x7FC02828u; /* S28 */
*--p_stk = (CPU_STK)0x7FC02727u; /* S27 */
*--p_stk = (CPU_STK)0x7FC02626u; /* S26 */
*--p_stk = (CPU_STK)0x7FC02525u; /* S25 */
*--p_stk = (CPU_STK)0x7FC02424u; /* S24 */
*--p_stk = (CPU_STK)0x7FC02323u; /* S23 */
*--p_stk = (CPU_STK)0x7FC02222u; /* S22 */
*--p_stk = (CPU_STK)0x7FC02121u; /* S21 */
*--p_stk = (CPU_STK)0x7FC02020u; /* S20 */
*--p_stk = (CPU_STK)0x7FC01919u; /* S19 */
*--p_stk = (CPU_STK)0x7FC01818u; /* S18 */
*--p_stk = (CPU_STK)0x7FC01717u; /* S17 */
*--p_stk = (CPU_STK)0x7FC01616u; /* S16 */
#endif /* USE_FPU */
*--p_stk = (CPU_STK)0x11111111u; /* R11 */
*--p_stk = (CPU_STK)0x10101010u; /* R10 */
*--p_stk = (CPU_STK)0x09090909u; /* R9 */
*--p_stk = (CPU_STK)0x08080808u; /* R8 */
*--p_stk = (CPU_STK)0x07070707u; /* R7 */
*--p_stk = (CPU_STK)0x06060606u; /* R6 */
*--p_stk = (CPU_STK)0x05050505u; /* R5 */
*--p_stk = (CPU_STK)0x04040404u; /* R4 */
return (p_stk);
}
其中红色代码是新添加的处理浮点寄存器的代码。特别注意注释为Reserved的第2行红字,在任务栈中保存这个保留的32位字是必须的,其值没有特别要求,请参考ARMv7-M Architecture Reference Manual (DDI0403D)。
回复:【MCU实战经验】向μC/OS-III在STM32F4xx上的移植中添加FPU支持
OS_CPU_PendSVHandler
CPSID I ; Prevent interruption during context switch
MRS R0, PSP ; PSP is process stack pointer
CBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time
IF
VMRS R1, FPSCR ; Dummy read access to force FPU state preservation and FPSCR clear
SUBS R0, R0, #0x40 ; Save remaining FP regs s16-s31 on process stack
VSTM R0, {D8-D15}
ENDIF
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
STM R0, {R4-R11}
LDR R1, =OSTCBCurPtr ; OSTCBCurPtr->OSTCBStkPtr = SP;
LDR R1, [R1]
STR R0, [R1] ; R0 is SP of process being switched out
; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
PUSH {R14} ; Save LR exc_return value
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
BLX R0
POP {R14}
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
LDR R0, =OSTCBCurPtr ; OSTCBCurPtr = OSTCBHighRdyPtr;
LDR R1, =OSTCBHighRdyPtr
LDR R2, [R1]
STR R2, [R0]
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;
LDM R0, {R4-R11} ; Restore r4-11 from new process stack
ADDS R0, R0, #0x20
IF
VLDM R0, {D8-D15} ; Restore s16-s31 from new process stack
ADDS R0, R0, #0x40
ENDIF
MSR PSP, R0 ; Load PSP with new process SP
ORR LR, LR, #0x04 ; Ensure exception return uses process stack
IF
AND LR, LR, #0xFFFFFFEF ; Clear LR to ensure FPU state restore
LDR R0, =0xE000EF34 ; Clear FPCCR (LSPACT) to ensure FPU state restore
LDR R1, [R0]
AND R1, R1, #0xFFFFFFFE
STR R1, [R0]
ENDIF
CPSIE I
BX LR ; Exception return will restore remaining context
其中红色代码是新添加的处理浮点寄存器的代码。几点说明:
1)根据FPCCR的设置值(就是复位值ASPEN=1, LSPEN=1),如果发生PendSV异常时CONTROL.FPCA=1,在进入PendSV异常处理函数时,硬件会自动在任务栈保留浮点寄存器占用的空间,首先通过读FPSCR寄存器让硬件自动保存浮点寄存器S0~S15和浮点状态寄存器FPSCR到任务栈,然后手动保存其余的浮点寄存器S16~S31。
2)在退出PendSV异常处理函数前,清除LR第4位并清除FPCCR寄存器第0位(LSPACT),目的是让硬件在退出PendSV异常处理函数时自动从任务栈恢复浮点寄存器S0~S15和浮点状态寄存器FPSCR。这样如果新任务是第一次运行,则可实现从任务栈加载浮点寄存器初值,否则是从任务栈加载以前保存的值,并且可以保证每个任务运行时都有CONTROL.FPCA=1。
3)虽然使能了延迟保存浮点状态功能,但因为总是有CONTROL.FPCA=1,因此无论旧任务是否执行过浮点指令,在进入PendSV异常处理函数执行任务切换时,都会保存旧任务的浮点寄存器,加载新任务的浮点寄存器,没有利用延迟保存浮点状态功能可减小中断延迟的优势。
RE:【MCU实战经验】向μC/OS-III在STM32F4xx上的移植中添加FPU支持
回复:【MCU实战经验】向μC/OS-III在STM32F4xx上的移植中添加FPU支持
回复:【MCU实战经验】向μC/OS-III在STM32F4xx上的移植中添加FPU支持
谢谢,在F407VG上通过
RE:【MCU实战经验】向μC/OS-III在STM32F4xx上的移植中添加FPU支持