MCU基础以及RTOS原理知识分享

**

1、什么是MCU?

  • MCU,中文简称单片机。即将CPU、存储器(RAM和ROM)、多种I/O接口等集成在一片芯片上,形成的芯片级计算机。早期MCU架构多是8位为主(例如Intel 8051系列、Atmel AT8/TS8系列、Labs EFM8系列等),且整合开发环境(IDE)也是以8位为主。
    近年来,MCU作为物联网的核心零组件,无论在市场规模,还是技术要求上都得到了飞速的发展。随着物联网时代任务的复杂化,对计算能力越来越高促使MCU开始迈向16或32位来设计,与此同时相关的软件开发环境也提升到32位,甚至做到可以向下兼容,让开发环境不受限于硬件,以提供更具弹性的开发空间。
  • 目前全球市场上的MCU厂商
    欧美系: 意法半导体 ST、恩智浦(飞思卡尔) NXP、德州仪器 TI、爱特梅尔 ATMEL、英飞凌 infineon、芯科实验室 silicon labs、塞朴拉斯(飞索半导体-富士通) cypress、亚德诺 ADI、美信 Maxim 、博通 Broadcom、美高森美 Microsemi、赛灵思 Xilinx、阿尔特拉 Altera、NORDIC;
    日韩系:瑞萨电子 Renesas、东芝半导体 Toshiba、三星电子 Samsung、微知纳特 WIZnet、现代单片机 ABOV;
    台系: 新唐科技 Nuvoton、盛群半导体 Holtek、松翰科技 Sonix、MTK;
    大陆系:海思半导体 Hisilicon、珠海全志 Allwinner、珠海炬芯、福州瑞芯微 Rockchip、北京兆易创新 DigaDevice、北京芯盈速腾。

2、ARM

ARM公司是全球领先的半导体知识产权(IP)提供商。全世界超过95%的智能手机和平板电脑都采用ARM架构。ARM设计了大量高性价比、耗能低的RISC处理器、相关技术及软件。2014年基于ARM技术的全年全球出货量是120亿颗,从诞生到现在为止基于ARM技术的芯片有600亿颗。技术具有性能高、成本低和能耗省的特点。在智能机、平板电脑、嵌入控制、多媒体数字等处理器领域拥有主导地位。
MCU基础以及RTOS原理知识分享_第1张图片
CISV以Intel和AMD的x86架构为代表,RISV以ARM和MIPS为代表,目前正在崛起的RISC-V也是RISV架构,开源采用宽松的BSD协议,企业完全自由免费使用,同时也容许企业添加自有指令集拓展而不必开放共享以实现差异化发展。
CISV和RISV区别
插曲:ARM与RISC-V的竞争
ARM上线了质疑risc-v的网站riscv-basics.com,24小时后又下线了,该网站列举了对RISC-V的几大质疑,包括:
-成本:虽然RISC-V是开源ISA,但是ISA仅仅是处理器芯片的一小部分,因此RISC-V的免费ISA对于整体处理器的成本影响并不大。
-生态系统:RISC-V生态系统不够完整,无法提供完整的(包括硬件到软件)设计支持。
-碎片化风险:RISC-V生态中每个项目都可能会做自己的私有指令集扩展,导致软件兼容性不好,即碎片化问题。
-安全性问题:之前由大厂出品的x86和ARM许多处理器都遇到了安全性问题(Spectre漏洞),而由一个尚处于起步阶段组织或初创公司发布的RISC-V处理器遇到安全性问题的可能性更大。
-设计验证:RISC-V虽然是开源指令集可以自行改动指令集,但是改动指令集会需要大量设计验证,所以如果设计验证完整度不够的情况下自行修改指令集反而容易出错。

3、ARM-Cortex™-M4

