ucosII 在LM4F中的应用加入浮点运算——我这么写哪里不对?



参考  发的帖子,我做了如下修改,但是不成,程序跑飞,且编译器提示S16~S31  Bad register name symbol

请帮忙看看哪里有问题:

1. 使能KEIL 的 FPU和MCU 的FPU

    Target Option → Floating Point Hardware→Use FPU

    BSP_PreInit()中:

    ROM_FPUEnable();

    ROM_FPULazyStackingEnable();

 2. 修改OSTaskStkInit函数,加入浮点堆栈处理, FPSCR,S15~S0总计18*4=72个字节压栈,还有S31~S16总计 16*4=64字节压栈处理

    OSTaskStkInit()中:

    

...
stk = ptos; /* Load stack pointer */

/* Registers stacked as if auto-saved on exception */
// 要使用FPU,需要加入浮点堆栈处理, FPSCR,S15~S0总计18*4=72个字节压栈,还有S31~S16总计 16*4=64字节压栈处理
#if 1
*( stk) = (INT32U)0xccuL; /* No Name Register */
*(--stk) = (INT32U)0xdduL; /* FPSCR */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S15 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S14 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S13 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S12 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S11 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S10 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S9 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S8 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S7 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S6 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S5 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S4 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S3 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S2 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S1 */
*(--stk) = (INT32U)0xAAAAAAAAuL; /* S0 */
#endif

*(--stk) = (INT32U)0x01000000uL; /* xPSR */
*(--stk) = (INT32U)task; /* Entry Point PC */
*(--stk) = (INT32U)0xFFFFFFFEL; /* R14 (LR) (init value will */
/* cause fault if ever used) */ 
*(--stk) = (INT32U)0x12121212uL; /* R12 */
*(--stk) = (INT32U)0x03030303uL; /* R3 */
*(--stk) = (INT32U)0x02020202uL; /* R2 */
*(--stk) = (INT32U)0x01010101uL; /* R1 */
*(--stk) = (INT32U)p_arg; /* R0 : argument */

/* Remaining registers saved on process stack */
#if 1
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S31 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S30 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S29 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S28 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S27 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S26 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S25 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S24 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S23 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S22 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S21 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S20 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S19 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S18 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S17 */
*(--stk) = (INT32U)0xBBBBBBBBuL; /* S16 */
#endif

*(--stk) = (INT32U)0x11111111uL; /* R11 */
*(--stk) = (INT32U)0x10101010uL; /* R10 */

...

 3. 修改PendSV中断,加入浮点寄存器 S31~S16的压栈和出栈处理

OSPendSV
CPSID I ; Prevent interruption during context switch
MRS R0, PSP ; PSP is process stack pointer 栈指针
CBZ R0, OSPendSV_nosave ; 若PSP=0则执行OSPendSV_nosave函数

;SUB R0, R0, #0x40 ; Save remaining regs S16-S31 on process stack
;MOV R1, R0
;STM R1!, {S16-S31}

SUB R0, R0, #0x20 ; 压栈R4~R11,共8个寄存器,即4字节*8 = 32 = 0x20
MOV R1, R0
STM R1!, {R4-R11} ; 压栈

LDR R1, =OSTCBCur ; R1 = &OSTCBCur
LDR R1, [R1] ; R1 = *R1 = *OSTCBCur
STR R0, [R1] ; *R1 = R0 (R0 is SP of process being switched out)

; At this point, entire context of process has been saved
OSPendSV_nosave
PUSH {R14} ; Save LR exc_return value
LDR R0, =OSTaskSwHook ; 调用钩子函数OSTaskSwHook();
BLX R0
POP {R14} ; 恢复R14

LDR R0, =OSPrioCur ; 令当前优先级=最高优先级, OSPrioCur = OSPrioHighRdy
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]

LDR R0, =OSTCBCur ; 设置当前TCB指针 OSTCBCur = OSTCBHighRdy;
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]

LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
MOV R1, R0
LDM R1!, {R4-R11} ; Restore r4-11 from new process stack
ADDS R0, R0, #0x20 ; R4~R11 Regirst

;VLDM R0, {S16-S31} ; Restore S16-S31 from new process stack
;ADDS R0, R0, #0x40

