手把手教你丨小熊派移植华为 LiteOS-M

x33g5p2x  于2022-02-07 转载在 其他  
字(4.1k)|赞(0)|评价(0)|浏览(508)

摘要:本文详细讲解如何移植 LiteOS 到小熊派。

本文分享自华为云社区《小熊派移植华为 LiteOS-M(基于MDK)》,作者: JeckXu666。

前言

之前使用小熊派实现了鸿蒙动画的开机界面,具体使用的技术栈为 STM32 + LiteOS + LVGL + FATFS +DMA 方式实现,刷新效率非常高,预览视频如下:

关于这个的实现过程我会写一系列的教程分享出来,主要分为下面几个部分,本节为第一部分,移植 LiteOS 到小熊派上

  • [x] 小熊派移植华为 LiteOS-M(基于MDK):链接
  • [ ] 小熊派基于 LiteOS 移植 LVGL 显示接口:链接;
  • [ ] 小熊派基于 LiteOS 移植 LVGL 文件系统:链接;
  • [ ] 小熊派实现鸿蒙开机界面(LiteOS+LVGL):链接;

一、软硬件介绍

1.1 小熊派开发板

开发板外貌:

小熊派参数如下:

1.2 LiteOS介绍

LiteOS 是华为面向物联网领域开发的一个基于实时内核的轻量级操作系统。属于华为物联网操作系统 Huawei LiteOS 源码,鸿蒙体系的内核之一,本质上就是一个 RTOS,现有基础内核支持任务管理、内存管理、时间管理、通信机制、中断管理、队列管理、事件管理、定时器等操作系统基础组件,更好地支持低功耗场景,支持tickless机制,支持定时器对齐

同时 LiteOS 提供端云协同能力,集成了 LwM2M、CoAP、mbedtls、LwIP 全套 IoT 互联协议栈,且在 LwM2M 的基础上,提供了 AgentTiny 模块,用户只需关注自身的应用,而不必关注 LwM2M 实现细节,直接使用 AgentTiny 封装的接口即可简单快速实现与云平台安全可靠的连接

1.3 移植前言

LiteOS 软件开发框架按照下面的框架来进行,其中 LiteOS调度内核我们移植官方提供的代码即可,而 BSP 外设软件库我们则通过 STM32CubeMX 来配置生成 HAL 库,当这两方面准备好之后,我们只需要在任务层进行开发即可,开发效率极高

LiteOS 的移植一般也分为两种移植方法,一种移植的时候将芯片的中断也关联到 LiteOS 方便调用,另外一种则不关联中断,使用单片机自己的中断管理,这里 STM32 的 NVIC 中断管理很棒,我们不需要接管中断

二、CubeMX 配置

我们通过 STM32CubeMX 来配置小熊派的一些基本接口,比如配置时钟树,开启 SystemTick定时器,方便移植 LiteOS

配置时钟树:

设置 HAL库定时器为TIM1,防止和 LiteOS 使用的 Systemtick 冲突

配置 LED 的 GPIO 口,方便我们点灯操作

配置工程名称,选择生成 MDK

配置代码生成选项

生成代码

代码生成后打开工程,下一步进入移植操作

三、获取源码

LiteOS 的老版本有对 MDK 的支持,新版本暂时还没有更新,所以这里我使用老版本的代码,仓库地址如下:

Github 仓库

我们把老版本的仓库 Down 到本地,Git 指令如下:

git clone -b develop https://github.com/LiteOS/LiteOS.git

代码拉取后如下:

没有 Git 工具的话可以上 GitHub 网页把 ZIP Downloade 下来再解压也可以

下面就是代码移植阶段

四、源码移植

在 MDK 工程目录下新建 LiteOS 移植目录,按如下新建文件夹

这几个文件夹的作用如下:

  • ARCH:编译器启动文件
  • CMSIS:存放 CMSIS-RTOS 接口文件
  • Config:存放内核配置文件,用于配置和裁剪内核
  • Kernel:存放 LiteOS 内核源码

下面我们从源码文件夹拷贝代码到移植目录下面

4.1 ARCH

移植 文件路径\LiteOS\arch\arm 架构文件夹到 ARCH 下,arm 下文件包含了各个 arm 架构的支持文件

M 架构下面的文件主要有三个 GCC、IAR、KEIL 三个,适配不同集成开发环境的编译器,因为小熊派是 M4 内核,所以我们主要关注的就是 cortex-m4 下面的 keil 文件夹下的启动文件,这里我把所有的都复制进去了

至于 include 和 src 文件夹,则是存放了 LiteOS 的一些内核接口代码,比如中断接口、Systemtick 定时器接口函数等等

4.2 CMSIS