ARMCortex™-M4处理器是由ARM专门开发的嵌入式处理器,在M3的基础上强化了运算能力,新加了浮点、DSP、并行计算等,用以满足需要有效且易于使用的控制和信号处理功能混合的数字信号控制市场。其高效的信号处理功能与Cortex-M处理器系列的低功耗、低成本和易于使用的优点的组合,旨在满足专门面向电动机控制、汽车、电源管理、嵌入式音频和工业自动化市场的新兴类别的灵活解决方案。
以STM32L4R9为例,MCU中几个比较典型的外设:
MCU基础以及RTOS原理知识分享_第2张图片

  • Clock
    系统时钟,负责系统主频,各个外设运行频率,通过倍频和分频实现不同频率输出。
  • WDOG
    俗称看门狗,为了预防死机而设计的一种硬件定时器,通过软件程序定期喂狗(重新设定定时器参数),如果系统发生异常进入hardfault或者assert,喂狗程序无法执行,看门狗溢出触发MCU复位或者产生中断。
  • UART/USART
    俗称串口,前者支持异步输出,后者支持异步和同步输出(需要CK),支持硬件流控。经常作为log输出使用,我们的手表和手环上,一般是stm32+dialog,二者使用串口进行通信;有些WIFI和蓝牙芯片上作为AT命令通信端口使用。一般用于芯片间中低速、短距离通信,长距离通信一般要外接485或者422芯片,一般用于工控领域。
  • I2C
    I2C Bus(Inter-Integrated Circuit Bus) 最早是由Philips半导体(现被NXP收购)开发的两线时串行总线,同步半双工,常用于微控制器与外设之间的连接,只有两条总线SCL和SDA。一般用于低速、小数据通信场景和作为命令控制端口使用,支持多从机机制,比如手表上的触摸屏,气压计,光感等。
  • SPI
    Serial Peripheral Interface,是 Motorola 公司推出的一种同步串行接口技术,是一种高速、全双工、同步的通信总线,已知的有的器件SPI已达到50Mbps。常用于微控制器与外设之间的连接,通常有四条总线SCK、MISO、MOSI、CS,其中CS可以没有,也可以有多个CS,用于多从机场景。常见的3/6/9轴传感器、某些低分辨率显示屏、存储器(FLASH和EEPROM)等。
  • TIMER
    定时器,如名所示,不多说。
  • RTC
    Real Time Clock,提供精确的实时时间,或者为电子系统提供精确的时间基准,目前实时时钟芯片大多采用精度较高的晶体振荡器作为时钟源。
  • ADC/DAC
    模数转换,数模转换,模拟信号和数字信号之间的转换。

4、RTOS运行机制

仅仅从单处理器运行多线程这一点来说,实时嵌入式系统中的多任务与桌面电脑的多任务从概念上来讲是相似的。但实时嵌入式系统的侧重点却不同于桌面电脑——特别是当嵌入式系统期望提供”硬实时”行为的时候。
桌面电脑的输入处理可以归类为”软实时”。为了保证用户的最佳体验,计算机对每个输入的响应应当限定在一个恰当的时间范围——但是如果响应时间超出了限定范围,并不会让人觉得这台电脑无法使用。比如说,键盘操作必须在键按下后的某个时间内作出明显的提示。但如果按键提示超出了这个时间,会使得这个系统看起来响应太慢,而不致于说这台电脑不能使用。
硬实时功能必须在给定的时间限制之内完成——如果无法做到即意味着整个系统的绝对失败。汽车的安全气囊触发机制就是一个硬实时功能的例子。安全气囊在撞击发生后给定时间限制内必须弹出。如果响应时间超出了这个时间限制,会使得驾驶员受到伤害,而这原本是可以避免的。
大多数嵌入式系统不仅能满足硬实时要求,也能满足软实时要求。
(1)常见的嵌入式软件结构
可以分为轮询系统、前后台系统和多任务系统。这些方案是根据具体的需求提出的,各有各的特点和使用的领域。
MCU基础以及RTOS原理知识分享_第3张图片
(2)RTOS多任务机制概述

  • 时钟节拍
    时钟节拍是多任务系统的基础,它代表把处理器时间以多大的频率分割成固定长度的时间片段。硬件定时器产生周期性的中断,在中断服务函数中内核代码得以执行,进行任务调度等工作;
  • 多任务机制
    在单核系统中,在某一时刻只有一个任务在运行,但是可以通过将处理器时间分成小的时间段,多个任务按照一定的原则分享这些时间段的方法,轮流加载执行各个任务,宏观并行,微观串行。
    任务通常作为内核调度的基本和最小单位。
    某些系统,比如linux,线程是内核调度和资源分配的最小单位,一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。
  • 任务上下文
    任务是一个动态的概念,任务在处理器上运行的某一时刻,有自己的状态,即所有寄存器的数据,这个叫做任务的上下文,类似快照的概念。
  • 任务切换
    当操作系统需要运行其他任务时,操作系统会首先保存当前相关寄存器的数据到当前任务栈中,然后从将要加载的任务栈中取出之前保存的寄存器内容加载到相关寄存器中,从而继续运行被加载的任务,实现任务切换。
    uC/OS-III和FreeRTOS以及其他大多数RTOS的任务切换都是利用的PendSV中断。
    MCU基础以及RTOS原理知识分享_第4张图片
  • 任务调度
    基于优先级的调度:操作系统总是让具有最搞优先级的就绪任务运行,缺点:如果高优先级任务不主动让出使用权,其他任务将会永远无法被调度;
    基于时间片的调度:每个任务用完时间片后,操作系统把处理器的使用权交给其他任务,缺点:响应速度慢;
    基于优先级的的时间片调度:吸收了上述两者的优点,同时又解决了他们的不足。这种调度算法为每个任务都分配了时间片和优先级,不用优先级任务间采用优先级调度,相同优先级任务采用时间片调度。

