APP下载

基于MSP432 的AliOS Things 操作系统移植

2021-11-26杨淇善韩德强

电子技术应用 2021年11期
关键词:堆栈源代码微控制器

杨淇善,韩德强

(北京工业大学 信息学部,北京 100124)

0 引言

物联网(Internet of Things,IoT)是一个通过信息技术将各种物体与网络相连,以帮助人们获取所需物体相关信息的巨大网络[1]。在这个网络中,存在数量巨大的各类嵌入式设备。这些设备在计算能力、可用内存、实时性、通信、功耗等诸多方面都有限制或要求[2]。通用操作系统对硬件系统的性能要求较高,物联网系统内的绝大多数嵌入式设备无法运行。传统的嵌入式操作系统具有内核小、实时性高等优点,适用于性能较低的嵌入式设备。但是,仅有一个轻量级内核并无法解决物联网应用中繁多的通信协议、硬件接口等造成的“碎片化”问题。因此,致力于解决“碎片化”问题、并具有终端安全保障和统一管理技术支撑的物联网操作系统应运而生。

AliOS Things 是面向物联网领域的轻量级物联网操作系统,包含物联网领域需用的组件和接口,具备极致性能、极简开发、云端一体、安全防护等特点,可广泛应用于智能家居、智慧城市、新出行等物联网领域[3]。

TI 公司的MSP432 系列微控制器采用了ARM Cortex-M4F 内核,具有浮点运算单元(Float Point Unit,FPU)和存储器保护单元。MSP432P401R 作为该系列的其中一款产品,内置256 KB 的Flash 和64 KB 的SRAM,最大工作频率48 MHz,工作功耗和待机功耗分别仅为80 μA/MHz 和660 nA。此外,还集成了多个SPI、UART 和I2C 接口,以及密码编译加速器等模块[4]。因此,高性能的特点可充分发挥AliOS Things 操作系统的优势,超低功耗的特点使其可广泛应用于物联网感知层的设备上。两者的结合在物联网领域中具有良好的应用价值。

1 AliOS Things 系统架构

AliOS Things 物联网操作系统除了提供轻量级的内核以外,还具有网络通信与组网、安全加密、物联网中间件等多种功能与服务组件,其层次架构和组件结构如图1所示。

图1 AliOS Things 操作系统架构图

1.1 BSP

BSP(Board Support Package,板级支持包)是介于硬件平台与操作系统之间的一层,封装了访问和使用硬件资源的功能函数。对于微控制器而言,可参考芯片数据手册开发或使用厂商提供的函数库实现。对于硬件平台中的其他外设,则根据实际使用的通信接口和控制方式进行函数封装。

1.2 HAL

HAL(Hardware Abstraction Layer,硬件适配层)屏蔽了硬件平台,使其上层代码不直接访问硬件资源且在不改变功能的情况下可移植到其他平台中,增强了代码的稳定性与移植性。实现该层的函数可根据实际的功能需求调用BSP 中的函数。

1.3 Kernel

内核层是AliOS Things 的核心部分,包含Rhino 实时操作系统内核以及异步事件框架Yloop、VFS(Virtual File System,虚拟文件系统)等功能组件。其中,Rhino 内核是整个操作系统的基础部分,提供任务调度、内存分配、时间管理和中断控制等一系列功能。移植工作的基本任务即实现操作系统内核在目标平台上正常运行。

1.4 Protocol Stack

协议栈提供了物联网设备连接网络或组网的多种协议。对于面向IP 的设备,AliOS Things 集成了基于LwIP 的TCP/IP 协议栈以及提供标准Socket 功能的SAL(Socket Abstraction Layer,套接字抽象层)。对于非IP设备,集成了BLE(Bluetooth Low Energy,低功耗蓝牙)协议和LoRa 协议。同时,协议栈中还包含可支持不同物联网设备自组织异构网络的uMesh 技术。

1.5 Security

安全组件中集成了TLS(Transport Layer Security,安全传输层协议)和TEE(Trusted Execution Environment,可信执行环境),并支持ID2(Internet Device ID,联网设备身份标识)认证与相关密钥管理的功能。

1.6 AOS API

该部分可称为操作系统应用程序编程接口层,针对系统内核以及协议组件进行了封装,将应用层与内核层进行了隔离。上层应用使用操作系统时,仅需调用AOS API 的接口函数即可,内核代码对其完全透明。因此,只要不改变AOS API 的接口,修改内核代码或更换协议组件均不影响应用层,提高了系统的可迭代性和维护性。

