精华内容
下载资源
问答
  • ARM.CMSIS-RTOS_Validation.1.1.0.pack
  • CMSIS-RTOS API参考手册

    2018-06-23 14:22:43
    CMSIS-RTOS API参考手册 V1.02 ,根据Keil官方网站文档整理,方便使用FreeRTOS、uc/os等底层操作系统的
  • 本工程模板是在STM32CubeMX生成的工程基础上,增加了CMSIS-RTOS的移植,包含RTX5源码,包含HAL库,app文件中实现了使用任务调度方式控制LED闪烁的功能
  • CMSIS-RTOS(FreeRTOS)在STM32F407下的移植 在MDK-ARM环境下,基于官方的CubeF4固件库,进行了CMSIS-RTOS的移植。 CMSIS-RTOS是ARM对FreeRTOS的在此封装,更加适合在STM32环境下使用。
  • CMSIS-RTOS

    2021-05-29 15:16:29
    CMSIS是ARM的为Cortex系列处理器提供的硬件抽象层,为了屏蔽各个芯片厂商的差异从而方便开发人员。 当前版本是5.7.0,英文表示:Software Interface Standard for Arm Cortex-based Microcontrollers。

    新到手一个开发板STM32L4R9IDISCOVERY,官网下载demo程序源码,我勒个去,里面的OS的任务调用咋看不懂,原来从FreeRTOS变成了CMSIS-RTOS拉。

    CMSIS是ARM的为Cortex系列处理器提供的硬件抽象层,为了屏蔽各个芯片厂商的差异从而方便开发人员。

    当前版本是5.7.0,英文表示:Software Interface Standard for Arm Cortex-based Microcontrollers,Cortex Microcontroller Software Interface Standard (CMSIS)。
    详情请参照:https://www.keil.com/pack/doc/CMSIS/General/html/index.html

    而ROTS,顾名思义。一般我们使用的有FreeRTOS,RTX,RIOT,μC/OS,RTLinux,RT-Thread,QNX, ThreadX等。
    这其中的RTX是ARM自有的RTOS系统。

    两个加一起表示的是给ARM Cortex芯片的通用的RTOS interface,这样就屏蔽了各种RTOS不同接口的差异,从而降低学习成本和开发难度。说白了这就是一层封装。你懂的,但凡出现一个解决不了的问题,加一个中间层吗。

    目前支持CMSIS-RTOS的是(Keil)RTX和FreeRTOS。

    展开全文
  • 关注+星标公众号,不错过精彩内容素材来源 |网络我们之前分享的文章《Cortex-M软件接口标准CMSIS有哪些重要内容》中描述了CMSIS主要内容:CMSIS-RTOS:主要用于RTO...

    关注+星标公众,不错过精彩内容

    1214ddd475e8f11e08fbf71d7095cff8.png

    素材来源 | 网络

    我们之前分享的文章《Cortex-M软件接口标准CMSIS有哪些重要内容》中描述了CMSIS主要内容:

    • CMSIS-RTOS:主要用于RTOS的API,可与中间件和库组件实现一致的软件层。

    • CMSIS-DSP:Arm针对各种Cortex-M处理器内核进行了优化的丰富DSP功能的集合。

    • CMSIS-Driver:接口可用于许多微控制器系列。

    • CMSIS-Pack:定义了包含软件组件的软件包。

    • CMSIS-SVD:可通过当前寄存器状态显示设备外设的详细视图。

    • CMSIS-DAP:Cortex调试访问端口(DAP)的标准化接口。

    • CMSIS-NN:高效的神经网络内核的集合。

    同时,我们在使用STM32CubeMX配置FreeRTOS时有一个CMSIS_V1CMSIS_V2的选项,有读者就问了一个问题:CMSIS-RTOS是什么?CMSIS_V1和CMSIS_V2区别是什么?

    下面我们就来简单分享一下关于CMSIS-RTOS的内容。

    CMSIS的简介

    Cortex微控制器软件接口标准(Cortex Microcontroller Software Interface Standard)是ARM和一些编译器厂家以及半导体厂家共同遵循的一套标准,是由ARM专门针对CORTEX-M系列提出的标准。

    在该标准的约定下,ARM和芯片厂商会提供一些通用的API接口来访问Cortex内核以及一些专用外设,以减少更换芯片以及开发工具等移植工作所带来的金钱以及时间上的消耗。

    只要都是基于Cortex的芯片,代码均是可以复用的。CMSIS是 Cortex-M 处理器系列的与供应商无关的硬件抽象层。使用 CMSIS可以为处理器和外设实现一致且简单的软件接口,从而简化软件的重用、缩短微控制器新开发人员的学习过程,并缩短新设备的上市时间。

    CMSIS主要内容就如之前分享的Cortex-M内容

    • CMSIS-RTOS:主要用于RTOS的API,可与中间件和库组件实现一致的软件层。

    • CMSIS-DSP:Arm针对各种Cortex-M处理器内核进行了优化的丰富DSP功能的集合。

    • CMSIS-Driver:接口可用于许多微控制器系列。

    • CMSIS-Pack:定义了包含软件组件的软件包。

    • CMSIS-SVD:可通过当前寄存器状态显示设备外设的详细视图。

    • CMSIS-DAP:Cortex调试访问端口(DAP)的标准化接口。

    • CMSIS-NN:高效的神经网络内核的集合。

    更多相关介绍可以参看文章:Cortex-M软件接口标准CMSIS

    CMSIS-RTOS是干么的?

    众所周知,实时操作系统是嵌入式领域的基石,而可选的嵌入式操作系统有很多,如FreeRTOS、μCOS、RT-Thread、RTX、ThreadX、uLinux等。

    CMSIS-RTOS是ARM公司为统一操作系统、降低嵌入式门槛而发布的操作系统标准软件接口。通俗讲,CMSIS-RTOS将操作系统(不管是FreeRTOS还是RTX等)屏蔽起来,然后提供CMSIS-RTOS接口函数给最终使用者调用。

    如此以来,最终使用者只需要学习CMSIS-ROTS即可,从而降低学习门槛。(目前FreeRTOS和RTX能够很好的支持CMSIS-RTOS,其他有些RTOS还没有做适配)。

    5959eb997f86bdb14b21d707d864ff75.png

    CMSIS-RTOS 是实时操作系统的通用 API。它提供了标准化的编程接口,它只是封装了RTX/Embos,以后还可能封装μCOS、ThreadX等第三方RTOS。

    就如开篇所说的,在STM32CubeMX配置FreeRTOS有一个CMSIS_V1CMSIS_V2的选项:

    f7d3914fcbe8b0b3326a69aaf3aab791.png

    同时,CMSIS-ROTS也对Keil的RTX作了很好的支持,如果你安装了Keil MDK,在CMSIS目录下,你会发现RTX的源码:

    0151735c481a3afdb8bcb86ce7868741.png

    这里顺便说一下:RTX与μCOS、ThreadX等这些RTOS一样,同样免费开源(源码在CMSIS目录下,可以自己查看),遵循Apache2.0开源协议

    补充

    CMSIS RTOS是ARM现在热推的物联网操作系统mbedOS的基础,搞懂这个RTOS API,更有利于从事RTOS底层、IC底层软件开发。

    这里推荐一篇使用CMSIS-RTOS创建线程的教程:

    https://blog.csdn.net/ichamber/article/details/53116253

    可移植到很多,RTOS,使软件模板、中间件、库及其它组件能工作于支持的 RTOS 系统(ST就针对FreeRTOS做了CMSIS-RTOS底层支持,所以,你会看到STM32CubeMX有CMSIS_V1和CMSIS_V2的选项)。

    更多关于CMSIS-RTOS的内容,可以参看官方教程:

    https://www.keil.com/pack/doc/CMSIS/RTOS2/html/rtos_api2.html

    (公号不支持外连接,请复制链接到浏览器打开)

    声明:本文部分素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。

    ------------ END ------------

    后台回复『MCU』『软件算法』阅读更多相关文章。

    欢迎关注我的公众号回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。

    欢迎关注我的视频号:

    760326792f908468a11c5af46545e463.png

    点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

    展开全文
  • CMSIS-RTOS API版本2的C ++ 11 / C ++ 14接口。 此源代码基于接口实现了STL的某些类。 您必须使用支持C ++ 11 / C ++ 14标准的C ++编译器,例如 。 C ++标准 线 定义于头文件“ Thread.h” 此标头是库的一部分。 ...
  • CMSIS-RTOS教程中文版

    千次阅读 2020-03-02 09:33:25
    CMSIS_RTOS_Tutorial自译中文版 一.序言 本资料是Trevor Martin编写的《The Designers Guide to the Cortex-M Processor Family》的摘要,并得到Elsevier的再版许可。查询更多细节,请到本资料尾部进阶章节。 ...

    CMSIS_RTOS_Tutorial自译中文版

     

    一.序言

     

    本资料是Trevor Martin编写的《The Designers Guide to the Cortex-M Processor Family》的摘要,并得到Elsevier的再版许可。查询更多细节,请到本资料尾部进阶章节。

    本资料着力于介绍RTX,RTX可运行在基于Cortex-M构架的微控制器上。尤其,RTX符合CMSIS标准。CMSIS全称"Cortex Microcontroller Interface Standard",定义了基于Cortex-M构架的微控制器标准的RTOS Api。CMSIS RTOS Api提供基于RTOS开发的接口,掌握后可跨多系列微控制器使用。另外,CMSIS RTOS Api也为高级应用(如Java虚拟机,UML)等提供标准接口。同时,CMSIS RTOS Api也是不依赖于硬件层的标准接口,支持代码重复使用。

    作为新手,适应RTOS需要大量的练习,但RTOS的便利性会使使用者再也不想回到裸板程序。

    1.1.起步-安装工具

     

    要运行本资料中的示例代码,必须安装MDK-ARM工具链。可在如下地址下载最新版本,并运行安装程序。

    http://www.keil.com/mdk5/install 

    该安装程序是MDK-ARM的核心,包括IDE,编译/链接工具和基本调试模块。不包括对基于Cortex-M构架微控制器的具体型号支持,要支持具体的型号需要下载"Device Family Pack"(集合了启动文件,Flash编程算法和调试支持)。

    本资料中的练习,均基于STM32F103RB微控制器,所以需要安装对应的"Device Family Pack"。

    初次安装完毕,Pack Installer会自动启动。也可通过工具栏启动,如图所示:

    在Pack Installer选择相应的模块安装,Pack Installer自动下载并安装。

    1.2.安装例程

     

    本资料中涉及到的例程也被做成CMSIS pack下载。在Pack Installer中双击Hitex.CMSIS_RTOS_Turorial.xxxx.pack file即可自动安装。

    安装完成后界面如图:

    1.3.硬件需求

     

    不需要硬件支持!

    Keil工具链包含基于Cortex-M构架微控制器的模拟器,并可完全模拟其模型(包括CPU和外设)。这就意味着可以在debug模式下模拟运行。

     

    二.综述

     

    学习本资料,分三个步骤:

    1. 首先建立一个基于Cortex-M构架微控制器的RTOS工程,并运行起来;

    2. 进一步深入RTOS每个细节,体验RTOS对应用程序的贡献和闪光点;

    3. 对RTOS有个整体认识后,深入探讨如何配置RTOS选项;

    对于没有接触过RTOS的新手来说,以下两点需要克服:

     

    1. 进程(或者叫任务),重点在理解进程的运行原理;

    2. 进程见通讯,重点是理解进程间的同步通讯;

    2.1.进入RTOS的第一步

     

    1. RTOS的核心是调度器(支持轮换、抢占和协同多任务),时间和内存管理服务。进程间通讯由额外模块如信号、信号量、互斥量、消息队列、消息邮箱等支持完成。而,中断则通过特权进程由内核调度。

    2.2导入CMSIS-RTOS Api

     

    1. 添加头文件 <cmsis_os.h>即可调用CMSIS_RTOS Api,如下:

      #include <cmsis_os.h>

      该头文件作为CMSIS-RTOS标准文件。对于符合CMSIS-RTOS标准的Keil 内置RTX是默认的Api。其他RTOS应该会包含其特有Api,但只要支持CMSIS_RTOS,即可通过此方式引入。

    2.3进程

     

    1. 标准C语言的最小程序块是函数(函数被其他代码并完成某些特定的运算)。在CMSIS-RTOS中,基本代码单元是进程。进程与函数类似,但也有一些不同。

      函数示例: 进程示例:

      Unsigned int fun(void) void thread(void)

      { {

      .... ......

      Return(ch); while(1){........}

      } }

      最大的区别是,函数总归要返回到被调用处,而进程则是无限循环,不会主动结束。

      RTOS程序有一定数量的进程组成,在调度器控制下运行。调度器使用Systick中断生成时间片,并以时间片为单位分配各个进程的运行时间。如,进程1运行5ms,而后调度器将CPU分配给进程2一个相似的时间段,然后将cpu分别给进程3,......。宏观来看,好像各个进程同步运行。

      在概念层面,程序包含数个同步运行的进程,而每个进程则是完成特定功能的独立代码段。进程代码的独立性,使设计代码、测试可限制在进程内进行,进而组合各个进程完成程序设计,这就使进程利于面向对象程序设计。同样道理,进程可将调试局限在进程内,也更利于调试。后续可发现,进程对提高代码复用性同样有利。

      进程在创建时,系统自动分配进程ID,用作进程的标识,如下:

      osThreadId    id1,id2,id3

      完成进程切换,需要制定硬件定时器作为RTOS时间片参考,并消耗一定的代码开销。当进程切换时,系统需要保存正在运行的进程信息,同时加载将要运行的进程的信息,统称为"任务切换时间",它是评估RTOS的重要指标。进程信息保存在进程控制块中。

    2.4创建进程

     

    1. 一个创建进程的示例:

      Void thread1(void const *parm);

      osThreadDef(thread1,osPriorityNormal, 1, 0);

      优先级 实例数 stacksize(0默认size)

      osThreadId thread1_id = osThreadCreate(osThread(thread1),NULL);

      Void thread1(void const *parm)

      {

      //init code

      While(1) //thread body

      {

      ......

      }

      }

    2.5进程优先级和进程管理

     

    1. 一经创建,系统分配进程ID,进程ID是管理进程的标识。

      进程有优先级特性,如图:

      管理进程包括设置优先级,读取优先级,进程消亡等,Api如下:

      osStatus osThreadSetPriority(threadID,priority);

      osPriority osThreadGetPriority(threadID);

      osStatus osThreadTerminate(threadID);

    2.6多实例进程

     

    1. 进程支持多实例,如Ex4 Multiple Instance,代码摘录:

      void Led_Switch(void const *argument)

      {

      LED_ON((uint32_t)argument);

      Delay(500);

      LED_OFF((uint32_t)argument);

      Delay(500);

      }

      osThreadDef(osThread(Led_Swtich),osPriorityNormal,2,0);

      osThreadId id1 = osThreadCreate(osThread(Led_Swtich),(void *)1);

      osThreadId id2 = osThreadCreate(osThread(Led_Swtich),(void *)2);

    2.7开始RTOS

     

    默认,RTOS自main函数起接管系统调度,所以main函数是第一个运行中进程。一旦进入main函数,首先调用osKernelInitialize()停用调度,以争取时间完成硬件初始化(如GPIO配置,USART配置等)和创建需要的进程或其他RTOS组件,而后调用osKernelStart()将系统控制权交还给RTOS,如下代码示例:

    Void main(void)

    {

    osKernelInitialize();

    //user code

    Init_thread();

    osKernelStart();

    }

    上例中,main进程在完成进程创建后运行到"}"时消亡,这在RTOS中是不推荐的。Main函数也可作为一个进程,并通过ID管理,如下:

    osThreadId main_id;

    Void main(void)

    {

    osKernelInitialize();

    //user code

    main_id = osThreadGetId(); //返回当前进程ID

    Init_thread();

    osKernelStart();

    While(1) //thread body

    {

    }

    }

    三.时间管理

    RTOS提供基本的时间管理组件。

    3.1延时函数

    事件组件中最基本的服务就是延时函数,在应用程序中可直接调用延时函数,非常方便。

    插曲:尽管RTOS内核约5K左右,相比于非RTOS系统中延时循环的无用代码消耗,RTOS还是优势明显,这就是RTOS出现的原因。

    函数原型:void osDelay(uint32_t millisec)

    调用延时函数的进程会进入WAIT_DELAY状态并持续延时函数制定的时间(millisec),调度器转向其他READY状态进程。延时结束,进程进入READY状态,等待调度器调度。

    3.2等待事件

    除了等待制定的时间,osWait也可中断进程并使进程进入等待状态直至被重新触发(触发时间可以是信号、信号量、消息等),并且osWait同样支持指定延时的周期。

    函数原型:osStatus osWait(uint32_t millisec)

    注意:keil RTX不支持此节内容。

    3.3虚拟定时器

    CMSIS-RTOS支持虚拟定时器,虚拟定时器向下计数,溢出时运行用户定义的call-back函数。虚拟定时器可以定位为单次和循环模式,步骤如下:

    1. 定义回调函数(call-back);

    2. 定义定时器结构体;

    3. 创建定时器;

    4. 启动定时器;

    如Ex 6 Virtual Timers代码摘录:

    void callback(void const *pram)

    {

    Switch((uint32_t) pram)

    {

    case 0:

    GPIOB->ODR ^= 0x8;

    Break;

    case 1:

    GPIOB->ODR ^= 0x4;

    Break;

    case 2:

    GPIOB->ODR ^= 0x2;

    Break;

    case 3:

    Break;

    }

    }

    osTimerDef(osTimer(Timer0_handle),callback);

    osTimerDef(osTimer(Timer1_handle),callback);

    osTimerDef(osTimer(Timer2_handle),callback);

    osTimerDef(osTimer(Timer3_handle),callback);

    osTimerId timer0 = osTimerCreate(osTimer(Timer0_hanlder),osTimerPeriodic,(void *)0);

    osTimerId timer1 = osTimerCreate(osTimer(Timer1_hanlder),osTimerPeriodic,(void *)1);

    osTimerId timer2 = osTimerCreate(osTimer(Timer2_hanlder),osTimerPeriodic,(void *)2);

    osTimerId timer3 = osTimerCreate(osTimer(Timer3_hanlder),osTimerPeriodic,(void *)3);

    osTimerStart(timer0_handle,0x100);

    osTimerStart(timer1_handle,0x100);

    osTimerStart(timer2_handle,0x100);

    osTimerStart(timer3_handle,0x100);

    3.4微秒延时

    借用系统中的Systick原始计数值可实现微妙延时。微妙延时不触发调度,它仅仅暂停执行指定时间段,遵循如下步骤:

    1. 获取Systick原始计数值;

    2. 定义延时时间段;

    3. 等待延时结束;

    示例代码如下:

    Uint32_t tick,delayPeriod;

    tick = osKernelSysTick(); //1

    delayPeriod = osKernelTickMicroSec(100); //2

    do{

    ....

    }while((osKernelSysTick()-tick) < delayPeriod); //3

    3.5空闲进程

    空闲进程在系统没有可用进程时被调用,以防止系统没有进程可用。

    空闲进程定义在RTX_Conf_CM.c中,并允许用户自定义代码。通常情况下,空闲进程中配置CPU进入低功耗状态。如此一来,当Systick中断或其他中断时唤醒调度,如有可运行进程则运行进程,否则继续进入低功耗状态。

    示例代码:Ex 7 Idle

    四.信号

     

    4.1功能描述

     

    CMSIS-RTOS keil RTX的进程支持多达16个信号,信号保存在进程控制块中。当进程中存在等待信号时(不管是单个等待信号还是多个等待信号),进程暂停执行直至其他进程发出了被等待的信号。

    调用信号等待函数,将触发当前进程中止运行并进入等待状态。处于等待状态的进程满足以下两个条件时退出等待,进入可被调度状态:

    1. 等待的信号被置位;

    2. 等待的时间溢出;

    信号等待函数原型:osEvent osSignalWait(uint32_t signals,uint32_t millisec)

    等待时间设置为0fffff,表示始终不溢出;

    等待时间设置为0时,表示任一信号置位即可引起中止等待;

    其他进程可置位或清除等待信号:

    Uint32_t osSignalSet(osThreadId thread_id,uint32_t signals)

    Uint32_t osSignalClear(osThreadId thread_id,uint32_t signals)

    另,调用osEvent.value.signals,返回值指示当前被置位信号。

    4.2例程

     

    "Ex8 Signals"

    4.3中断进程

     

    CMSIS-RTOS使用Systick中断作为系统时钟。因Systick中断的服务等级设定为最低级,当中断服务程序(ISR)的运行时间超出一个Systick中断时,系统中断将受到影响。

    于是,在CMSIS-RTOS中,正确的处理方式是将中断服务定义为一个进程,进程中等待信号。而在中断服务中,仅仅给中断进程发送信号。从而极大缩短中断服务程序的长度,转而在线程中执行。

    示例代码:

    osThreadDef(osThread(isr_thread),osPriorityNormal,1,0);

    osThreadId Isr_thread_id = osThreadCreate(osThread(isr_thread),NULL);

    中断线程:void isr_thread(void const *pram)

    {

    ....

    While(1)

    {

    osSignalWait(isrSignal,waitForever);

    .....

    }

    }

    中断服务程序:void IRQ_Handler(void)

    {

    osSignalSet(Isr_thread_id,isrSignal);

    }

    4.4内核权限调用SVC

     

    CMSIS-RTOS运行在unprivilege模式下,当需要在进程中访问privilege资源时,有两种方式:

    1. 在配置文件中提升进程的权限至privilege状态(如下图所示),但会造成所有的进程运行在privilege模式下,影响系统安全。

    参考例程"Ex9 interrupt signal"

    1. 在需要privilege权限时运行"系统级"代码。

    4.4.1SVC

     

    遵循如下步骤:

    1. 新建"系统级"代码列表(.s汇编文件),如下图:

      SVC_Tables.s代码如下:
          

      AREA SVC_TABLE, CODE, READONLY

      EXPORT SVC_Count

      SVC_Cnt EQU (SVC_End-SVC_Table)/4

      SVC_Count DCD SVC_Cnt

      ; Import user SVC functions here.

      IMPORT __SVC_1 //第一个"系统级"代码

      EXPORT SVC_Table

      SVC_Table

      ; Insert user SVC functions here. SVC 0 used by RTL Kernel.

      DCD __SVC_1 ; user SVC function

      SVC_End

      END

      其中__SVC_1就是"系统级"用户代码函数。

    2. 建立"系统级"代码与"进程级"代码接口,示例:

      void __svc(1) init_ADC (void);

      __svc(1)代表SVC_Tables.s中第一个"系统级"代码,同样如果有多个应用,依次递增即可。

    3. 编写"系统级"代码,如下图:

      Void __SVC_1 (void)

      {

      ......

      }

      在完成定义后,进程中调用init_ADC()将自动执行__SVC_1()中的代码。

    五.信号量

     

    5.1功能描述

    与信号类似,信号量是两个或多个进程同步的方法。

    信号量项是一个包含多个信号的容器。当进程执行到需要信号量的代码段(进程申请信号量),如果信号量中有信号可用(包含不少于一个的信号),则进程继续执行,并且信号量中的信号数自减一。相反,如信号量中无信号可用(包含0个信号),则进程中止执行并等待信号量中的信号可用。

    同时,进程中可向信号量添加信号数目,从而引起信号量中的可用信号数增一。

    如上图。假定信号量初始化为只有一个可用信号,当任务1提出申请时,信号量中含有1个可用信号,则任务1继续执行并引起信号量中的可用信号为0。此时任务2若提出申请因信号量中无可用信号,任务2进入信号量等待状态,直至任务1释放信号量。

    可见,进程可以释放信号给信号量。

    5.2创建信号量

    示例代码:

    osSemaphoreId sem1;

    osSemaphoreDef(sem1);

    sem1 = osSemaphoreCreate(osSemaphore(sem1),SIX_TOKENS);

    定义了一个含有6个可用信号的信号量sem1。

    信号量初始化后,进程中即可申请信号量,使用函数:

    osSemaphoreWait(osSemaphoreId sem_id,uint_32 millisec)

    Millisec = 0xffff wait for ever

    信号量使用结束后,释放信号量,使用函数:

    osSemaphoreRelease(osSemaphoreId sem_id);

    5.3例程

    Ex11 Interrupt Signals

    5.4使用场景

    5.4.1信号

    两个线程间同步执行是信号量最基本的应用。示例代码:

    osSemaphoreId sem_id;

    osSemaphoreDef(sem_id);

    void task1(void)

    {

    Sem_id = osSemaphoreCreate(osSemaphore(sem1),0);

    While(1)

    {

    Fun(A);

    osSemaphoreRelease(sem1);

    }

    }

    Void task2(void)

    {

    While(1)

    {

    osSemaphoreWait(sem1,osWaitForever);

    Fun(B);

    }

    }

    在这个案例中,Fun(A)始终先于Fun(B)执行。

    5.4.2限额

    限额用于限制某些资源的配额。例如,某个指定的内存块只运行指定数目的应用访问。

    如下例程,信号量初始化为5个信号,每个申请信号量的线程造成信号自减,当获取信号量的进程为5个时,后续申请信号量的进程进入等待状态,直至已获取配额的进程释放信号量,代码例程:

    osThreadId sem_id;

    osThreadDef(sem1);

    Void task1(void)

    {

    Sem_id = osThreadCreate(osThread(sem1),5);

    While(1)

    {

    osSemaphoreWait(sem1,osWaitForever);

    ProcessBuffer();

    osSemaphoreRelease(sem1);

    }

    }

    Void task2(void)

    {

    While(1)

    {

    osSemaphoreWait(sem1,osWaitForever);

    ProcessBuffer();

    osSemaphoreRelease(sem1);

    }

    }

    ......

    例程"Ex12 Multiplex"。

    5.4.3互锁(2个线程同步)

    互锁是两个线程同步的另一种通用模式。互锁确保两个线程得到同一互锁点。如下例程:

    osSemaphoreId arrival1,arrival2;

    osSemaphoreDef(sem1);

    osSemaphoreDef(sem2);

    Void task1(void)

    {

    arrival1 = osSemaphore(osSemephore(sem1),0);

    arrival2= osSemaphore(osSemephore(sem2),0);

    While(1)

    {

    FunA1();

    osSemaphoreRelease(arrival2);

    osSemaphoreWait(arrival1);

    FunA2();

    }

    }

    Void task2(void)

    {

    While(1)

    {

    FunB1();

    osSemaphoreRelease(arrival1);

    osSemaphoreWait(arrival2);

    FunB2();

    }

    }

    此例程中,确保FunA2()、FunB2()同步执行。

    5.4.4屏障(多个线程同步)

    屏障是多个进程同步的有效模式,它的总体思路:设置一个初始化为0的信号量作为屏障,并在所有进程达到同步点时依次释放屏障中的信号量,达到同步执行的目的。

    例程"Ex14 Barrier"

    5.5注意事项

    信号量是RTOS中极端有效的模式。然而,因信号量可在进程中增减甚至销毁,信号量中可用配额数比较难把控,使用时必须实时把控可用配额数。

    六.互斥量

    6.1功能描述

    单从功能来讲,互斥量可以看做只含有一个可用配额且不可被创建和销毁的特殊信号量。互斥量主要用于防止对硬件的访问冲突,比如同一时刻只能有一个应用访问串口,否则将造成数据混乱。

    申请互斥量的进程,必须等待互斥量中存在有效配额,否则进入等待状态。

    6.2创建互斥量

    创建互斥量与创建信号量类似,示例代码如下:

    osMutexId    uart_mutex;

    osMutexDef(Mutex1);

    进程中创建互斥量:uart_mutex = osMutexCreate(osMutex(Mutex1));

    其他进程申请互斥量:osMutexWait(uart_mutex);

    使用完毕释放互斥量:osMutexRelease(uart_mutex);

    6.3例程

    例程"Ex15 Mutex"

    6.4注意事项

    互斥量的使用限制多,也更安全,但扔要注意以下内容:

    1. 使用完毕必须及时释放互斥量,否则将造成后续进程无法使用该资源;

    2. 调用ThreadTerminate()函数消亡进程时,必须确保该进程没有占用互斥量,否则将造成后续进程无法使用该资源;

    七.数据交换

    信号、信号量、互斥量只用于进程之间的触发,但对进程间的数据交换无能为力。进程间数据交换最简单的方式是全局变量,但即使在简单的系统中,把握和灵活应用全局变量也是不小的挑战,因为全局变量会引起一系列不可预知错误。

    在RTOS中,消息队列和邮箱队列是进程间数据交互最为有效、安全的方式。

    消息队列和邮箱队列的工作方式基本一样,唯一的区别是消息队列中传输的是待交换数据,而邮箱队列中传输是指向待交换数据的指针,如下图所示:

    使用消息队列和邮箱队列进行数据交换有如下好处:

    1. 规范进程间数据交换的接口和缓存,为设计子系统提供可能;

    2. 规范进程的输入、输出,使进程独立测试、调试成为可能;

    7.1消息队列

    7.1.1创建消息队列

    创建消息队列,遵循如下步骤:

    1. 声明消息队列ID,示例:osMessageQId Q_id;

    2. 定义消息队列结构体,示例:osMessageQDef(Q1,16_Message_Slots,unsigned int);其中16_Message_Slots指示空间大小为16,unsigned int指示空间类型;

    3. 在进程中创建消息队列,示例:Q_id = osMessageQCreate(osMessageQ(Q1),NULL);

    4. 声明解析消息队列数据的osEvent类型数据,示例:osEvent result;

    5. 在进程中发送数据到消息队列,例程:osMessagePut(Q_id,Data,osWaitForever);

    6. 在另一进程中获取消息队列数据,例程:result = osMessageGet(Q_id,osWaitForever);result.value.xxx;

    其中,osEvent是个union结构体,如下所示:

    Union{

    Uint32_t v;

    Void *p;

    Uint32_t signals;

    }value

    7.1.2例程

    "Ex16 Message queue"

    7.2内存链

    7.2.1功能描述

    消息队列中的数据类型可以是数据本身,也可以是指向数据的指针。

    消息队列中存储的数据是指向特定内存区域的指针,这样的进程间交换数据的方式成为内存链。

    结构体可以达到规范化特定内存区域的目的。

    7.2.2创建内存链

    创建内存链,遵循如下步骤:

      1.定义结构体,用于规范内存块及初始化指针,示例:

    Typedef    struct {

    Uint8_t led1;

    Uint8_t led2;

    Uint8_t led3;

    Uint8_t led4;

    }memory_block_t;

      2.初始化内存链,示例:

    osPoolId pool_id;

    osPoolDef(pool_t,ten_blocks,memory_block_t);

    在进程中创建pool_id = osPoolCreate(osPool(pool_t));

      3.初始化消息队列,示例:

    osMessageQDef(q1,ten_blocks,memory_block_t);

    osMessageQid q_id;

    在进程中创建:q_id = osMessageQCreate(osMessageQ(q1),NULL);

      4.发送消息队列,示例:

    memory_block_t *led = (memory_block_t *)osPoolAlloc(pool_id);

    led->led1 = xx;....

    osMessagePut(q_id,led,osWaitForever);

      5.读取消息队列,示例:

    osEvent evt;

    evt = osMessageGet(q_id,osWaitForever);

    memory_block_t *temp = (memory_block_t *)evt.value.p;

      6.使用完毕释放内存链:示例:

    osPoolFree(pool_id,temp);

    7.2.3例程

    "Ex16 MemoryPool"

    7.3邮箱队列

     

    7.3.1功能描述

     

    邮箱队列是将内存链融合到消息队列中而成,邮箱队列中存储的同样是指向特定内存区域的指针。

    7.3.2创建邮箱队列

     

    同样采用7.2.2中的结构体作为数据基础,Typedef    struct {

    Uint8_t led1;

    Uint8_t led2;

    Uint8_t led3;

    Uint8_t led4;

    }memory_block_t;

    创建邮箱队列遵循如下步骤:

    1.创建邮箱队列,例程:

     

    osMailQDef(MQ_1,ten_blocks,memory_block_t);

    osMailQId mq_id;

    进程中创建,mq_id = osMailQCreate(osMailQ(MQ_1),NULL);

    2.发送数据,例程:

     

    Memory_block_t *led = (memory_block_t *)osMailAlloc(mq_id);

    led->led1 = xx;....

    osMailQPut(mq_id,led);

    3.读取数据,例程:

     

    osEvent evt;

    evt = osMailGet(mq_id,osWaitForever);

    Memory_block_t *temp = (memory_block_t *)evt.value.p;

    4.使用完毕释放邮箱队列,示例:

     

    osMailFree(mq_id,temp);

    7.3.3例程

     

    "Ex17 MailQueue"

    八.系统配置

     

    掌握前面的内容,对CMSIS-RTOS有了总体的认识。CMSIS-RTOS包括进程管理、时间管理、进程间通讯等。

    本章着力于讨论如何配置系统。CMSIS-RTOS针对基于Cortex-M构架的处理器,提供一个统一的配置文件,RTX_Conf_CM.c,如下图:

    8.1进程参数

     

    在讨论进程的相关章节中一经接受了创建进程的基础知识。

    每个进程,系统分配一块内存空间用作进程栈(默认200bytes),栈空间在进程创建时指定。

    应用中最多允许运行的进程数可配置。

    由于进程栈空间、进程数可配置,应用中的内存需求也可很容易的计算出来。

    8.2内核调试支持

    内核可配置项,包括:

    8.2.1追踪溢出

    选择该项"stack overflow checking",出现进程栈溢出RTOS内核调用os_error函数并进入死循环。该项主要用于调试阶段的问题追踪,当然也可自定义os_error函数用于最终的应用中打印错误信息,os_error代码在RTX_CONF_CM.C文件中,源码:

    /* OS Error Codes */

    #define OS_ERROR_STACK_OVF 1

    #define OS_ERROR_FIFO_OVF 2

    #define OS_ERROR_MBX_OVF 3

    #define OS_ERROR_TIMER_OVF 4

    extern osThreadId svcThreadGetId (void);

    /// \brief Called when a runtime error is detected

    /// \param[in] error_code actual error code that has been detected

    void os_error (uint32_t error_code) {

    /* HERE: include optional code to be executed on runtime error. */

    switch (error_code) {

    case OS_ERROR_STACK_OVF:

    /* Stack overflow detected for the currently running task. */

    /* Thread can be identified by calling svcThreadGetId(). */

    break;

    case OS_ERROR_FIFO_OVF:

    /* ISR FIFO Queue buffer overflow detected. */

    break;

    case OS_ERROR_MBX_OVF:

    /* Mailbox overflow detected. */

    break;

    case OS_ERROR_TIMER_OVF:

    /* User Timer Callback Queue overflow detected. */

    break;

    default:

    break;

    }

    for (;;);

    }

    8.2.2监控栈使用率

    选择"stack usage watermark"项,oxcc样式自动写入进程栈。运行时,watermark用于计算最大栈内存使用率,并在"system and Event viewer"窗口报告,如下图所示:

    8.2.3用户定时器数

    如用户定时器数量与应用中使用的虚拟定时器不符,会造成os_timer()函数失效。

    8.2.4进程运行权限选择

    如"Ex9 interruter signal",进程运行权限可配置。

    8.3系统时基

    默认的系统时基是Cortex-M中的SysTick定时器。但,也支持自定义使用其他定时器作为系统时基。

    8.4时间片

    默认的时间片是5ms。

    8.5调度选项

    调度器支持如下三种调度模式:

    1.抢占式

    此模式下,系统中进程拥有不同的优先级,当拥有高优先级的进程进入"ready"状态,调度器转入高优先级进程运行。

    2.轮询式

    此模式下,系统根据时间片为每个进程分配运行时间,处于运行态的进程在时间片到来时触发调度(注意,即使高优先级的进程进入"ready"状态也要等时间片结束)。

    3.轮询、抢占式(默认状态)

    此模式下,系统根据时间片为每个进程分配运行时间,处于运行态的进程在时间片到来时或高优先级的进程进入"ready"态触发调度(注意,高优先级的进程进入"ready"状态将马上触发调度)。

    4.协同式

    此模式下,进程拥有相同的优先级,有且仅有运行态的进程主动申请系统调度才会引起调度。

    8.6源码调试

    如果用户需要源码级别的调试,遵循如下步骤:

    1. 新建文本文件,命名为"xxx.ini";

    2. "xxx.ini"中添加,SET SRC = <PATH>,其中<PATH>是RTX源码的文件夹,默认是C:\Keil\ARM\pack\arm\cmsis\<version>\cmsis\rots\rtx。

    3. 在调试文件中导入"xxx.ini",如下图所示:

    注:"xxx.ini"中xxx代表任意长度满足PC操作系统命名规格的字符串。

    展开全文
  • 目录作者介绍CMSIS-RTOS2接口简介鸿蒙与CMSIS-RTOS2接口联系如何使用CMSIS-RTOS2接口 作者介绍 刘懿宵,男,西安工程大学电子信息学院,2017级本科生。 专业:通信工程 电子邮件:liuyixiao@stu.xpu.edu.cn CMSIS-...

    HarmonyOS CMSIS-RTOS2接口简介

    作者介绍

    刘懿宵,男,西安工程大学电子信息学院,2017级本科生。
    专业:通信工程
    电子邮件:liuyixiao@stu.xpu.edu.cn

    CMSIS-RTOS2接口简介

    什么是CMSIS-RTOS2接口
    CMSIS是Cortex微控制器软件接口标准(Cortex Microcontroller Software Interface Standard)是ARM和一些编译器厂家以及半导体厂家共同遵循的一套标准,是由ARM专门针对Cortex-M系列提出的标准。在该标准的约定下,ARM和芯片厂商会提供一些通用的API接口来访问Cortex内核以及一些专用外设,以减少更换芯片以及开发工具等移植工作所带来的金钱以及时间上的消耗。

    CMSIS-RTOS2(CMSIS-RTOS API Version 2)是Arm® Cortex®-M 处理器的通用的RTOS接口。为需要RTOS功能的软件组件提供了标准化的API。

    CMSIS-RTOS2是一个通用的API,它与底层的RTOS内核无关,写应用序的程序员在用户代码中调用CMSISRTOS2 API函数,可以更方便地将应用程序从一个RTOS到另一个RTOS,使用CMSIS-RTOS2 API的中间件也可以避免很多不必要的移植工作。

    鸿蒙与CMSIS-RTOS2接口联系

    鸿蒙在CMSIS-RTOS2接口中封装了LiteOS-m的内核代码
    CMSIS-RTOS2实现://kernel/liteos_m/kal/cmsis/cmsis_liteos2.c
    在这里插入图片描述
    在这里插入图片描述

    osStatus_t osKernelInitialize(void)
    {
        if (OS_INT_ACTIVE) {
            return osErrorISR;
        }
    
        if (g_kernelState != osKernelInactive) {
            return osError;
        }
    
        if (LOS_OK == LOS_KernelInit()) {
            g_kernelState = osKernelReady;
            return osOK;
        } else {
            return osError;
        }
    }
    

    调用了LOS_KernelInit

    osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)
    {
        UINT32 uwTid;
        UINT32 uwRet;
        LosTaskCB *pstTaskCB = NULL;
        TSK_INIT_PARAM_S stTskInitParam;
    
        if (OS_INT_ACTIVE) {
            return NULL;
        }
    
        if ((attr == NULL) || (func == NULL) || (attr->priority < osPriorityLow1) ||
            (attr->priority > osPriorityAboveNormal6)) {
            return (osThreadId_t)NULL;
        }
    
        (void)memset_s(&stTskInitParam, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
        stTskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)func;
    #ifndef LITEOS_WIFI_IOT_VERSION
        stTskInitParam.uwArg = (UINT32)argument;
    #else
        stTskInitParam.auwArgs[0] = (UINT32)argument;
    #endif
        stTskInitParam.uwStackSize = attr->stack_size;
        stTskInitParam.pcName = (CHAR *)attr->name;
        stTskInitParam.usTaskPrio = OS_TASK_PRIORITY_LOWEST - ((UINT16)(attr->priority) - LOS_PRIORITY_WIN); /* 0~31 */
    
        uwRet = LOS_TaskCreate(&uwTid, &stTskInitParam);
    
        if (LOS_OK != uwRet) {
            return (osThreadId_t)NULL;
        }
    
        pstTaskCB = OS_TCB_FROM_TID(uwTid);
    
        return (osThreadId_t)pstTaskCB;
    }
    

    新建

    osStatus_t osDelay(uint32_t ticks)
    {
        UINT32 uwRet = 0;
        if (ticks == 0) {
            return osOK;
        }
        if (osKernelGetState() != osKernelRunning) {
            uwRet = LOS_HalDelay(ticks);
        } else {
            uwRet = LOS_TaskDelay(ticks);
        }
        if (uwRet == LOS_OK) {
            return osOK;
        } else {
            return osError;
        }
    }
    

    延迟

    如何使用CMSIS-RTOS2接口

    1、在业务代码中包含“cmsis_os2.h”
    2、通过调用“cmsis_os2.h”中的API函数使用系统相关功能

    osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr);
     //新建
    /**
    * @brief Obtains the name of a thread.
    *
    * @param thread_id Indicates the thread ID, which is obtained using osThreadNew or osThreadGetId.
    * @return Returns the thread name; returns NULL in the case of an error.
    * @since 1.0
    * @version 1.0
    */
    const char *osThreadGetName (osThreadId_t thread_id);
     //获取任务名
    /**
    * @brief Obtains the ID of the currently running thread.
    *
    * @return Returns the thread ID; returns NULL in the case of an error.
    * @since 1.0
    * @version 1.0
    */
    osThreadId_t osThreadGetId (void);
     //获取任务ID
    
    /**
    * @brief Obtains the state of a thread.
    *
    * @param thread_id Indicates the thread ID, which is obtained using osThreadNew or osThreadGetId.
    * @return Returns the thread state.
    * @since 1.0
    * @version 1.0
    */
    

    更多API介绍请参考:https://arm-software.github.io/CMSIS_5/RTOS2/html/index.html
    主要看这部分
    主要看这部分

    往期回顾

    2021物联网开发学习自学历程记录汇总

    展开全文
  • CMSIS-RTOS Presentation
  • 获取有关CMSIS-RTOS API的版本信息。 用于创建对象的RTOS内核的初始化。 启动RTOS内核和线程切换。 检查RTOS内核的执行状态。 注意: 不能从中断服务例程中调用内核信息和控制功能。 RTX5的内核初始化记录...
  • CMSIS-RTOS的使用

    千次阅读 2018-08-20 11:14:00
    CMSIS-RTOS实现通常作为库提供。要将RTOS功能添加到现有的基于CMSIS的应用程序,需要添加RTOS库(通常是配置文件)。RTOS库的可用功能在头文件cmsis_os.h中定义,该文件特定于每个CMSIS-RTOS实现。 根据CMSIS-...
  • CMSIS-RTOS2 入门教程 [1]——工作原理

    千次阅读 2020-03-17 22:53:54
    在 Time == 5期间,当最高优先级的线程4被 阻塞RTOS-call(blocking RTOS-call) 再次阻塞时,立即切换回线程3。 在 Time == 5期间,线程3也使用了一个 阻塞RTOS-call。因此,调度器将切换回线程2 内存分配 Memory ...
  • CMSIS-RTOS手册

    2021-03-22 16:41:51
    CUBEIDE生成的freeRTOS代码是经过CMSIS封装过的,与原版freertos有些许差异。...https://arm-software.github.io/CMSIS_5/RTOS2/html/group__CMSIS__RTOS__Message.html#gaa515fc8b956f721a8f72b2c505813bfc ...
  • STM32中使用CMSIS-RTOS建立任务
  • CMSIS-RTOS中,此机制称为s消息队列。数据以类似FIFO的操作从一个线程传递到另一个线程。使用消息队列功能,您可以控制,发送,接收或等待消息。要传递的数据可以是整数或指针类型: CMSIS-RTOS消息队列 ...
  • CMSIS-RTOS2 文档翻译 之 通用 RTOS 接口

    千次阅读 2018-04-21 15:39:40
    通用 RTOS 接口 CMSIS-RTOS2 是一个通用的 API ,不受底层 RTOS 内核的影响。应用程序员在用户代码中调用 CMSIS-RTOS2 API 函数以确保从一个 RTOS 到另一个 RTOS 的最大可移植性。使用 CMSIS-RTOS2 API 的中间件可以...
  • 官方文档:https://arm-software.github.io/CMSIS_5/RTOS2/html/index.html 中文翻译:https://blog.csdn.net/u012325601/category_9274156.html RTOS的一些系统概念解释:...
  • rtos需要额外的内存,中断响应变慢。 基本元素: 任务调度器: 支持round-robin、抢占式的多任务调度。 时间管理: 内存管理:mem pool 线程间通信:event group、semaphore、mutex、message 线程: --------...
  • 二、API说明 以下任务管理接口位于 kernel/liteos_m/components/cmsis/2.0/cmsis_os2.h。 业务BUILD.gn中包含路径 include_dirs = [ "//utils/native/lite/include", "//kernel/liteos_m/components/cmsis/2.0", ] ...
  • 二、API说明 以下任务管理接口位于 kernel/liteos_m/components/cmsis/2.0/cmsis_os2.h。 业务BUILD.gn中包含路径 include_dirs = [ "//utils/native/lite/include", "//kernel/liteos_m/components/cmsis/2.0", ] ...
  • 因为要使用CMSIS-RTOS的信号量,所以需要了解以下几点功能: 1.接收信号量时,返回值的意思 2.接收信号量时,如果信号量容器不只为一,那么是否可以再次接收到 3.发送信号量是否有限制 带着以上问题做了一个测试...
  • Keil官网 CMSIS-RTOS v2 信号量章节的网址 功能: 创建并初始化一个信号量 参数 max_count : 最大可获取的值 参数 initial_count : 可获取的初始值 参数 attr : 信号量的相关属性(名字,大小 ...) 返回值: 后面被...
  • 定义了CMSIS-RTOS RTX的配置参数,每一个使用CMSIS-RTOS RTX内核的项目的都必须有这个文件。下面几节将详细解释各个配置选项。 “RTX_Config文件”。包含空闲任务(osRtxIdleThread) 和异常报告函数(osRtxErrorNotify...
  • CMSIS-RTOS2 文档翻译 之 功能概述

    千次阅读 2018-04-22 14:20:16
    功能概述 CMSIS-RTOS v2 提供了多种 API 接口:CMSIS-RTOS2 是支持动态对象创建和 Armv8-M(Arm Cortex-M23 和 Cortex-M33)的新 C 函数 API 。CMSIS-RTOS C API v1 是与 CMSIS-RTOS v1 向后兼容的 C 函数 API 。...
  • 最近使用CMSIS-RTOS(以下简称RTX)时遇到全局变量被意外更改的情况,检查代码没有发现有更改这个变量的情况,因此怀疑是栈溢出导致的,修改的是启动文件里的Stack_Size后问题解决,因此确定是栈溢出导致的。...
  • [CMSIS-RTOS2]线程间通信

    2020-12-03 00:51:08
    Event Flags: 类似于thread flags,但是需要创建,且作为global rtos对象,可以被所有线程使用。 osEventFlagsAttr_t { const char *name; ///; ///(none) void *cb_mem; ///; ///; osEventFlagsId_t EventFlag_...
  • CMSIS-RTOS RTX实时操作系统介绍

    万次阅读 多人点赞 2018-04-20 14:31:03
    CMSIS RTOS Api提供基于RTOS开发的接口,掌握后可跨多系列微控制器使用。另外,CMSIS RTOS Api也为高级应用(如Java虚拟机,UML)等提供标准接口。同时,CMSIS RTOS Api也是不依赖于硬件层的标准接口,支持代码...
  • 线程管理CMSIS-RTOS2 API 定义,创建和控制线程函数。更多...数据结构struct osThreadAttr_t 线程的属性结构体。更多... 宏定义#define osThreadJoinable 0x00000001U 线程在可连接模式下创建。更多... #...
  • 单片机型号:STM32F070F6P6 昨天,将FreeRTOS移植到STM32现有的工程后,今天希望使用RTOS进行工程设计,遇到的第1个问题,就是工程中的函数在...CMSIS-RTOS是keil公司对不同RTOS的一种封装结构,可以使不同的RTO...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,679
精华内容 671
关键字:

CMSIS-RTOS