手把手教你丨小熊派移植華為 LiteOS-M
摘要:本文詳細講解如何移植 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 的支援,新版本暫時還沒有更新,所以這裡我使用老版本的程式碼,倉庫地址如下:
我們把老版本的倉庫 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 */
編譯下載程式,觀察現象: