1、LiteOS 简介
Huawei LiteOS 是华为轻量级物联网操作系统,其体系架构如下图所示:
Huawei LiteOS由Huawei LiteOS kernel、互联互通中间件、开放API以及安全组成:
1)Huawei LiteOS Kernel为Huawei LiteOS基础内核,属于最精简RTOS。
包括任务管理、内存管理、时间管理、通信机制、中断管理、队列管理、事件管理、定时器、异常管理等操作系统基础组件,可以单独运行;
2)Huawei LiteOS互联互通中间件,可覆盖短距(Wifi、 BT等)/广域(4G/NB-IoT)协议,可解决不同协议架构间互联互通、互操作问题;
3)Huawei LiteOS提供面向不同IoT领域的业务Profile,并以开放API的方式提供给第三方开发者;
4)Huawei LiteOS构建完备的设备侧安全、轻量级E2E传输安全能力。
1.1、LiteOS 特性
1.2、移植环境
开发板:
可选STM32F103、 STM32F4、 STM32F7全系列芯片。
仿真器:
J-Link V9 或者ST-Link
软件环境:
主流的ARM cortex M系列微控制器集成开发环境主要有MDK、 IAR;
由于华为开发者社区已经提供IAR版本的Huawei LiteOS源码,集成开发环境为MDK5.21 ,在 MDK5 安装完成后,要让 MDK5 支持 STM32F103 的开发,还要安装 STM32F103的器件支持包: Keil.STM32F1xx_DFP.2.1.0.pack(STM32F1 系列的器件包)。
下载地址: STM32 器件包
2、源码目录结构介绍
LiteOS 下载地址:
LiteOS
新建工程目录:
在电脑上新建一个目录,这里命名为Huawei LiteOS_STM32_DEMO,将STM32的LED灯例程的文件全部拷贝到该目录下,并将Huawei LiteOSKernel源码文件夹Huawei_LiteOS也拷贝到该目录下,删除Listing、 Output两个文件夹,并将Project文件夹目录下面的文件全部删除。
源码中共有 6 个目录,移植需要使用到的代码在下面用红色标记:
/arch/arm/arm-m M核中断、调度、tick相关代码
/common arm核公用的cmsis core接口(这个可以在keil直接设置)
/components/cmsis LiteOS提供的cmsis os接口实现
/connectivity/agent_tiny agent_tiny端云互通组件
/lwm2m lwm2m协议实现
/net/lwip_port lwip驱动及OS适配代码
/lwip-2.0.3 lwip协议实现
/security/mbedtls/mbedtls_port MBEDTLS的OS适配代码
/mbedtl-2.6.0 MBEDTLS协议实现
/doc 此目录存放的是LiteOS的使用文档和API说明等文档
/examples 供开发者测试LiteOS内核的demo示例,此目录存放的是内核功能测试用的相关用例的代码
/kernel/base/core LiteOS基础内核代码,包括队列、task调度、软timer、时间片计算等功能
/om 与错误处理相关的文件
/include LiteOS内核内部使用的头文件
/ipc LiteOS中task间通讯的相关接口,包括事件、信号量、消息队列、互斥锁等
/mem LiteOS中的内核内存管理的相关代码
/misc 内存对齐功能以及毫秒级休眠sleep功能
/extended/tickless 低功耗框架代码
/include LiteOS开源内核头文件
/targets 不同内核的板端工程代码(含原厂芯片驱动)
由于这里移植的是stm32f1,系统中需要使用到配置文件,在移植时需要复制以下目录中的三个头文件:
/targets/STM32F103RB_NUCLEO/OS_CONFIG/(los_builddef.h, los_printf.h, target_config.h)
/targets/STM32F103RB_NUCLEO也将作为的例程工程进行移植的参考和学习。
3、建立工程
工程可分为三个文件夹 Libraries、Project 和 User。
Libraries 存放的是 stm32 的标准库文件,包括源文件和头文件。
Project存放的是工程相关的文件;
User文件夹下包括了main.c,自己写的bsp,以及移植系统需要用到的源码文件。
若使用到stm32的库函数,则需要添加"stm32f10x_conf.h"这一头文件,并在工程中定义宏“USE_STDPERIPH_DRIVER”和"STM32F10X_HD"。
4、修改启动文件和 .sct 文件
移植中的启动文件和.sct文件对比源码的例程工程并没有进行大幅度的修改简化,保证程序运行的稳定性。
但是这两个文件相比较于裸机工程修改的幅度还是很大的,.sct文件添加了若干个加载域进行分散加载,启动文件也进行了大规模的修改。
在例程工程中的启动文件中,与裸机的启动文件不同,使用符号"Image$ $ARM_LIB_STACKHEAP$ $Base",合并的堆栈/堆区的方法,对堆栈进行划分,从而产生了LOS_HEAP_ADDR_END和LOS_HEAP_ADDR_START两个地址变量。
而原来的启动文件是将堆栈分开进行设置的。
另外,例程工程中的启动文件将中断向量表省略,改成了"boot向量表",缩减了很多,只存有堆栈和Reset_Handler,而将其他的中断向量成员的定义工作完成在"los_hwi.c"文件中,因此.sct也随之变动。
启动文件的代码如下:
Heap_Size EQU 0x00000400
AREA LOS_HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
AREA LOS_HEAP_INFO, DATA, READONLY, ALIGN=2
IMPORT |Image$$ARM_LIB_STACKHEAP$$ZI$$Base|
EXPORT __LOS_HEAP_ADDR_START__
EXPORT __LOS_HEAP_ADDR_END__
__LOS_HEAP_ADDR_START__
DCD __heap_base
__LOS_HEAP_ADDR_END__
DCD |Image$$ARM_LIB_STACKHEAP$$ZI$$Base| - 1
PRESERVE8
THUMB
AREA RESET, CODE, READONLY
IMPORT ||Image$$ARM_LIB_STACKHEAP$$ZI$$Limit||
IMPORT osPendSV
EXPORT _BootVectors
EXPORT Reset_Handler
_BootVectors DCD ||Image$$ARM_LIB_STACKHEAP$$ZI$$Limit|| ; Top of Stack
DCD Reset_Handler ; Reset Handler
; Reset handler
Reset_Handler
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ALIGN
END
.sct文件对应启动文件的改变主要增加了两个加载域:VECTOR和ARM_LIB_STACKHEAP
.sct文件代码如下(地址对应自己的芯片做了修改):
LR_IROM1 0x08000000 0x00080000 { ; load region size_region
ER_IROM1 0x08000000 0x00080000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
* (LOS_HEAP_INFO)
}
VECTOR 0x20000000 0x400 { ; Vector
* (.data.vector)
}
RW_IRAM1 0x20000400 0x0000F800 { ; RW data
* (.data, .bss)
* (LOS_HEAP)
}
ARM_LIB_STACKHEAP 0x2000FC00 EMPTY 0x400 { ;LiteOS MSP
}
}
5、配置参数和任务
在 los_config.h 中修改相应参数:
常用参数如下,这里示例采用的是STM32F103芯片,因此将OS_SYS_CLOCK设为系统主频72Mhz。
#DEFINE OS_SYS_CLOCK 72000000
#DEFINE LOSCFG_BASE_CORE_TSK_LIMIT 15
#DEFINE OS_SYS_MEM_SIZE 0X00008000
#DEFINE LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE SIZE(0X2D0)
#DEFINE LOSCFG_BASE_CORE_SWTMR_LIMIT 16
内核代码移植完毕后,main()函数就可以跑起来了。贴出用来测试的main()函数的代码及相应的解释:
int main(void)
{
UINT32 uwRet = LOS_OK;
LED_Init(); //硬件驱动初始化
uwRet = LOS_KernelInit(); //OS内核初始化
if (uwRet != LOS_OK)
{
return LOS_NOK;
}
uwRet = create_task1(); //创建任务
if (uwRet != LOS_OK)
{
return LOS_NOK;
}
LOS_Start(); //启动OS
}
其中,create_task1()如下所示,主要是填满TSK_INIT_PARAM_S类型结构体,调用LOS_TaskCreate函数进行创建:
UINT32 create_task1(void)
{
UINT32 uwRet = LOS_OK;
TSK_INIT_PARAM_S task_init_param;
task_init_param.usTaskPrio = 1;//任务优先级
task_init_param.pcName = "task1";//任务名
task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)task1;//指定任务入口函数
task_init_param.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//设置任务堆栈大小
uwRet = LOS_TaskCreate(&g_TestTskHandle,&task_init_param);//调用任务创建函数
if(uwRet !=LOS_OK)
{
return uwRet;
}
return uwRet;
}
task1主要做的工作是指示灯的状态切换:
VOID task1(void)
{
UINT32 uwRet = LOS_OK;
while(1)
{
macLED1_TOGGLE();
uwRet = LOS_TaskDelay(1000);//操作系统延时
if(uwRet !=LOS_OK)
return;
}
}
refer:
https://blog.csdn.net/sinat_27066063/article/details/84320579