[求助] MSP432用上μC/OS-III,却开不了FPU

TWENLONG   2015-9-27 16:22 楼主
最近接触了μC/OS-III,手里的MSP432LaunchPad都尘封了好久了,于是想着让它用上μC/OS-III。在Micrium公司官网下载已经移植好的示例工程,这是为这块板子适配的,拿来就可以用,里面包含了IAR和CCS的工程文件。(所有文件在文末有百度云下载) 无标题.png 先在IAR上玩一下,直接下载调试运行,就可以看到LED1在闪烁了,S1可以调节闪烁频率,S2用来控制RGB LED的点亮 官方的工程文件里面主要是BSP里面的内容需要根据自己的实际情况改写,我这种新手还不习惯官方的写法,于是进行了一番删减 官方的启动文件同之前的不一样,中断向量表里面的函数入口地址每个都已经写好了,复位程序里面就关掉了看门狗,
  1. /*
  2. *********************************************************************************************************
  3. * EXCEPTION / INTERRUPT VECTOR TABLE
  4. *
  5. * Note(s) : (1) The Cortex-M4 may have up to 256 external interrupts, which are the final entries in the
  6. * vector table. The MSP432 has 65 external interrupt vectors.
  7. *********************************************************************************************************
  8. */
  9. __root const APP_INTVECT_ELEM __vector_table[] @ ".intvec" = {
  10. { .Ptr = (void *)__sfe( "CSTACK" )},
  11. /* 000 Initial stack pointer. */
  12. App_Reset_ISR, /* 001 Initial program counter. */
  13. App_NMI_ISR, /* 002 Non-maskable interrupt. */
  14. App_Fault_ISR, /* 003 Hard fault exception. */
  15. App_Spurious_ISR, /* 004 Reserved interrupt 4. */
  16. App_BusFault_ISR, /* 005 Bus fault exception. */
  17. App_UsageFault_ISR, /* 006 Usage fault exception. */
  18. App_Spurious_ISR, /* 007 Reserved interrupt 7. */
  19. App_Spurious_ISR, /* 008 Reserved interrupt 8. */
  20. App_Spurious_ISR, /* 009 Reserved interrupt 9. */
  21. App_Spurious_ISR, /* 010 Reserved interrupt 10. */
  22. App_Spurious_ISR, /* 011 A supervisor call exception. */
  23. App_Spurious_ISR, /* 012 Debug Monitor. */
  24. App_Spurious_ISR, /* 013 Reserved interrupt 13. */
  25. OS_CPU_PendSVHandler, /* 014 PendSV exception. */
  26. OS_CPU_SysTickHandler, /* 015 SysTick Interrupt. */
  27. BSP_IntHandlerPSS, /* 016 IRQ[ 0] PSS ISR */
  28. BSP_IntHandlerCS, /* 017 IRQ[ 1] CS ISR */
  29. .
OS_PendSVHandler和OS_SysTickHandler在移植文件os_cpu_a.asm里面定义,前者用来上下文切换,后者是SysTick定时器的中断服务程序,外设的中断名都已经定义好了,假如PORT6中断发生,那就会执行BSP_IntHandlerPORT6,这个函数在bsp_int.c文件里:
  1. <blockquote>void BSP_IntHandlerPORT6 (void) { BSP_IntHandler(BSP_INT_ID_PORT6); }
然后又执行BSP_IntHandler(BSP_INT_DI_PORT6),
  1. void BSP_IntHandler (CPU_INT16U src_nbr)
  2. {
  3. CPU_FNCT_VOID isr;
  4. CPU_SR_ALLOC();
  5. CPU_CRITICAL_ENTER(); /* Tell the OS that we are starting an ISR */
  6. OSIntEnter();
  7. CPU_CRITICAL_EXIT();
  8. if (src_nbr < BSP_INT_ID_MAX) {
  9. isr = BSP_IntVectTbl[src_nbr];
  10. if (isr != (CPU_FNCT_VOID)0) {
  11. isr();
  12. }
  13. }
  14. OSIntExit(); /* Tell the OS that we are leaving the ISR */
  15. }
这个函数先定义了一个CPU_FNCT_VIOD类型的变量isr,这是个指向函数指针,该函数参数和返回值均为空,然后根据传入的中断源ID号从BSP_IntVecTbl里面取得地址,BSP_IntVecTbl在bsp_int.c里面定义:
  1. static CPU_FNCT_VOID BSP_IntVectTbl[BSP_INT_ID_MAX];
这个中断向量表由以下函数初始化:
  1. void BSP_IntInit (void)
  2. {
  3. CPU_INT32U int_id;
  4. for (int_id = 0; int_id < BSP_INT_ID_MAX; int_id++) { /* Initialize each interrupt with Dummy Handler */
  5. BSP_IntVectSet((CPU_INT08U)int_id,
  6. (CPU_FNCT_VOID)BSP_IntHandlerDummy);
  7. }
  8. }
  9. void BSP_IntVectSet (CPU_INT08U int_id,
  10. CPU_FNCT_VOID isr)
  11. {
  12. CPU_SR_ALLOC();
  13. if (int_id < BSP_INT_ID_MAX) {
  14. CPU_CRITICAL_ENTER();
  15. BSP_IntVectTbl[int_id] = isr; /* Setup interrupt specified in the vector table */
  16. CPU_CRITICAL_EXIT();
  17. }
  18. }
初始化完毕后向量表全部指向BSP_IntHandlerDummy,这个函数死循环,什么也不做:
  1. static void BSP_IntHandlerDummy (void)
  2. {
  3. while (DEF_TRUE) {
  4. ;
  5. }
  6. }
所以要用中断时先要调用BSP_IntVectSet 设置对应的中断向量表,比如在官方的例程里面开启了按键的中断:
  1. BSP_IntVectSet(BSP_INT_ID_PORT1, App_Port1_ISR);
App_Port1_ISR就是自己定义的中断服务程序了,这真是绕了好大一圈啊,这么做我想也是有道理的,不过我不习惯,就给改了,启动代码里面全用App_Spurious_ISR代替BSP_IntHandlerxxx,用到某个中断就把函数名替换过来,这就习惯了,跟原来差不多了,官方提供的一些中断初始化之类的函数就不要了,最后bsp_int.c文件里面就删减得没东西了。 再对着例程看看,任务运行之前都干了些啥 先CPU初始化,CPU name 什么的:CPU_Init(); 关中断,以免初始化过程被打断:BSP_IntDisAll(); 这个函数就是执行CPU_IntDis(),就是两条汇编指令,所以可以替换掉; 接着创建启动任务,启动任务里面执行BSP_Init():
  1. void BSP_Init (void)
  2. {
  3. BSP_SysInit(); /* -------------- CLOCK INITIALIZATION --------------- */
  4. BSP_IntInit(); /* ------------- INTERRUPT INITIALIZATION ------------ */
  5. BSP_LED_Init(); /* ---------------- LED INITIALIZATION --------------- */
  6. BSP_PB_Init(); /* ------------ PUSH BUTTON INITIALIZATION ----------- */
  7. }
BSP_SysInit()函数把MCLK设为48M,SysTick定时器时间间隔为1ms,然后开启了中断,我觉得中断的开启放在外面是不是要好一点
  1. void BSP_SysInit (void)
  2. {
  3. /* - Configure DCO to 48MHz. Make MCLK use the DCO. - */
  4. CSKEY = CS_ACCESS_KEY; /* Unlock CS module for register access. */
  5. CSCTL0 = 0u; /* Reset tuning parameters. */
  6. CSCTL0 = DCORSEL_5; /* Set DCO to 48MHz operation. */
  7. DEF_BIT_SET(CSCTL0, DCOEN); /* Enable DCO (digitally controlled oscillator). */
  8. /* Select DCO as the MCLK with no divider. */
  9. DEF_BIT_CLR(CSCTL1, (SELM_M | DIVM_M));
  10. DEF_BIT_SET(CSCTL1, SELM_3);
  11. CSKEY = 0u; /* Lock CS module to protect it from inadvertent access.*/
  12. /* Enable SysTick Module */
  13. DEF_BIT_SET(BSP_SYS_REG_SCS_STCSR,
  14. SYSTICK_STCSR_CLKSOURCE | SYSTICK_STCSR_ENABLE);
  15. /* Set SysTick period to 1/48000 */
  16. if (((CSCTL0 & DCORSEL_M) >> 16u) == 5u) {
  17. SYSTICK_STRVR = 48000u;
  18. }
  19. CPU_IntEn(); /* Enable Interrupts. */
  20. }
BSP_IntInit()就是前面说的设置中断向量表,我就不用它了。接着是LED和按键的初始化 然后执行BSP_Tick_Init(),根据所设定的系统滴答设置SysTick定时器的时间间隔,SysTick在Cortex-M4内核的MCU上应该是一样的,OS_CPU_SysTickInit里面开启了SysTick的中断,我把BSP_Tick_Init函数也写进BSP_Init里面了,bsp_sys.c和bsp_sys.h文件我就不要了
  1. void BSP_Tick_Init (void)
  2. {
  3. CPU_INT32U cpu_clk_freq;
  4. CPU_INT32U cnts;
  5. cpu_clk_freq = BSP_CPU_ClkFreq(); /* Determine SysTick reference freq. */
  6. #if (OS_VERSION >= 30000u)
  7. cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz; /* Determine nbr SysTick increments. */
  8. #else
  9. cnts = cpu_clk_freq / (CPU_INT32U)OS_TICKS_PER_SEC; /* Determine nbr SysTick increments. */
  10. #endif
  11. OS_CPU_SysTickInit(cnts); /* Init uC/OS periodic time src (SysTick). */
  12. }
到这儿初始化工作差不多就完了,然后就可以创建自己的任务了。 调试之前需对工程设置一番: Debugger里面的Setup选项卡Driver选择TI XDS: 捕获.PNG Download选项卡勾上Use flash loader(s): 捕获4.PNG IAR提供了调试UC/OS的插件,可以勾上μC/OS-III,如果安装了μC/Prob还可勾上: 捕获5.PNG TI XDS里面Setup选项卡选择调试器和调试包的安装路径: 捕获3.PNG 然后就可以进入调试了,勾选了插件之后菜单栏会有μC/OS-III,任务列表,CPU使用率,堆栈使用量等等都可以显示出来,可是我感觉这个这个显示的并不准确呀,而且不能实时地刷新 捕获6.PNG 我安装了μC/Prob,这个软件也可以显示μC/OS的各种信息,不过教育版使用有限制,首先设置连接方式,有很多可选项,这里由于IAR里面勾选了插件,选择TCP/IP,填上自己的IP地址就可以了 捕获7.PNG 接着加载ELF文件,IAR输出的.out文件就是ELF格式 捕获8.PNG 右键project1,添加μC/OS-III Awareness,并在datascreen里面添加一个温度计,把一个全局变量和温度计关联起来,直接托上去 捕获9.PNG 接着就可以点run了(IAR需要在调试界面),也有各种信息,全局变量也可以显示,可是为啥有时候是实时的,有时候又不是啊??? 捕获10.PNG 捕获11.PNG 接着测试FPU,MSP432要用PFU的话,是不是首先编译器要开启FPU,然后程序里面再用库函数开启FPU?我在工程选项里面选择了使用FPU,创建了一个定时器任务,里面调用库函数MAP_FPU_enableModule(),然后每秒对浮点数加0.01,结果任然硬件错误,不启用FPU一切正常,启用FPU不进行浮点运算也是一切正常。。。μC/OS-III里面对浮点寄存器确实是做了进栈和出栈处理的,这里我也不知道该怎么改,汇编什么的都不懂,忧伤。。。。 捕获12.PNG
  1. <blockquote>void timerTask(void *p_arg)
接着在CCS里面玩,感觉CCS要人性化一点,可是我的是Free License的,不能调试 做同样的删减,同样的程序代码,同样也是浮点的问题,没有浮点运算一切正常,加了浮点运行3秒就死了,而且工程选项里面我关不掉FPU,不能选择第一行空白,还有我在添加驱动库的时候路径必须添加到最后一行,要不然就报错,实在让人无语。。。 捕获13.PNG 刚接触μC/OS-III,也不知道其他的RTOS好用不,比如FreeRTOS和TI RTOS,附上百度云连接,官方代码,自己的工程,μC/Prob: http://pan.baidu.com/s/1kT1YrxP 本帖最后由 TWENLONG 于 2015-9-27 16:25 编辑

回复评论 (4)

上下文切换中有没有对与浮点运算有关的寄存器进行压栈和出栈的处理,没有这些代码是不是会出错?
RTEMS
点赞  2015-9-27 16:43
引用: 54chenjq 发表于 2015-9-27 16:43
上下文切换中有没有对与浮点运算有关的寄存器进行压栈和出栈的处理,没有这些代码是不是会出错?

从代码上看确实是有对浮点寄存器的进栈和出栈的处理,堆栈初始化的时候浮点寄存器进栈,位于os_cpu_c.c文件中:
  1. CPU_STK  *OSTaskStkInit (OS_TASK_PTR    p_task,
  2.                          void          *p_arg,
  3.                          CPU_STK       *p_stk_base,
  4.                          CPU_STK       *p_stk_limit,
  5.                          CPU_STK_SIZE   stk_size,
  6.                          OS_OPT         opt)
  7. {
  8.     CPU_STK    *p_stk;

  9.    
  10.     (void)opt;                                                  /* Prevent compiler warning                               */

  11.     p_stk = &p_stk_base[stk_size];                              /* Load stack pointer                                     */
  12.                                                                 /* Align the stack to 8-bytes.                            */
  13.     p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8);
  14.                                                                 /* Registers stacked as if auto-saved on exception        */
  15.     *--p_stk = (CPU_STK)0x01000000u;                            /* xPSR                                                   */
  16.     *--p_stk = (CPU_STK)p_task;                                 /* Entry Point                                            */
  17.     *--p_stk = (CPU_STK)OS_TaskReturn;                          /* R14 (LR)                                               */
  18.     *--p_stk = (CPU_STK)0x12121212u;                            /* R12                                                    */
  19.     *--p_stk = (CPU_STK)0x03030303u;                            /* R3                                                     */
  20.     *--p_stk = (CPU_STK)0x02020202u;                            /* R2                                                     */
  21.     *--p_stk = (CPU_STK)p_stk_limit;                            /* R1                                                     */
  22.     *--p_stk = (CPU_STK)p_arg;                                  /* R0 : argument                                          */
  23.                                                                 /* Remaining registers saved on process stack             */
  24.     *--p_stk = (CPU_STK)0x11111111u;                            /* R11                                                    */
  25.     *--p_stk = (CPU_STK)0x10101010u;                            /* R10                                                    */
  26.     *--p_stk = (CPU_STK)0x09090909u;                            /* R9                                                     */
  27.     *--p_stk = (CPU_STK)0x08080808u;                            /* R8                                                     */
  28.     *--p_stk = (CPU_STK)0x07070707u;                            /* R7                                                     */
  29.     *--p_stk = (CPU_STK)0x06060606u;                            /* R6                                                     */
  30.     *--p_stk = (CPU_STK)0x05050505u;                            /* R5                                                     */
  31.     *--p_stk = (CPU_STK)0x04040404u;                            /* R4                                                     */
  32.    
  33. #if (OS_CPU_ARM_FP_EN == DEF_ENABLED)
  34.     if ((opt & OS_OPT_TASK_SAVE_FP) != (OS_OPT)0) {
  35.         *--p_stk = (CPU_STK)0x02000000u;                        /* FPSCR                                                  */
  36.                                                                 /* Initialize S0-S31 floating point registers             */
  37.         *--p_stk = (CPU_STK)0x41F80000u;                        /* S31                                                    */
  38.         *--p_stk = (CPU_STK)0x41F00000u;                        /* S30                                                    */
  39.         *--p_stk = (CPU_STK)0x41E80000u;                        /* S29                                                    */
  40.         *--p_stk = (CPU_STK)0x41E00000u;                        /* S28                                                    */
  41.         *--p_stk = (CPU_STK)0x41D80000u;                        /* S27                                                    */
  42.         *--p_stk = (CPU_STK)0x41D00000u;                        /* S26                                                    */
  43.         *--p_stk = (CPU_STK)0x41C80000u;                        /* S25                                                    */
  44.         *--p_stk = (CPU_STK)0x41C00000u;                        /* S24                                                    */
  45.         *--p_stk = (CPU_STK)0x41B80000u;                        /* S23                                                    */
  46.         *--p_stk = (CPU_STK)0x41B00000u;                        /* S22                                                    */
  47.         *--p_stk = (CPU_STK)0x41A80000u;                        /* S21                                                    */
  48.         *--p_stk = (CPU_STK)0x41A00000u;                        /* S20                                                    */
  49.         *--p_stk = (CPU_STK)0x41980000u;                        /* S19                                                    */
  50.         *--p_stk = (CPU_STK)0x41900000u;                        /* S18                                                    */
  51.         *--p_stk = (CPU_STK)0x41880000u;                        /* S17                                                    */
  52.         *--p_stk = (CPU_STK)0x41800000u;                        /* S16                                                    */
  53.         *--p_stk = (CPU_STK)0x41700000u;                        /* S15                                                    */
  54.         *--p_stk = (CPU_STK)0x41600000u;                        /* S14                                                    */
  55.         *--p_stk = (CPU_STK)0x41500000u;                        /* S13                                                    */
  56.         *--p_stk = (CPU_STK)0x41400000u;                        /* S12                                                    */
  57.         *--p_stk = (CPU_STK)0x41300000u;                        /* S11                                                    */
  58.         *--p_stk = (CPU_STK)0x41200000u;                        /* S10                                                    */
  59.         *--p_stk = (CPU_STK)0x41100000u;                        /* S9                                                     */
  60.         *--p_stk = (CPU_STK)0x41000000u;                        /* S8                                                     */
  61.         *--p_stk = (CPU_STK)0x40E00000u;                        /* S7                                                     */
  62.         *--p_stk = (CPU_STK)0x40C00000u;                        /* S6                                                     */
  63.         *--p_stk = (CPU_STK)0x40A00000u;                        /* S5                                                     */
  64.         *--p_stk = (CPU_STK)0x40800000u;                        /* S4                                                     */
  65.         *--p_stk = (CPU_STK)0x40400000u;                        /* S3                                                     */
  66.         *--p_stk = (CPU_STK)0x40000000u;                        /* S2                                                     */
  67.         *--p_stk = (CPU_STK)0x3F800000u;                        /* S1                                                     */
  68.         *--p_stk = (CPU_STK)0x00000000u;                        /* S0                                                     */
  69.     }
  70. #endif   

  71.     return (p_stk);
  72. }