MSR PSP, R0 ; PSP=R0, Load PSP with new process SP
ORR LR, LR, #0x04 ; 确保LR<2>=1,返回到使用进程堆栈
CPSIE I ; 开中断
BX LR ; Exception return will restore remaining context


  • 楼主发的3中的红色代码都被注释掉了,这些要保留的

    SUB R0, R0, #0x40 ; Save remaining regs S16-S31 on process stack
    MOV R1, R0
    STM R1!, {S16-S31}


    VLDM R0, {S16-S31} ; Restore S16-S31 from new process stack
    ADDS R0, R0, #0x40

  • 是的,被我注释掉了,因为编译器提示S16~S31  Bad register name symbol

  • 楼主的开发环境是ccs吗?

    要看看楼主的编译器是否是用的m4的

  • 我的开发环境是Keil MDK

    版本信息:

    IDE-Version:
    μVision V4.60.0.0
    Toolchain: MDK-ARM Standard Version: 4.60.0.0
    Assembler: Armasm.Exe V5.02.0.28
    Linker/Locator: ArmLink.Exe V5.02.0.28
    Librarian: ArmAr.Exe V5.02.0.28
    Hex Converter: FromElf.Exe V5.02.0.28
    CPU DLL: SARMCM3.DLL V4.60.0.0
    Dialog DLL: DCM.DLL V1.6.0.0
    Target DLL: lmidk-agdi.dll V???
    Dialog DLL: TCM.DLL V1.5.0.0

  • 我测试用的硬件环境是 LM4F2325QD EVALUATION BOARD

  • Keil的话寄存器名字可能不一样,汇编用法也会有些区别。要看看编译器的器件手册了,我这里没有,楼主可以看看Keil的帮助

    楼主注释掉的程序,会导致弹栈数据错误导致跑飞,所以不能少

  • 原来Keil用的不是S16-S31,而是D8-D15。不过还是不行,跑不起来。

    OSPendSV
    CPSID I ; Prevent interruption during context switch
    MRS R0, PSP ; PSP is process stack pointer 栈指针
    CBZ R0, OSPendSV_nosave ; 若PSP=0则执行OSPendSV_nosave函数

    SUB R0, R0, #0x20 ; 压栈R4~R11,共8个寄存器,即4字节*8 = 32 = 0x20
    STM R0, {R4-R11} ; 压栈
    SUB R0, R0, #0x40 ; Save remaining regs S16-S31 on process stack
    VSTM R0, {D8-D15}

    LDR R1, =OSTCBCur ; R1 = &OSTCBCur
    LDR R1, [R1] ; R1 = *R1 = *OSTCBCur
    STR R0, [R1] ; *R1 = R0 (R0 is SP of process being switched out)

    ; At this point, entire context of process has been saved
    OSPendSV_nosave
    PUSH {R14} ; Save LR exc_return value
    LDR R0, =OSTaskSwHook ; 调用钩子函数OSTaskSwHook();
    BLX R0
    POP {R14} ; 恢复R14

    LDR R0, =OSPrioCur ; 令当前优先级=最高优先级, OSPrioCur = OSPrioHighRdy
    LDR R1, =OSPrioHighRdy
    LDRB R2, [R1]
    STRB R2, [R0]

    LDR R0, =OSTCBCur ; 设置当前TCB指针 OSTCBCur = OSTCBHighRdy;
    LDR R1, =OSTCBHighRdy
    LDR R2, [R1]
    STR R2, [R0]

    LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;

    VLDM R0, {D8-D15} ; Restore S16-S31 from new process stack
    ADD R0, R0, #0x40
    LDM R0, {R4-R11} ; Restore r4-11 from new process stack
    ADD R0, R0, #0x20 ; R4~R11 Regirst

    BIC.W LR, LR, #0X10 ; Set exception return uses floating-point state

    MSR PSP, R0 ; PSP=R0, Load PSP with new process SP
    ORR LR, LR, #0x04 ; 确保LR<2>=1,返回到使用进程堆栈
    CPSIE I ; 开中断
    BX LR ; Exception return will restore remaining context

  • 楼主说的跑不起来是无法编译还是运行时候会跑飞?

  • 上传我的工程,请帮忙看看吧,折腾我好几天了。

    为了缩小体积,删除了 MyDemo\FWlib 文件夹下的 driverlib-cm4f.lib 和 grlib-cm4f.lib

    MyDemo.rar
  • 把S16-Sf1改成D8-D15后,已经可以编译了,但是会跑飞

    运行到   ROM_FPUEnable();    时,就会跳到FaultISR

  • 楼主先用FPUEnable()先试试,进入FaultISR以后看看是什么原因进的FaultISR?


    不要着急省体积啥的,一步步来。

  • 把所有的ROM_都去掉后,跟踪发现,在OLED显示屏初始化SSI总线时出问题了。

    在执行函数SSIConfigSetExpClk时,会调用SysCtlClockGet(),虽然我设置为16M,但返回值却是1M,从而在SSIConfigSetExpClk时,

    ulMaxBitRate = ulSSIClk / ulBitRate   1M/4M等于0了,然后下面再计算ulSCR = (ulMaxBitRate / ulPreDiv) - 1得到一个非常大的unsi long值,程序被堵在while(ulSCR > 255);

    把DISPLAY_SSI_CLOCK由4M降为0.25M,也不行,虽然不会被堵在while(ulSCR > 255)了,但在通过SSI发数据给OLED时,却会被堵在SSIDataPut里的while循环中...

    昨晚我把TI提供的grlib移除,自己写了OLED的驱动,加到ucos里,就没有问题,没开FPU,运行了UART、LED、OLED三个进程,一切正常...

  • 楼主很细心!感谢分享!

    SysCtlClockGet得到值不一定是准确的,在它之前一定需要通过(且只通过)SysCtlClockSet来配置时钟才行。