查看: 1681|回复: 1

[原创] IRDLPC1768 从裸机 (bare metal)到RTOS C -- 3

[复制链接]
回帖奖励 100 NXP金币 回复本帖可获得 1 NXP金币奖励! 每人限 1 次
  • TA的每日心情
    擦汗
    2021-7-5 15:45
  • 签到天数: 664 天

    [LV.9]以坛为家II

    42

    主题

    1594

    帖子

    19

    金牌会员

    Rank: 6Rank: 6

    积分
    5393
    最后登录
    2021-12-22
    发表于 2019-3-18 00:07:21 | 显示全部楼层 |阅读模式
    本帖最后由 okwh 于 2019-3-23 15:35 编辑

    IRD-LPC1768-DEV 从裸机 (bare metal)RTOS  C -- 3
    上篇用CMSIS-RTOSV1 Keil RTX 初步试验了RTX, 本篇分析下目前CMSIS-RTOS目前状况。

    1   CMSIS-RTOS
    CMSIS由ARM定义(http://developer.arm.com/embedded/cmsis),从第一版到现在已经有10年历史,可以说已经足够完善,几乎所有Cortex系列芯片都支持, Cortex系列芯片应该是使用最广的嵌入单片机芯片了。
    CMSIS标准的软件架构主要有四层:用户应用层(中间件)、操作系统层、CMSIS层和硬件寄存器层。CMSIS层分3个部分:核内外设访问层(CPAL),由ARM负责实现对寄存器名称、地址定义、NVIC中断接口等定义。片上外设访问层(DPAL)和外设访问函数(AFP),由芯片厂商负责实现。目前已增加了DSP、SVD、NN、DAP等有用组件。
    0301.png

    目前版本为CMSIS  Version 5.4.0,    CMSIS-RTOS2 Version 2.1.3,  Keil RTX version 5(RTX5)(RTX5为RTX version 4 and CMSIS-RTOS V1 提供兼容支持)。CMSIS软件包在http://github.com/ARM-software/CMSIS_5开源,ARM.CMSIS.5.4.0.pack和不需要硬件支持基于模拟器的学习包Hitex.CMSIS_RTOS_Turorial.xxxx.pack以及各芯片的Pack可随时在uVision下载使用。
    CMSIS-RTOS2 API 就是个通用API, 符合CMSIS-RTOS标准的任何RTOS核都可被使用。 KeilRTX version 5是keil的一个RTOS核实现,随uVision环境自动提供。另外似乎为uVision支持的其他芯片也可类似使用Keil RTX,比如RTX51 Tiny就是一个更简单的RTX。
    换句话说,使用CMSIS-RTOS2API写程序,基本上可以不管实际的OS是什么了(除了做大同小异的配置)。RTX5 C 源代码质量合乎MISRA C:2012汽车级软件编码标准规范 (MISRA (The Motor Industry Software Reliability Association 汽车工业软件可靠性联会),保障了软件易读、可靠安全、可移植、易于维护,还可用uVision的Tools菜单以PC_Lint静态代码分析工具对嵌入软件质量的进行分析和工程规范评价。编译器调试器提供DAP提供了Event Recorder等很好的软件调试途径。
    Keil RTX5目前已支持在ARM、IAR、GNU编译工具链,目前支持的芯片主要包括Cortex-M0/M0+/M23,Cortex-M3/M4/M7/M33,Cortex-A5/A7/A9。
    未来CMSIS 软件包本身还将提供了ARM::CMSIS-RTOS_Validation用于RTOS规范测试ttps://github.com/xpacks/arm-cmsis-rtos-validator。C++版的CMSIS也在开发中。 只是这两者进展极其缓慢。

    2  嵌入程序的ABC
    裸机程序大致这个样子+中断: (相当于轮询判断处理+中断处理)
    void main(void) {
    初始化
         while(1) {
                  DoThing1( );    //+标志判断
                  DoThing2( );      
                  DoThing3 ( );   //………….
         }
       OS的大致这个样子+中断:(OS用一个计数器调度所有线程函数什么时候或轮询或优先执行,协调各种任务间的关系、协调各任务的紧急程度,协助合理完成其他事务如资源分配、数据传递等)
    Thing1( );    Thing2( );    Thing3( );
    void main(void) {
    初始化
    os_init();
    os_create_task(Thing1);
    os_create_task(Thing2);
    os_create_task(Thing3);
    …….
    os_start();

    3  CMSIS-RTOSV2 + Keil RTX5
          CMSIS-RTOSV2 + Keil RTX5比以前有了不错的改进,更规范清晰,主要是去除了宏定义,API分下表十类, 可以清晰按图索骥。http://www.keil.com/pack/doc/CMSIS/RTOS2/html/rtos_api2.html
         基础知识准备:状态机。
      CMSIS-RTOS V2 + Keil RTX5  功能分类
    Kernel Information and Control
    内核信息和控制
    Thread Management
    线程管理
    Thread Flags
    线程标志
    Event Flags
    事件标志
    Generic Wait Functions
    通用等待功能
    Timer Management
    计时器管理
    Mutex Management
    互斥管理
    Semaphores
    信号灯
    Memory Pool
    内存池
    Message Queue
    消息队列
    OS Tick API
    系统滴答计数器API
    RTX5 API
    RTX5具体API
    cmsis_os2.h头文件中实现所有CMSIS-RTOS  C API v2函数
      RTX_Config.h  RTX_Config.cRTX配置
      os_systick.c OS Tick API
      rtx_os.hRTX用的各种数据结构定义

    重要事项:
    1) 中断服务中,最好1ms(默认调度时间基准单位)内完成,仅仅用于发送信号、设置标志,真正处理留在高优先级别线程进行;
    2) RTX5 任务调度基于三类:基于时间轮询的SysTick_Handler(对应rtx_system.cosRtxTick_Handler,调度普通线程), 锁定停用低级线程、处理优先执行的SVC_Handler(调度OS系统级线程),配合中断处理的最高优先的PendSV_Handler(对应rtx_system.c osRtxPendSV_Handler调度中断服务线程);
    3) RTX5不含其他设备部分,那些可用CMSIS的设备驱动RTE (Run-TimeEnvironment) DeviceDFP (Device Family Pack)或自行基于厂家的Chip DriverHAL(hardware abstraction layer)BSPBoard Support Package)建立。
    4) 包含RTX5源代码的工程需要设置C/C++编译选项 C99 Mode启用。


    工程建立过程:
    选芯片,在运行时环境选添加CMSIS CorestartupPINGPIORTOS Keil RTX5库组件等。
    0302.png

    配置RTX: RTX_Config.h  RTX_Config.c
    0303.png

    添加源代码,可从模板生成框架
    0304.png

    主程序结构大致如下:
    //#include "RTE_Components.h"
    ///#include CMSIS_device_header
    #include "cmsis_os2.h"

    /*---- Application1/2/3/4/5… thread --------*/
    void app1 (void *argument) {
      for(;;) {}              }
    void app2 (void *argument) {
      for(;;) {}              }

    int main (void) {
    SystemCoreClockUpdate();  //System Initialization
      //... 其他初始化
    osKernelInitialize();                // Initialize CMSIS-RTOS
    osThreadNew(app1, NULL, NULL);   // Create application1 thread
    osThreadNew(app2, NULL, NULL);   // Create application2 thread
    osKernelStart();                   // Start thread execution
      for(;;) {}
    }


    4  例程
    将前文的CMSIS-RTOS1 APIKeil RTX 4.81改为CMSIS-RTOS2 APIKeil RTX5

    1. /*----------------------------------------------------------------------------
    2. *      RL-ARM - RTX5 IRD-LPC1768 test
    3. *---------------------------------------------------------------------------*/
    4. #include <b><font color="#ff0000">"cmsis_os2.h" </font></b>                 // ARM::CMSIS:RTOS2:Keil RTX5
    5. #include "LPC17xx.h"                  
    6. #include "PIN_LPC17xx.h"
    7. #include "GPIO_LPC17xx.h"

    8. #define LED_COUNT (4)
    9. const PIN LED_PIN[] = {     //后3个 相关USB,做led  就不要用usb
    10.   {0, 7},
    11.   {1, 18},
    12.   {2, 9},
    13.   {1, 22 },
    14. };
    15. int32_t <b>LED_Initialize</b> (void) {       // led初始化  GPIO
    16.   uint32_t n;
    17.   GPIO_PortClock     (1);          /* Enable GPIO clock */
    18.   for (n = 0; n < LED_COUNT; n++) {              /* Configure pins: Output Mode with Pull-down resistors */
    19.     PIN_Configure (LED_PIN[n].Portnum, LED_PIN[n].Pinnum, PIN_FUNC_0, PIN_PINMODE_PULLDOWN, PIN_PINMODE_NORMAL);
    20.     GPIO_SetDir   (LED_PIN[n].Portnum, LED_PIN[n].Pinnum, GPIO_DIR_OUTPUT);
    21.     GPIO_PinWrite (LED_PIN[n].Portnum, LED_PIN[n].Pinnum, 0);
    22.   }
    23.   GPIO_PinWrite (LED_PIN[1].Portnum, LED_PIN[1].Pinnum, 1);  // P1.18 led负端, 1灭
    24.         GPIO_PinWrite (LED_PIN[2].Portnum, LED_PIN[2].Pinnum, 1);  // P2.9 led负端, 1灭
    25.   return 0;
    26. }

    27. <b>osThreadId_t</b> tid_phaseA;                  /* Thread id of task: phase_a */
    28. osThreadId_t tid_phaseB;                  /* Thread id of task: phase_b */
    29. osThreadId_t tid_phaseC;                  /* Thread id of task: phase_c */
    30. osThreadId_t tid_phaseD;                  /* Thread id of task: phase_d */
    31. osThreadId_t tid_Other;                   /* Thread id of task: anyOther   */

    32. /*---  Function 'signal_func' called from multiple threads ----*/
    33. void signal_func (osThreadId_t tid)  {      // 做公共处理、触发后续其他线程等
    34. <b>  osThreadFlagsSet</b>(tid_Other, 0x0100);           /* set signal to any other thread    */
    35.   osDelay(500);                             /* delay 500ms                   */
    36.   osThreadFlagsSet(tid, 0x0001);                 /* set signal to thread next one of ABCD 'threads' */
    37.   osDelay(500);                             /* delay 500ms                   */
    38. }
    39. /*
    40. void signal_func (osThreadId tid)  {      // 只简单用于设置触发后续其他线程的标志
    41.   osSignalSet(tid, 0x0001);                 // set signal to thread  'thread'
    42. }
    43. */

    44. /*------Thread 1 'phaseA': Phase A output -------------*/
    45. void phaseA (void  *argument) {
    46.   for (;;) {
    47. <b>    osThreadFlagsWait</b>(0x0001,osFlagsWaitAny,  osWaitForever);    /* wait for an event flag 0x0001  for start this thread */
    48.     GPIO_PinWrite(LED_PIN[3].Portnum, LED_PIN[3].Pinnum,1);        //On
    49.     signal_func(tid_phaseB);                /* call common signal function   to trigger next thread*/
    50.     GPIO_PinWrite (LED_PIN[3].Portnum, LED_PIN[3].Pinnum, 0);     //Off
    51.   }
    52. }                                                                           

    53. /*--- Thread 2 'phaseB': Phase B output -----------*/
    54. void phaseB (void  *argument) {
    55.   for (;;) {
    56.     osThreadFlagsWait(0x0001,osFlagsWaitAny,  osWaitForever);    /* wait for an event flag 0x0001 for start this thread*/
    57.     GPIO_PinWrite(LED_PIN[2].Portnum, LED_PIN[2].Pinnum,0);  //On
    58.     signal_func(tid_phaseC);                /* call common signal function   to trigger next thread*/
    59.     GPIO_PinWrite(LED_PIN[2].Portnum, LED_PIN[2].Pinnum,1);   //Off
    60.   }
    61. }

    62. /*----- Thread 3 'phaseC': Phase C output -------*/
    63. void phaseC (void  *argument) {
    64.   for (;;) {
    65.     osThreadFlagsWait(0x0001,osFlagsWaitAny,  osWaitForever);    /* wait for an event flag 0x0001 */
    66.     GPIO_PinWrite(LED_PIN[1].Portnum, LED_PIN[1].Pinnum,0);  //On
    67.     signal_func(tid_phaseD);                /* call common signal function   */
    68.     GPIO_PinWrite(LED_PIN[1].Portnum, LED_PIN[1].Pinnum,1);   //Off
    69.   }
    70. }

    71. /*----  Thread 4 'phaseD': Phase D output -------*/
    72. void phaseD (void   *argument) {
    73.   for (;;) {
    74.     osThreadFlagsWait(0x0001,osFlagsWaitAny,  osWaitForever);    /* wait for an event flag 0x0001 */
    75.     GPIO_PinWrite(LED_PIN[0].Portnum, LED_PIN[0].Pinnum,1);  //On
    76.     signal_func(tid_phaseA);                /* call common signal function   */
    77.     GPIO_PinWrite(LED_PIN[0].Portnum, LED_PIN[0].Pinnum,0);   //Off
    78.   }
    79. }

    80. /*------  Thread 5 'Other' ----------*/
    81. void Other (void   *argument) {          // can be used  to do other things
    82.   for (;;) {
    83.     osThreadFlagsWait(0x0100,osFlagsWaitAny, osWaitForever);    /* wait for an event flag 0x0100 */  //
    84.     osDelay(100);                            /* delay 100ms    text  this osDelay time > that at signal_func ???             */
    85.   }
    86. }

    87. /*----------------------------------------------------------------------------
    88. *      Main: Initialize and start RTX Kernel
    89. *---------------------------------------------------------------------------*/
    90. int <b>main </b>(void) {
    91. SystemCoreClockUpdate ();                 /* Update system core clock    100MHz   */  
    92. // SysTick_Config(SystemCoreClock/10);      /* SysTick 中断 each 100 ms  */
    93. // 不需要了, RTX 初始化SysTick,用于RTOS的调度计时,不得再它用
    94.   LED_Initialize();                         /* Initialize the LEDs           */
    95. <b>  osKernelInitialize</b>();
    96.   tid_phaseA = <b>osThreadNew</b>(phaseA, NULL, NULL);      //创建线程
    97.   tid_phaseB = osThreadNew(phaseB, NULL, NULL);
    98.   tid_phaseC = osThreadNew(phaseC, NULL, NULL);
    99.   tid_phaseD = osThreadNew(phaseD, NULL, NULL);
    100.   tid_Other  = osThreadNew(Other, NULL, NULL);

    101. <b>  osThreadFlagsSet</b>(tid_phaseA, 0x0001);          /* set signal to phaseA thread  触发第一个线程  */
    102. <b>  osKernelStart</b>();
    103.   //osDelay(osWaitForever);
    104.   while(1);
    105. }
    复制代码

    编译后,Program Size: Code=13412 RO-data=464RW-data=5140 ZI-data=612  

    工程文件:   RTX5.zip (30.05 KB, 下载次数: 2)
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2021-7-5 15:45
  • 签到天数: 664 天

    [LV.9]以坛为家II

    42

    主题

    1594

    帖子

    19

    金牌会员

    Rank: 6Rank: 6

    积分
    5393
    最后登录
    2021-12-22
     楼主| 发表于 2019-3-23 15:35:49 | 显示全部楼层

    论坛不活跃, 回帖奖励!!
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-5-6 06:23 , Processed in 0.115892 second(s), 22 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表