uCOS-III中每个任务能保持的时间片可以单独设置,需要在任务初始化时作为形参传入。这样做的坏处是对用户不太友好(API的形参如果太多,应用开发人员接受起来有些麻烦);这样做的好处是不会在每个时间片都发生任务的切换(任务切换是需要开销的),提高了总的CPU利用率。
另外,uC/OS-III中,由于可以对每个任务的时间片分别进行设置和修改,所以可以很方便地调节同优先级下每个任务的CPU占用率,尽管两个任务的优先级是一样的,但是有个任务比较重要,我们希望让它的CPU占用率高一点,这时只要把它的时间片设置得大一点即可。而在FreeRTOS中同优先级下的每个任务对CPU的占用率都只能是一样。
  • 优先级翻转
    A、B、C三个不优先级从高到低的任务,A、C共享互斥量R,C先持有R,然后A尝试持有,结果被阻塞住,A运行过程中被B抢占,相当于低优先级的任务B间接阻塞了高优先级的任务A,这个现象违背了优先级机制的设计初衷。
    解决方案:
    优先级继承策略
    优先级天花板策略

    优先级继承策略对任务执行流程的影响相对较小,因为只有当高优先级任务申请已经被低优先级任务占有的资源时,才提升低优先级任务的优先级,而天花板策略是谁占有就直接升到最高,一步到位。
    著名案例:火星探路者(Mars Pathfinder, MPF)”于1997年07月04日在火星表面着陆。在开始的几天内工作稳定,并传回大量数据,但是几天后,“探路者”开始出现系统复位、数据丢失的现象。经过研发人员的分析,最后得出结论,就是因为系统里发生了优先级反转的问题。
    火星探路者采用了VxWorks操作系统,采用了优先级继承策略,默认情况下该功能被关闭,所以就有可能发生优先级反转,也就导致了“火星探路者”中问题的发生。
  • 任务状态
    常见的有:就绪、运行、等待、阻塞、挂起等。
    MCU基础以及RTOS原理知识分享_第5张图片
  • 中断机制
    中断是处理器重要的基础功能,用来应对处理各种事件的响应和处理。当外设或者处理器自身有事件发生时,处理器会暂停执行当前的代码,立刻执行中断服务程序。
    中断通常由三种:
    外部中断:如串口接收到数据,GPIO中断等;
    内部中断:处理器自身的原因引起的异常事件,如非法指令、总线错误、运算出错等;
    软件中断:一种特殊的中断,通过软件指令触发的,从而主动引起程序流程的变化,比如任务的调度就是通过软件中断PendSV 实现的,当操作系统决定要切换任务时,会通过软件触发一个PendSV 中断:
void xPortSysTickHandler( void )
{
	/* The SysTick runs at the lowest interrupt priority, so when this interrupt
	executes all interrupts must be unmasked.  There is therefore no need to
	save and then restore the interrupt mask value as its value is already
	known. */
	( void ) portSET_INTERRUPT_MASK_FROM_ISR();
	{
		/* Increment the RTOS tick. */
		if( xTaskIncrementTick() != pdFALSE )
		{
			/* A context switch is required.  Context switching is performed in
			the PendSV interrupt.  Pend the PendSV interrupt. */
			portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
		}
	}
	portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );
}

中断状态寄存器bit28位被写入1,将PendSV中断设置为挂起状态,等到优先级高于PendSV的中断执行完成后,PendSV中断服务程序将被执行,进行任务切换工作。
堆 Heap,用于动态内存分配,一般是通过定义一个数组实现固定内存分配,malloc从数组中分配内存:

/* Allocate the memory for the heap. */
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
	/* The application writer has already defined the array used for the RTOS
	heap - probably so it can be placed in a special segment or address. */
	extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
	static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
  • 栈 Stack
    在CM4处理器内核中共有两个栈指针,R13 是栈指针寄存器。
    当引用 R13(或写作SP)时,你引用到的是当前正在使用的那一个,另一个必须用特殊的指令来访问(MRS,MSR指令)。
    这两个堆栈指针分别是:
    主堆栈指针(MSP),或写作 SP_main。这是缺省的堆栈指针,它由 OS 内核、异常服务例程以及所有需要特权访问的应用程序代码来使用。
    进程堆栈指针(PSP),或写作 SP_process。用于常规的应用程序代码(不处于异常服例例程中时)。
    要注意的是,并不是每个应用都必须用齐两个堆栈指针。简单的应用程序只使用 MSP就够了。
    RTOS上的每个任务都有自己独立的栈空间,用于保存各自的任务快照,每次任务切换时,都会将新任务的栈空间指针加载到PSP,这样在任务中的函数参数和临时变量都可以保证在各自的任务栈空间分配,各个任务间实现了物理隔离。
    任务创建时分配会通过pvPortMalloc分配栈空间,要注意的是,分配栈空间时,要对任务中使用的栈大小大概估计一下再分配,否则会造成任务栈溢出,比如函数中的局部变量,函数调用时的现场保护和返回地址,函数的形参等,尤其要注意递归函数的使用。
	BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,
							const char * const pcName,		/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
							const configSTACK_DEPTH_TYPE usStackDepth,
							void * const pvParameters,
							UBaseType_t uxPriority,
							TaskHandle_t * const pxCreatedTask )

栈空间大小 = usStackDepth * sizeof( StackType_t ) bytes,在CM4上,sizeof( StackType_t ) = 4。
pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );

任务栈空间使用量估算方法:
(1)函数的嵌套调用,针对每一级函数用到栈空间的有如下四项:
函数局部变量;
函数形参,一般情况下函数的形参是直接使用的 CPU 寄存器,不需要使用栈空间,但是这个函数中如果还嵌套了一个函数的话,这个存储了函数形参的 CPU 寄存器内容是要入栈的。 所以建议大家也把这部分算在栈大小中;
函数返回地址,针对 M3 和 M4 内核的 MCU,一般函数的返回地址是专门保存到 LR(LinkRegister)寄存器里面的,如果这个函数里面还调用了一个函数的话,这个存储了函数返回地址的 LR 寄存器内容是要入栈的。 所以建议大家也把这部分算在栈大小中;
函数内部的状态保存操作也需要额外的栈空间;
(2)任务切换,任务切换时所有的寄存器都需要入栈,对于带 FPU 浮点处理单元的 M4 内核 MCU 来说,FPU 寄存器也是需要入栈的。
FreeRTOS 提供了两种栈溢出检测机制,这两种检测都是在任务切换时才会进行:
 方法一
在任务切换时检测任务栈指针是否过界了,如果过界了,在任务切换的时候会触发栈溢出钩子函
数。

void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );

用户可以在钩子函数里面做一些处理。这种方法不能保证所有的栈溢出都能检测到。比如任务在执行的过程中出现过栈溢出。任务切换前栈指针又恢复到了正常水平,这种情况在任务切换的时候是检测不到的。又比如任务栈溢出后,把这部分栈区的数据修改了,这部分栈区的数据不重要或者暂时没有用到还好,但如果是重要数据被修改将直接导致系统进入硬件异常,这种情况下,栈溢出检测功能也是检测不到的。
使用方法一需要用户在 FreeRTOSConfig.h 文件中配置如下宏定义:

#define configCHECK_FOR_STACK_OVERFLOW 1

 方法二
任务创建的时候将任务栈所有数据初始化为 0xa5,任务切换时进行任务栈检测的时候会检测末尾的 16 个字节是否都是 0xa5,通过这种方式来检测任务栈是否溢出了。相比方法一,这种方法的速度稍慢些,但是这样就有效地避免了方法一里面的部分情况。 不过依然不能保证所有的栈溢出都能检测到,比如任务栈末尾的 16 个字节没有用到,即没有被修改,但是任务栈已经溢出了,这种情况是检测不到的。 另外任务栈溢出后,任务栈末尾的 16 个字节没有修改,但是溢出部分的栈区数据被修
改了,这部分栈区的数据不重要或者暂时没有用到还好,但如果是重要数据被修改将直接导致系统进入硬件异常,这种情况下,栈溢出检测功能也是检测不到的。
使用方法二需要用户在 FreeRTOSConfig.h 文件中配置如下宏定义:

#define configCHECK_FOR_STACK_OVERFLOW 2

 钩子函数
钩子函数的主要作用就是对原有函数的功能进行扩展,用户可以根据自己的需要往里面添加相关的测
试代码, 大家可以在 FreeRTOS 工程中检索这个钩子函数 vApplicationStackOverflowHook 所在的位
置。
追踪Hardfault的原因:
MCU基础以及RTOS原理知识分享_第6张图片
MCU基础以及RTOS原理知识分享_第7张图片
R14 是连接寄存器( LR),在一个汇编程序中,你可以把它写作 LR 和 R14。 LR 用于在调用子程序时存储返回地址。例如,当你在使用 BL(分支并连接, Branch and Link)指令时,就自动填充 LR 的值。
R15 是程序计数器,在汇编代码中你也可以使用名字“PC”来访问它。
当MCU出现死机问题时,可以通过查看R14和R15的内容来复现死机现场:
在发生hardfault时,把R14和R15的值保存下来,通过查看map文件中的函数地址信息,可以得知发生死机时的主程序和子程序信息。
4、FreeRTOS的介绍
(1)特点
在嵌入式领域中,嵌入式实时操作系统正得到越来越广泛的应用。采用嵌入式实时操作系统(RTOS)可以更合理、更有效地利用CPU的资源,简化应用软件的设计,缩短系统开发时间,更好地保证系统的实时性和可靠性。由于RTOS需占用一定的系统资源(尤其是RAM资源),只有μC/OS-II、embOS、salvo、FreeRTOS等少数实时操作系统能在小RAM单片机上运行。相对于C/OS-II、embOS等商业操作系统,FreeRTOS操作系统是完全免费的操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行。
FreeRTOS是由Richard Barry在2003年由设计的,由于其设计的小巧简单,整个核心代码只有3到4个C文件。在设计之初就异军突起,累计开发者数百万,是目前市场占有率最高的RTOS,现在FreeRTOS已经支持三十多种芯片,基本包含市场上所有的微控制器。FreeRTOS在2018年被亚马逊收购,继续遵循GPLV2许可协议完全免费。 Richard Barry为了让代码容易阅读、移植和维护,大部分的代码都是以C语言编写,只有一些内核调度函数采用汇编编写。

  • 理论上支持无限多个优先级
  • 理论上支持无线多个任务
  • 支持抢占式调度(执行优先级最高的任务),时间片调度(定时切换任务)
  • 支持消息队列,二值信号量,计数信号量,递归信号量,互斥信号量,消息传递和消息同步
  • 静态可裁剪(根据FreeRTOSconfig.h文件)
    (2)常用功能介绍
  • 任务创建和删除
  • 信号量
  • 互斥量
  • 通知
  • 任务调度
  • 定时器
  • 内存管理
  • Tickless
    具体可参考:FreeRTOS API 详细介绍
    5、常见RTOS
    μC/OS—II/III,FreeRTOS,RT-thread,LiteOS(华为),Alios Things(阿里),TencentOS tiny(腾讯),Zephyr,VxWorks 等。
    目前由于物联网产业的崛起,各大厂商都在推出各自的RTOS软件方案,一般是内核+生态的方式,比如Amazon收购FreeRTOS后,正在基于Freertos构建自己的IOT生态圈,接入Amazon Cloud,提供ble、wifi、4G/5G的接入解决方案,提供HTTP、MQTT、OTA等的软件服务,国内的阿里、华为、腾讯都是如此,依托自已的云服务,打造“端-云”的生态系统,积极抢占物联网流量入口。
    FreeRTOS由于采取免费商用的策略,目前是市场占有率第一的RTOS。
    最近,以前一直采用商业收费方式的μC/OS,目前也开始免费商用,开始将旗下的FS、TCP-IP协议栈、USB Device/Host协议栈改为免费商用。

TencentOS tiny 架构图
MCU基础以及RTOS原理知识分享_第8张图片
附:uC/OS-III和FreeRTOS的区别

MCU基础以及RTOS原理知识分享_第9张图片

你可能感兴趣的:(嵌入式软件)