1.7 中间件

AliOS Things 具有诸多物联网系统可用的中间组件,更好地为整个应用系统提供可靠、便捷的服务。主要包括FOTA(Firmware Over-The-Air,无线固件升级)、uData框架、AT 命令解析和常用的物联网云端连接协议MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)、CoAP(Constrained Application Protocol,受限型应用协议)等。

2 AliOS Things 移植方法和过程

本文的AliOS Things 移植工作主要涉及系统架构中的以下六个部分:与微控制器架构相关的接口文件、板级支持包、硬件适配层、内核层、AOS API 和SysTick 定时器中断处理函数。

2.1 接口文件

AliOS Things 的源代码中提供了多种主流微控制器体系架构相关的移植接口文件,以供开发者参考或使用。适用于MSP432P401R 的Cortex-M4F 内核和IAR for ARM开发环境的相关文件存储于源代码目录platformarcharmarmv7miccarmm4 中,其包含4 个文件:k_types.h、port.h、port_c.c 和port_s.S。

k_types.h 对堆栈溢出控制的幻数值、强制内联关键字进行了宏定义。另外,根据微控制器内核的位数,重新定义操作系统中所需用的堆栈、定时器、信号量、互斥量和上下文切换量等数据类型。重新定义上述数据类型时,应使用C99 标准的头文件stdint.h 中所定义的数据类型,避免直接使用C 语言中char、int 等基本数据类型,以提高代码的可移植性。以sem_count_t 和ctx_switch_t 为例:

typedef uint32_t sem_count_t;

typedef uint64_t ctx_switch_t;

port.h 对任务处理中有关寄存器操作的函数进行了宏定义或声明,这些函数均在port_c.c 和port_s.S 两个文件中实现。

port_c.c 使用C 语言实现了任务堆栈初始化函数cpu_task_stack_init()。该函数的编写应遵循微控制器内核的相关特性。Cortex-M4F 内核的堆栈增长方式为高地址向低地址递减。此外,当系统产生中断时,寄存器R0-R3、R12、LR(链接寄存器)、PSR(程序状态寄存器)、S0-S15 和FPSCR(浮点数状态控制寄存器)均由硬件控制保存与恢复,而寄存器R4-R11 以及S16-S31 则需要由软件控制保存与恢复。因此,函数cpu_task_stack_init()在完成栈指针变量stk 的初始化之后,可按照以下顺序完成整个任务堆栈的构建。

(1)PSR 的值置为0x01000000,使能Thumb 指令集。

*(--stk)=(cpu_stack_t)0x01000000L;

(2)PC(程序计数器)的值置为任务函数的入口地址。

*(--stk)=(cpu_stack_t)entry;

(3)LR 的值置为krhino_task_deathbed()函数指针,该函数用于删除当前意外跳出的任务。

*(--stk)=(cpu_stack_t)krhino_task_deathbed;

(4)依次入栈R12、R3-R1 的初值,其数值可根据寄存器编号确定,以便于检查堆栈初始化是否正确。

*(--stk)=(cpu_stack_t)0x12121212L;

*(--stk)=(cpu_stack_t)0x03030303L;

*(--stk)=(cpu_stack_t)0x02020202L;

*(--stk)=(cpu_stack_t)0x01010101L;

(5)R0 的值置为任务函数传入参数。

*(--stk)=(cpu_stack_t)arg;

(6)若使用FPU,则依次入栈寄存器S31-S16 的初值,其数值与上述通用寄存器类似。

*(--stk)=(cpu_stack_t)0x31uL;

*(--stk)=(cpu_stack_t)0x30uL;

……

*(--stk)=(cpu_stack_t)0x16uL;

(7)EXC_RETURN 的值置为0xFFFFFFFD。

*(--stk)=(cpu_stack_t)0xFFFFFFFDL;

(8)依次入栈R11-R4 的初值,其数值与上述通用寄存器一致。

*(--stk)=(cpu_stack_t)0x11111111L;

*(--stk)=(cpu_stack_t)0x10101010L;

……

*(--stk)=(cpu_stack_t)0x04040404L;

除任务堆栈初始化函数以外,port.h 中声明的其他函数使用汇编语言在port_s.S 中实现。cpu_intrpt_save()和cpu_intrpt_restore()负责CPSR(程序状态寄存器)状态的保存和恢复,以及中断的禁止和使能。这两个函数在临界区代码前、后被调用。

