Azure RTOS全家桶

微软在2019年对Express Logic的收购将其ThreadX实时操作系统带入了Azure。 现在已被称为Azure RTOS(开源的主页为 https://github.com/azure-rtos ,它是一种工业级实时操作系统。ThreadX及其所有中间件的安全认证等级,至今没有一款小型RTOS可以与其匹敌。


  • 医疗-FDA510(k),IEC-62304ClassC,IEC-60601,ISO-14971
  • 工业-UL-1998,IEC-61508SIL4
  • 运输/铁路-EN50128SIL4,BS50128,49CFR236,IEC-61508
  • 航空航天设备-DO-178B,ED-12B,DO-278
  • 汽车-IEC-61508ASILD
  • 核应用-IEC-61508
  • 家电-UL/IEC60730/60335

各种安全等级基本都达到了最高。像工业级安全认证IEC61508,ThreadX满足最高等级SIL4,而SafeRTOS,embOS,uCOS-II都只是SIL3。

ThreadX和它功能极为全面各种中间件如下图

175459ds7bleb766ylpy1y.png.thumb.jpg

hreadXHC32F460上的移植

ThreadX的体系结构的一个优势是,很容易移植到新的芯片体系结构。现在拿前一节准备好的并且测试正常的OLED显示工程,直接移植,以下是过程。

下载内核源码

内核源码可以在官方的Github下载:https://github.com/azure-rtos/threadx 将源码中的common和ports文件夹复制到工程中:

175539z2f4rfj0v8eeeve4.png.thumb.jpg
添加Port文件和源码文件到工程

将源码文件和ports文件添加到MDK的工程项目中,添加后的效果如下:

175554vie1k2e2ngxmg3a2.png.thumb.jpg

ThreadX/Ports分组文件位置

文件tx_initialize_low_level.s在路径ThreadX\ports\cortex_m4\ac5\example_build其它文件在路径ThreadX\ports\cortex_m4\ac5\src

ThreadX/Source分组文件位置

全部在路径ThreadX\common\src,所有文件全部添加进来推荐使用下面的方法添加,有效防止MDK大批量添加源文件造成的卡顿问题:

175626oynno59jfsozly4c.png.thumb.jpg

添加所有相关的源码文件,然后添加好工程的头文件路径以及添加相关预定义宏

175639hgg8f7str7wmjtrw.png.thumb.jpg

175649m7qsuqeihuns5pps.png.thumb.jpg

修改初始化代码

原工程默认跑8MHz时钟,现需要修改时钟配置,更改到 200MHz主频

/* Define the initial systemcore clock.  */
  • void CLK_SwitchTo200MHz()
  • {
  •     en_clk_sys_source_t     enSysClkSrc;
  •     stc_clk_sysclk_cfg_t    stcSysClkCfg;
  •     stc_clk_xtal_cfg_t      stcXtalCfg;
  •     stc_clk_mpll_cfg_t      stcMpllCfg;
  •     stc_clk_freq_t          stcClkFreq;
  •     stc_clk_output_cfg_t    stcOutputClkCfg;
  •     stc_sram_config_t       stcSramConfig;
  •     MEM_ZERO_STRUCT(enSysClkSrc);
  •     MEM_ZERO_STRUCT(stcSysClkCfg);
  •     MEM_ZERO_STRUCT(stcXtalCfg);
  •     MEM_ZERO_STRUCT(stcMpllCfg);
  •     /* Set bus clk div. */
  •     stcSysClkCfg.enHclkDiv = ClkSysclkDiv1;
  •     stcSysClkCfg.enExclkDiv = ClkSysclkDiv2;
  •     stcSysClkCfg.enPclk0Div = ClkSysclkDiv1;
  •     stcSysClkCfg.enPclk1Div = ClkSysclkDiv2;
  •     stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;
  •     stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;
  •     stcSysClkCfg.enPclk4Div = ClkSysclkDiv2;
  •     CLK_SysClkConfig(&stcSysClkCfg);
  •     /* Config Xtal and Enable Xtal */
  •     stcXtalCfg.enMode = ClkXtalModeOsc;
  •     stcXtalCfg.enDrv = ClkXtalLowDrv;
  •     stcXtalCfg.enFastStartup = Enable;
  •     CLK_XtalConfig(&stcXtalCfg);
  •     CLK_XtalCmd(Enable);
  •     /* Switch system clock source to XTAL. */
  •     CLK_SetSysClkSource(ClkSysSrcXTAL);
  •     /* Use Xtal as MPLL source. */
  •     /* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 50M). */
  •     stcMpllCfg.pllmDiv = 1ul;
  •     stcMpllCfg.plln = 50ul;
  •     stcMpllCfg.PllpDiv = 8ul;
  •     stcMpllCfg.PllqDiv = 8ul;
  •     stcMpllCfg.PllrDiv = 8ul;
  •     CLK_SetPllSource(ClkPllSrcXTAL);
  •     CLK_MpllConfig(&stcMpllCfg);
  •     /* flash read wait cycle setting */
  •     EFM_Unlock();
  •     EFM_SetLatency(EFM_LATENCY_1);
  •     EFM_Lock();
  •     /* sram init include read/write wait cycle setting */
  •     stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
  •     stcSramConfig.enSramRC = SramCycle2;
  •     stcSramConfig.enSramWC = SramCycle2;
  •     stcSramConfig.enSramEccMode = EccMode3;
  •     stcSramConfig.enSramEccOp = SramNmi;
  •     stcSramConfig.enSramPyOp = SramNmi;
  •     SRAM_Init(&stcSramConfig);
  •     /* Enable MPLL. */
  •     CLK_MpllCmd(Enable);
  •     /* Wait MPLL ready. */
  •     while (Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
  •     {
  •         ;
  •     }
  •     /* Switch system clock source to MPLL. */
  •     CLK_SetSysClkSource(CLKSysSrcMPLL);
  •     /* Check source and frequency. */
  •     enSysClkSrc = CLK_GetSysClkSource();
  •     CLK_GetClockFreq(&stcClkFreq);
  •     /* flash read wait cycle setting */
  •     EFM_Unlock();
  •     EFM_SetLatency(EFM_LATENCY_4);
  •     EFM_Lock();
  •     /* Switch driver ability */
  •     PWC_HS2HP();
  •     /* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 200M). */
  •     stcMpllCfg.pllmDiv = 1ul;
  •     stcMpllCfg.plln = 50ul;
  •     stcMpllCfg.PllpDiv = 2ul;
  •     stcMpllCfg.PllqDiv = 2ul;
  •     stcMpllCfg.PllrDiv = 2ul;
  •     CLK_SetPllSource(ClkPllSrcXTAL);
  •     CLK_MpllConfig(&stcMpllCfg);
  •     SystemCoreClock = 200000000 ;
  • }
  • 复制代码

    需要将startup_hc32f46x.s 中的堆栈大小加大

    Stack_Size      EQU     0x00001400

    Heap_Size       EQU     0x00000600

    修改文件tx_initalize_low_level.s

    ThreadX为MDK AC5提供的这个文件有点欠妥,因为ThreadX通过这个文件直接接管了我们一直使用的xxxx.S启动文件。但接管的文件仅写了几个重要的中断向量表入口。这就给让移植的人非常不方便。所以我们做的例子不接管XXX.S启动文件了,方便大家移植。本周教程配套例子使用的这个文件已经做了修改,推荐大家直接复制粘贴到自己的工程即可,内容如下:

    注意:下面代码中置红部分的参数需要大家配置,即芯片主频和系统时钟节拍。

    SYSTEM_CLOCK       EQU     200000000

    SYSTICK_CYCLES     EQU     ((SYSTEM_CLOCK / 1000) -1)

    200000000是系统时钟主频,1000对应的就是系统时钟节拍,这里1000就表示1000Hz。

    其它的修改详见附件工程即可。

    添加ThreadX配置文件tx_user.h

    ThreadX内核相关的配置,已经全部整理到了这个文件中,并且做中文注释,大家可以更新需要使能宏定义。本工程中全部注释掉。

    添加应用程序

    应用程序比较简单,大家可以直接复制本章教程配置例子的main.c文件中的内容到自己工程里面测试。主要tx_application_define里面创建个任务:

    thread_0_entry  :闪灯任务

    thread_1_entry :OLED显示任务

    本次评测内容主要介绍了移植思路,具体可以参考后续文章中的附件工程,另外需要掌握ThreadX内核框架设计,这有助于移植。

    实验现象:可以看到板载的LED每秒闪烁一次,另外显示屏会有显示:

    180148houet3ofwdh52dur.png.thumb.jpg