当下FreeRTOS得到了Keil、STM32Cube MX等开发环境的大力支持,很大程度上无需再考虑移植等底层问题,简单设置后在代码中直接调用即可。
不得不说,这是激动人心的,RTOS的各项特性所带来的方便给予我们极大的诱惑,总觉得只要用好RTOS,我们能把单片机玩出各种花样,再也不用考虑什么全局变量、轮循顺序、执行时长等恼人的问题,只要设置好优先级、信号量和任务参数,剩下的就可以安心于用代码实现功能。
现实总是残酷帅毙的!Keil中一堆“……axf: Error: L6406E: No space in execution regions with .ANY selector matching……”错误,能轻易的将人从“安心于用代码实现功能”的美好幻想中拖到现实。
以Keil环境下,NuTiny-SDK-M051开发板为例,芯片是NuMicro M0516LDN,内核Cortex-M0,片上资源为主频50MHz、Flash 64KB、RAM 4KB,Flash空间地址为0x0000_0000~0x000_FFFF,RAM空间地址为0x2000_0000~0x2000_0FFF(养成查看映射地址的好习惯,IDE环境中常能用上)。
实际对比Keil环境中NONOS(不用RTOS)、freeRTOS、CMSIS-RTOS(Keil RTX)、CMSIS-RTOS2(Keil RTX5)几种方式下资源占用情况(在各RTOS种启动一个任务,该任务重复执行一条UART输出):
NONOS:
Program Size: Code=2672 RO-data=344 RW-data=76 ZI-data=812
freeRTOS:
Program Size: Code=7024 RO-data=344 RW-data=124 ZI-data=4948
CMSIS-RTOS(Keil RTX):
Program Size: Code=7268 RO-data=456 RW-data=68 ZI-data=2932
CMSIS-RTOS2(Keil RTX5):
Program Size: Code=6264 RO-data=560 RW-data=5128 ZI-data=608
//稍作解释:Code是代码占用的空间;RO-data是 Read Only 只读常量的大小,如const型;RW-data是(Read Write) 初始化了的可读写变量的大小;ZI-data是(Zero Initialize) 没有初始化的可读写变量的大小。ZI-data不会被算做代码里因为不会被初始化
//FLASH空间占用:(Code) + (RO Data) + (RW Data)
//RAM空间占用:( RW Dat) + (ZI Dat)
实际数值可以很容易的看出资源占用情况,当然我们也可以考虑通过对RTOS进行适当裁剪,来达到更小的FLASH和RAM空间占用——当然主要还是注重对RAM空间的占用,FLASH一般来说较为便宜且很容易外扩,不太容易先出现资源短缺的情况——但是很显然对于RAM 4KB的单片机而言,无论采用何种RTOS,片上资源总是吃紧,对于我们想要充分利用单片机外设资源的想法而言,调用RTOS难免导致kernel代码严重挤压功能代码的可用空间,得不偿失。
——————————————————————————————————————
(两、三个小时之后...)闲逛中,顺手点开了VSCode,在PlatformIO的强大威力下,对esp8266(NodeMCU 0.9)的esp8266-NONOS-SDK和esp8266-RTOS-SDK俩例程重新编译了一下,关于代码量得到如下结果:
NONOS:
DATA: [=== ] 33.2% (used 27194 bytes from 81920 bytes)
PROGRAM: [====== ] 60.0% (used 226009 bytes from 376832 bytes)
RTOS:
DATA: [==== ] 36.3% (used 29754 bytes from 81920 bytes)
PROGRAM: [======= ] 73.9% (used 278664 bytes from 376832 bytes)