另外,还应实现涉及上下文切换功能的部分函数。在任务切换时,需调用cpu_task_switch()。在中断结束时,需调用cpu_intrpt_switch()。任务切换和中断结束并非同一种情况,但两者均可利用触发PendSV 异常处理的方式完成相应的功能。因此,可采用相同的方法处理。

LDR R0,=SCB_ICSR

LDR R1,=ICSR_PENDSVSET

STR R1,[R0]

BX LR

cpu_first_task_start()则用于多任务系统的初始化阶段,由优先级最高的就绪任务开始执行。首先,该函数将PendSV 优先级设为14 级(PRI_14),Systick 优先级设为15 级(PRI_15)。

LDR R0,=SHPR3_PRI_14

LDR R1,=PRI_LVL_PENDSV

STRB R1,[R0]

LDR R0,=SHPR3_PRI_15

LDR R1,=PRI_LVL_SYSTICK

STRB R1,[R0]

随后,PSP(进程堆栈指针)赋值为0,以8 字节对齐MSP(主堆栈指针)。

MOVS R0,#0

MSR PSP,R0

MRS R0,MSP

LSRS R0,R0,#3

LSLS R0,R0,#3

MSR MSP,R0

最后,触发PendSV 异常并开启中断。

LDR R0,=SCB_ICSR

LDR R1,=ICSR_PENDSVSET

STR R1,[R0]

CPSIE I

B .

PendSV 异常处理函数PendSV_Handler()也在port_s.S中实现。通过PSP 是否为0 可判断触发该异常处理的函数。

MRS R0,PSP

CBZ R0,_pendsv_handler_nosave

若由cpu_task_switch()和cpu_intrpt_switch()触发,则保存通用寄存器的值,并将状态寄存器赋值给对应的任务模块。反之,若由cpu_first_task_start()触发异常,则跳过上述过程,直接从代码段_pendsv_handler_nosave 继续执行。然后,比较任务的优先级并执行当前最高级就绪的任务。

2.2 板级支持包

对于移植工作,BSP 需要对时钟、中断、SysTick、GPIO等功能实现支持。MSP432P401R 片内32 KB ROM 内集成了TI 官方的MSP432 外设驱动程序库,仅需将相关头文件加入相关源文件中即可。库函数均以ROM_ 作为前缀,以全局中断使能函数为例:

ROM_Interrupt_enableMaster();

2.3 硬件适配层

AliOS Things 的源代码中提供了HAL 函数声明的参考,相关文件存储于源代码目录includehalsoc 中。移植工作根据实际情况,重新声明并实现HAL 的函数。相关函数均以HAL_ 作为前缀,以SysTick 初始化和系统初始化两个函数为例:

2.4 内核层

开发者不应更改Rhino 内核的源代码,即以krhino_为前缀的函数,避免出现不可预知的错误。但是,需要根据实际硬件平台和系统需求,利用诸多宏定义配置和剪裁操作系统内核功能。AliOS Things 源代码中的头文件k_default_config.h 给出了用于配置和剪裁内核功能的相关宏定义的默认值,该文件存储于源代码目录kernel hinocoreinclude 中。该文件中对微控制器内核相关的特性进行了配置,默认采用小端模式,由高地址向低地址增长的堆栈方向等。

#define RHINO_CONFIG_LITTLE_ENDIAN 1

#define RHINO_CONFIG_CPU_STACK_DOWN 1

除此之外,该文件中的几十个宏定义还配置了操作系统的时标频率、信号量、消息队列、互斥量等功能特性,以及动态内存分配、中断堆栈检查、钩子函数等系统功能的默认值。

若修改这些宏定义的值,应在同目录下创建一个名为k_config.h 的头文件,而非直接修改k_default_config.h,以保持代码的可移植性和正确性。由于k_default_config.h中采用了#ifndef…#define…预编译,则k_config.h 中仅对要修改的默认值重新定义即可。

2.5 AOS API

AliOS Things 源代码中提供了AOS API 函数声明的参考,该层函数以aos_ 作为前缀,相关头文件存储于源代码目录includeaos 中。开发者不必逐一实现所有头文件中声明的函数,根据系统情况实现所需函数即可。本文的移植工作主要利用Rhino 内核相应的函数完成本层函数的实现,以aos_init()和aos_task_new_ext()两个函数为例:

2.6 SysTick 定时器中断处理函数