移植 文件路径\LiteOS\LiteOS-M-Develop\LiteOS\osdepends\liteos\cmsis CMSIS 系统接口文件夹到 CMSIS 下,CMSIS 文件夹下存放的是 CMSIS-RTOS 接口文件夹,RTOS内核支持的操作就那么些,CMSIS-RTOS 对这些操作提供了统一的 RTOS 接口,连接系统底层与 RTOS层,方便我们移植不同的 RTOS:

4.3 Config

Config 文件夹下存放系统的配置文件,这个配置文件我们从示例工程下面拷过来,示例工程目录位置 目录\LiteOS\targets\STM32F103VET6_NB_GCC\OS_CONFIG,目录下文件如下:

其中 los_builddef.h 用于设置构建的定义,los_printf.h 用于设置串口打印配置,target_config.h 可以用于裁剪系统内核,设置系统运行参数等等

4.4 Kernel

kernel 文件夹用于存放内核源码,源码位置在 目录\LiteOS\kernel 下面

base 是系统的基础内核源码

  • core 是核心源码,包括队列、task调度、软timer、时间片计算等功能,全部复制
  • OM 是与错误处理相关的文件,全部复制
  • include 是 LiteOS内 核内部使用的头文件,全部复制
  • ipc 是 LiteOS 中 task 间通讯的相关接口,包括事件、信号量、消息队列、互斥锁等,全部复制
  • mem 是LiteOS中的内核内存管理的相关代码,我们只需要复制其中一部分就行,内存分配方式选择适合小内存的分配方式(bestfit_little)

  • misc 是内存对齐功能以及毫秒级休眠sleep功能,全部复制

extended 是系统扩展内核的代码,目前里面有个支持低功耗的内核,我们顺便也复制进去

include 存放内核的调用头文件,我们全部复制进去

kernel 下面还有一个 los_init.c 文件,存放初始化代码,也复制进去

复制完成的文件夹如下:

五、MDK 配置

代码移植完成了,下面就是配置一下 MDK

5.1 文件导入

进入 MDK 进行文件管理,配置文件夹,导入文件:

  • config 导入 Config 下面 所有 .h 文件
  • kernel 导入 Kernel 下面 所有 .c 文件
  • cmsis 导入 CMSIS 下 cmsis_liteos.c 文件
  • arch 导入 ARCH\arm\arm-m\cortex-m4\keil 下 los_dispatch_keil.S文件,以及 ARCH\arm\arm-m\src 下 所有 .c 文件

5.2 路径导入

文件导入后下一步就是路径导入,在 C/C++ 配置中依次添加头文件路径

添加的路径如下,这里我的工程目录是 BearPi_LiteOS:

BearPi_LiteOS\Middlewares\LiteOS\Config
BearPi_LiteOS\Middlewares\LiteOS\Kernel\base\include
BearPi_LiteOS\Middlewares\LiteOS\Kernel\extended\include
BearPi_LiteOS\Middlewares\LiteOS\Kernel\include
BearPi_LiteOS\Middlewares\LiteOS\ARCH\arm\arm-m\include
BearPi_LiteOS\Middlewares\LiteOS\CMSIS\cmsis

到这基本差不多了,下面就是编译工程

5.3 编译工程

先编译一下工程,发现报错,缺少 #include “stm32f1xx.h” 文件,是因为我的小熊派开发板是 stm32l431 的芯片,修改这个工程头文件为 #include "stm32l4xx.h"

修改完再编译,当然还会有报错,因为 STM32CubeMX 生成的代码里面有

void PendSV_Handler(void)
void SysTick_Handler(void)

两个中断,这两个中断在 LiteOS 的内核源码里面有定义,一个用作系统时钟,一个用作上下文切换,所以我们要把 STM32CubeMX 生成的这部分中断处理代码注释掉

注释完后编译,编译通过:

到此系统移植基本完成了,下一步写个代码测试系统有没有移植成功

六、点灯实验

头文件包含 cmsis 接口

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "cmsis_os.h"
/* USER CODE END Includes */

创建一个任务句柄,以及任务实体和初始化函数

osThreadId_t led_taskHandle;
const osThreadAttr_t led_task_attributes = {
  .name = "led_task",
  .stack_size = 512 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};
void Led_Task(void *argument);

void Led_Task(void *argument)
{
	while(1)
	{
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
		osDelay(1000);
	}
}

在系统初始化的代码添加系统初始化代码,同时创建任务,创建完成后启动系统

/* USER CODE BEGIN 2 */
	osKernelInitialize();
  /* creation of uart_task */
  led_taskHandle = osThreadNew(Led_Task, NULL, &led_task_attributes);
	osKernelStart();
  /* USER CODE END 2 */

编译下载程序,观察现象:

点击关注,第一时间了解华为云新鲜技术~

相关文章