然后上下文切换里面似乎也有对于FPU寄存器的进栈与出栈操作,也位于os_cpu_c.c文件中
  1. void  OSTaskSwHook (void)
  2. {
  3. #if OS_CFG_TASK_PROFILE_EN > 0u
  4.     CPU_TS  ts;
  5. #endif
  6. #ifdef  CPU_CFG_INT_DIS_MEAS_EN
  7.     CPU_TS  int_dis_time;
  8. #endif


  9. #if (OS_CPU_ARM_FP_EN == DEF_ENABLED)
  10.     if ((OSTCBCurPtr->Opt & OS_OPT_TASK_SAVE_FP) != (OS_OPT)0) {
  11.         OS_CPU_FP_Reg_Push(OSTCBCurPtr->StkPtr);
  12.     }

  13.     if ((OSTCBHighRdyPtr->Opt & OS_OPT_TASK_SAVE_FP) != (OS_OPT)0) {
  14.         OS_CPU_FP_Reg_Pop(OSTCBHighRdyPtr->StkPtr);
  15.     }
  16. #endif

  17. #if OS_CFG_APP_HOOKS_EN > 0u
  18.     if (OS_AppTaskSwHookPtr != (OS_APP_HOOK_VOID)0) {
  19.         (*OS_AppTaskSwHookPtr)();
  20.     }
  21. #endif

  22. #if (defined(TRACE_CFG_EN) && (TRACE_CFG_EN > 0u))
  23.     TRACE_OS_TASK_SWITCHED_IN(OSTCBHighRdyPtr);                 /* Record the event.                                      */
  24. #endif

  25. #if OS_CFG_TASK_PROFILE_EN > 0u
  26.     ts = OS_TS_GET();
  27.     if (OSTCBCurPtr != OSTCBHighRdyPtr) {
  28.         OSTCBCurPtr->CyclesDelta  = ts - OSTCBCurPtr->CyclesStart;
  29.         OSTCBCurPtr->CyclesTotal += (OS_CYCLES)OSTCBCurPtr->CyclesDelta;
  30.     }

  31.     OSTCBHighRdyPtr->CyclesStart = ts;
  32. #endif

  33. #ifdef  CPU_CFG_INT_DIS_MEAS_EN
  34.     int_dis_time = CPU_IntDisMeasMaxCurReset();                 /* Keep track of per-task interrupt disable time          */
  35.     if (OSTCBCurPtr->IntDisTimeMax < int_dis_time) {
  36.         OSTCBCurPtr->IntDisTimeMax = int_dis_time;
  37.     }
  38. #endif

  39. #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
  40.                                                                 /* Keep track of per-task scheduler lock time             */
  41.     if (OSTCBCurPtr->SchedLockTimeMax < OSSchedLockTimeMaxCur) {
  42.         OSTCBCurPtr->SchedLockTimeMax = OSSchedLockTimeMaxCur;
  43.     }
  44.     OSSchedLockTimeMaxCur = (CPU_TS)0;                          /* Reset the per-task value                               */
  45. #endif
  46. }