SysTick 定时器为操作系统提供了“心跳”功能,即操作系统调度所需要的最小基本定时单元。根据不同的任务调度策略,当SysTick 中断触发时,操作系统会采取相应的措施进行多任务的切换。Rhino 内核中提供了平台无关的入口函数krhino_tick_proc(),以供SysTick 中断处理函数调用。在执行过程中,krhino_tick_proc()应受临界段代码保护。

3 测试

移植工作基于MSP-EXP432P401R LaunchPad 开发平台实现,其具有两个LED 可供测试工作使用,提供直观的视觉指示。同时,该平台自带XDS110 板载调试器,可通过USB 接口直接与上位机相连,实现程序的下载和调试功能。软件开发环境采用了IAR Embedded Workbench for ARM 8.22,通过配置相关参数即可支持MSP432P401R 和XDS110 的开发和调试,如图2 所示。

图2 IAR 开发环境配置

测试程序中,通过查看多个任务的运行结果,以确定操作系统移植后能否正常运行。首先,调用HAL 和AOS API 的初始化函数,分别对硬件资源和操作系统内核进行初始化。然后,创建两个测试任务LED1_Blink_Task和LED2_Blink_Task。其中,LED2_Blink_Task 的优先级高于LED1_Blink_Task。最后,调用aos_start()函数启动操作系统内核,使系统进入运行状态。主函数流程图如图3所示。

图3 测试程序主函数流程图

两个测试任务分别使开发平台的LED1和LED2以300ms和2000ms的周期翻转。以LED1_Blink_Task 为例:

HAL_LED1_Toggle();

aos_msleep(300);

此外,测试程序中设置了全局数组gSysTime[],通过调用aos_now_ms()函数在该数组中记录每次任务开始执行的时间点。在LED1_Blink_Task 中,gSysTime[]直接记录aos_now_ms()函数返回的时间值。

gSysTime[gArrayCount++]=aos_now_ms();

而在LED2_Blink_Task 中,将aos_now_ms()函数的返回值加1 后存入gSysTime[]中。

gSysTime[gArrayCount++]=aos_now_ms()+1;

由于两个任务的执行周期均为100 ms 的整数倍,则某个时间点上两个任务同时就绪并相继执行时,以此可区分数组中时间值的来源。

测试程序运行后,可看到开发平台的LED1 和LED2各自按照一定的周期闪烁。同时,通过IAR 开发环境中的Watch 窗口,查看测试程序运行一段时间后数组gSys-Time[]的状态,结果如图4 所示。

由gSysTime[0]=1 和gSysTime[1]=0 可知,系统启动后,即系统时间0 ms 时,两个任务均处于就绪状态并先执行了优先级更高的LED2_Blink_Task。此后的2 000 ms内,gSysTime[2]至gSysTime[7]的数值表明LED1_Blink_Task以300 ms 的周期正确执行。图4 中的gSysTime[8]、gSys-Time[16]和gSysTime[23] 的数值表明LED2_Blink_Task 以2 000 ms 的周期正确执行。此外,在系统时间6 000 ms 时,两个任务再次同时就绪,gSysTime[23]=6001 和gSysTime[24]=6000 表明操作系统以优先级执行了两个任务。

图4 数组gSysTime 的测试结果

综上所述,完成AliOS Things 操作系统移植后,多个任务能够正确地创建、运行和切换。

4 结论

物联网操作系统起源于TinyOS 和Contiki 项目,它们对IoT 系统的发展产生了深远的影响[5]。本文给出了AliOS Things 操作系统移植至MSP432 微控制器的方法,以操作系统架构中由底层至顶层的顺序详细描述了各层中需要完成的工作。通过相关测试,AliOS Things 能够正常、稳定地运行在MSP432 微控制器上,验证了移植方法的正确性,对于其他平台具有借鉴意义和参考价值。

猜你喜欢

堆栈源代码微控制器
基于行为监测的嵌入式操作系统堆栈溢出测试*
基于TXL的源代码插桩技术研究
软件源代码非公知性司法鉴定方法探析
物联网技术在微控制器实验教学中的应用
基于语法和语义结合的源代码精确搜索方法
基于堆栈自编码降维的武器装备体系效能预测
揭秘龙湖产品“源代码”
Atmel针对新一代物联网应用发布全新32位微控制器
最新STM32设计工具增加对混合信号微控制器的支持
意法半导体(ST)推出世界首款基于ARM Cortex-M7的STM32 F7系列微控制器