|
因项目需要使用STM32F417的硬件浮点单元,但当时Micrium的官方移植µC/OS-III V3.03.01 (2013/01/23)不支持FPU,因此需要修改代码添加FPU支持。 N- B5 H1 {& _5 \ 首先,为了便于控制是否使用FPU,定义一个宏 USE_FPU。需要使用FPU时在MDK的工程选项中定义这个宏,要在”C/C++“和”Asm“选项卡中都定义,这样无论C代码还是汇编代码中都可以使用这个宏了。需要注意的是,预定义宏__TARGET_FPU_VFP只能在C文件中使用,汇编文件中不能使用。2 ]6 w' I. X5 k1 n1 U8 H, g 然后,在CPU初始化代码中设置FPU。在官方移植中,设置代码已经有了,但被注释掉了,只要取消注释即可,然后再设置代码前后添加条件编译:4 O, L, E" u, H- N% y IF EF: USE_FPU;Enable FPU" v' k) M! h+ {" \/ ` ;Use reset settings: automatic lazy FPU state preservation LDR R0, =0xE000ED88 ; Enable CP10,CP11 LDR R1,[R0]# |, A$ _9 y% I, f7 q9 {" s2 A- F - i- {( P5 W* J1 A9 W <span lang="EN-US" style="font-size: 9pt; font-family: Arial, sans-serif;"> ORR R1,R1,#(0xF |
【福利三:雨露均沾·逢7狂欢】之四:用一个定时器同步另外两个定时器输出PWM
【逢7发帖赢大礼】STM32开发之WIFI实时时钟
【逢7发帖赢大礼】STM32开发之指纹识别!
【逢7发帖赢大礼】STM32开发之环境空气质量监测
【逢7发帖赢大礼】STM32开发之人体实时运动信息监测!
【逢7发帖赢大礼】STM32开发之IC门禁卡UID读取方法!
【逢7发帖赢大礼】全网最简单的Arduino_STM32开发环境搭建教程!
STM32F4中文用户手册
STM32F400、STM32F402 Cortex-M4超值单片机
SPI 高温读错最后一位?STM32F42xx 官方根治方案
微信公众号
手机版
RE:【MCU实战经验】向μC/OS-III在STM32F4xx上的移植中添加FPU支持
CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task,, N& t1 U" b" e) U2 k% X
void *p_arg," @0 c) d8 \7 A. P6 K& X
CPU_STK *p_stk_base,
CPU_STK *p_stk_limit,8 \. p2 p& S9 q! i" a: a \- P
CPU_STK_SIZE stk_size,
OS_OPT opt)
{
CPU_STK *p_stk;
% W# B8 g U6 P% d' h/ C1 J5 H
(void)opt; /* Prevent compiler warning */
p_stk = &p_stk_base[stk_size]; /* Load stack pointer */
/* Align the stack to 8-bytes. */. s& e* [+ C- V! E' c% x; ]
p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8);
/* Registers stacked as if auto-saved on exception */$ V: k1 h" R6 }1 B3 B B1 _# J) ^
#ifdef USE_FPU* B6 u/ n$ ~& T
*--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 */- w( H; r% k2 ~! r' w
*--p_stk = (CPU_STK)0x7FC01212u; /* S12 */
*--p_stk = (CPU_STK)0x7FC01111u; /* S11 */3 l' M# L: k$ X8 h$ A$ P
*--p_stk = (CPU_STK)0x7FC01010u; /* S10 */. N' U8 G( [5 Y% H7 M
*--p_stk = (CPU_STK)0x7FC00909u; /* S9 */5 e/ v5 K% k1 a5 g1 P# [- T K
*--p_stk = (CPU_STK)0x7FC00808u; /* S8 */# d* K& v! ^+ j& i
*--p_stk = (CPU_STK)0x7FC00707u; /* S7 */
*--p_stk = (CPU_STK)0x7FC00606u; /* S6 */
*--p_stk = (CPU_STK)0x7FC00505u; /* S5 */
*--p_stk = (CPU_STK)0x7FC00404u; /* S4 */# |, A4 r: d+ D$ P
*--p_stk = (CPU_STK)0x7FC00303u; /* S3 */& m0 F3 E5 H) s& i5 Y; V3 E Y
*--p_stk = (CPU_STK)0x7FC00202u; /* S2 */
*--p_stk = (CPU_STK)0x7FC00101u; /* S1 */+ M9 n9 \* {6 {! q" r
*--p_stk = (CPU_STK)0x7FC00000u; /* S0 */
#endif /* USE_FPU */
*--p_stk = (CPU_STK)0x01000000u; /* xPSR */: G. H+ c& v! A8 [# e( {+ Z
*--p_stk = (CPU_STK)p_task; /* Entry Point */- y, C" }/ ~% _0 _( X. V$ `' d
*--p_stk = (CPU_STK)OS_TaskReturn; /* R14 (LR) */
*--p_stk = (CPU_STK)0x12121212u; /* R12 */3 \7 E8 e5 _! o4 s H
*--p_stk = (CPU_STK)0x03030303u; /* R3 */
*--p_stk = (CPU_STK)0x02020202u; /* R2 */
*--p_stk = (CPU_STK)p_stk_limit; /* R1 */: A( z/ c: ~8 u8 u/ p
*--p_stk = (CPU_STK)p_arg; /* R0 : argument */' f. S( h" e; R
/* Remaining registers saved on process stack */; C9 D/ v$ S( I
#ifdef USE_FPU7 c0 T9 v( _: V, Y
*--p_stk = (CPU_STK)0x7FC03131u; /* S31 */
*--p_stk = (CPU_STK)0x7FC03030u; /* S30 */
*--p_stk = (CPU_STK)0x7FC02929u; /* S29 */
*--p_stk = (CPU_STK)0x7FC02828u; /* S28 */( k+ `5 y/ q# W1 P9 C9 F' `
*--p_stk = (CPU_STK)0x7FC02727u; /* S27 */. n, z2 C9 K d7 I* k; V& N: c
*--p_stk = (CPU_STK)0x7FC02626u; /* S26 */4 S& H5 _# \9 Q; D V& u9 a1 ~* _
*--p_stk = (CPU_STK)0x7FC02525u; /* S25 */
*--p_stk = (CPU_STK)0x7FC02424u; /* S24 */
*--p_stk = (CPU_STK)0x7FC02323u; /* S23 */
*--p_stk = (CPU_STK)0x7FC02222u; /* S22 */) z+ [, L/ E: M( N
*--p_stk = (CPU_STK)0x7FC02121u; /* S21 */
*--p_stk = (CPU_STK)0x7FC02020u; /* S20 */
*--p_stk = (CPU_STK)0x7FC01919u; /* S19 */) ^ O& W! K& ^* Z3 J
*--p_stk = (CPU_STK)0x7FC01818u; /* S18 */0 t/ G* {; ^$ J S: T& v/ x0 Z* _
*--p_stk = (CPU_STK)0x7FC01717u; /* S17 */: ^& i/ O+ `7 y6 ^. P
*--p_stk = (CPU_STK)0x7FC01616u; /* S16 */$ \$ S1 P d; Z; i1 q: y
#endif /* USE_FPU */# p) j" s9 P( R
*--p_stk = (CPU_STK)0x11111111u; /* R11 */
*--p_stk = (CPU_STK)0x10101010u; /* R10 */ X( x$ M' o0 q) _
*--p_stk = (CPU_STK)0x09090909u; /* R9 */, _! T$ P3 H+ v1 D8 D% d' a
*--p_stk = (CPU_STK)0x08080808u; /* R8 */+ u0 @$ }+ b4 a q+ V; [
*--p_stk = (CPU_STK)0x07070707u; /* R7 */3 X* @) h+ ?4 Z/ e! J: r) P6 j
*--p_stk = (CPU_STK)0x06060606u; /* R6 */# L$ ?9 M! D. L5 H% Z% y
*--p_stk = (CPU_STK)0x05050505u; /* R5 */
*--p_stk = (CPU_STK)0x04040404u; /* R4 */0 a: @- b6 _- j& E$ @( b
return (p_stk);; q# Y. ]& ?2 \! v) S
} f. C% ~% N) d9 ^, x" |' S
其中红色代码是新添加的处理浮点寄存器的代码。特别注意注释为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- X' O$ m0 E1 u$ X( [+ H1 K
MRS R0, PSP ; PSP is process stack pointer/ B) T# X- K, d# X6 W
CBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time
% y7 ^; Y1 H1 L( e" c1 o* B: N1 a
IF
VMRS R1, FPSCR ; Dummy read access to force FPU state preservation and FPSCR clear' ?1 f8 r1 i+ i' R9 h! u" x
SUBS R0, R0, #0x40 ; Save remaining FP regs s16-s31 on process stack1 J- ?8 y$ B* X( ^2 z. b1 p) v
VSTM R0, {D8-D15}* @. t; K5 s% S: `1 D; Q4 j
ENDIF4 _) d/ K# |' u) I
# ?0 V1 f6 K: h; p4 Y
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack! [% ~8 T# ^: n+ y. |
STM R0, {R4-R11}
) M. {( f3 d7 `! e- S
LDR R1, =OSTCBCurPtr ; OSTCBCurPtr->OSTCBStkPtr = SP;* k, q( F6 j; m
LDR R1, [R1]: ^4 Y3 a! r+ o
STR R0, [R1] ; R0 is SP of process being switched out) q$ j/ K* X0 h, \" n
7 e$ _- u; z/ v3 y7 I5 w
; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
PUSH {R14} ; Save LR exc_return value% R5 K0 o$ ^9 E3 J
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
BLX R0
POP {R14}7 G! C* c3 a# J" N2 @6 j: }5 u# f
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy! D5 q% i7 B$ E2 }" m T
LDRB R2, [R1]
STRB R2, [R0]9 Y( a, E! Z$ P& `2 w2 M
! }- x7 [& t5 S' l. A, V& q
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
* Z$ j k) o8 B* V3 R& |
IF
VLDM R0, {D8-D15} ; Restore s16-s31 from new process stack
ADDS R0, R0, #0x40) {, d- m7 J. b( j$ L: x! b' E
4 B: ~/ G! r& O# G8 e" t- b
ENDIF8 y4 l9 k2 P1 _1 I' o
MSR PSP, R0 ; Load PSP with new process SP
ORR LR, LR, #0x04 ; Ensure exception return uses process stack; N$ V; c' W- I% o0 S) p
8 q% Q2 s7 t" O1 M2 s& w* ]4 k' Z
IF
9 |9 C; ^: C# h( A2 _
AND LR, LR, #0xFFFFFFEF ; Clear LR to ensure FPU state restore
LDR R0, =0xE000EF34 ; Clear FPCCR (LSPACT) to ensure FPU state restore. H+ v3 [9 M3 ~' r O- o2 l7 M
LDR R1, [R0]- Q7 r1 r, P+ h7 V, G7 P
AND R1, R1, #0xFFFFFFFE
STR R1, [R0]
) E5 G9 W7 J4 B
ENDIF
' R, D! b$ Q5 U1 o ?; _
CPSIE I6 r% a: c3 Q. F# J! E- z* p) k- E
BX LR ; Exception return will restore remaining context
其中红色代码是新添加的处理浮点寄存器的代码。几点说明:9 ~* @0 s$ ?% Q! |
1)根据FPCCR的设置值(就是复位值ASPEN=1, LSPEN=1),如果发生PendSV异常时CONTROL.FPCA=1,在进入PendSV异常处理函数时,硬件会自动在任务栈保留浮点寄存器占用的空间,首先通过读FPSCR寄存器让硬件自动保存浮点寄存器S0~S15和浮点状态寄存器FPSCR到任务栈,然后手动保存其余的浮点寄存器S16~S31。 X: E" @% K s2 k
2)在退出PendSV异常处理函数前,清除LR第4位并清除FPCCR寄存器第0位(LSPACT),目的是让硬件在退出PendSV异常处理函数时自动从任务栈恢复浮点寄存器S0~S15和浮点状态寄存器FPSCR。这样如果新任务是第一次运行,则可实现从任务栈加载浮点寄存器初值,否则是从任务栈加载以前保存的值,并且可以保证每个任务运行时都有CONTROL.FPCA=1。. F* o0 A% U* y' U" l- T
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上通过# }* u7 ^- f- f6 o: `; }- b
RE:【MCU实战经验】向μC/OS-III在STM32F4xx上的移植中添加FPU支持