OS_CPU_FP_Reg_Push和OS_CPU_FP_Reg_Pop是用汇编语言写的,位于os_cpu_a.asm中:

  1. #ifdef __ARMVFP__
  2. OS_CPU_FP_Reg_Push
  3.     MRS     R1, PSP                                             ; PSP is process stack pointer
  4.     CBZ     R1, OS_CPU_FP_nosave                                ; Skip FP register save the first time

  5.     VMRS    R1, FPSCR
  6.     STR R1, [R0, #-4]!
  7.     VSTMDB  R0!, {S0-S31}
  8.     LDR     R1, =OSTCBCurPtr
  9.     LDR     R2, [R1]
  10.     STR     R0, [R2]
  11. OS_CPU_FP_nosave
  12.     BX      LR
  13. #endif

  14. #ifdef __ARMVFP__
  15. OS_CPU_FP_Reg_Pop
  16.     VLDMIA  R0!, {S0-S31}
  17.     LDMIA   R0!, {R1}
  18.     VMSR    FPSCR, R1
  19.     LDR     R1, =OSTCBHighRdyPtr
  20.     LDR     R2, [R1]
  21.     STR     R0, [R2]
  22.     BX      LR
  23. #endif
点赞  2015-9-27 18:18
Mark,差的还远着呢,得向楼主学习~
点赞  2015-9-30 00:08
When enabling the FP co-processor, make sure to clear bits ASPEN and LSPEN in the
*                          Floating-Point Context Control Register (FPCCR).
点赞  2015-11-16 13:55
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复