赞
踩
随着 OpenHarmony3.1 的正式发布,其功能也在不断完善。OpenHarmony LiteOS-M 内核是面向IoT领域构建的轻量级物联网操作系统内核,具有小体积、低功耗、高性能的特点,其代码结构简单,主要包括内核最小功能集、内核抽象层、可选组件以及工程目录等,分为硬件相关层以及硬件无关层,硬件相关层提供统一的HAL(Hardware Abstraction Layer)接口,提升硬件易适配性,不同编译工具链和芯片架构的组合分类,满足AIoT类型丰富的硬件和编译工具链的拓展。本文主要介绍如何在STM32上移植 OpenHarmony LiteOS-M 内核,及其注意事项。
硬件:
- STM32F429I-DISC1 开发板
软件:
- VSCode:用于编辑代码
- STM32CubeMX:用于生成工程
- make、arm-none-eabi-gcc:用于编译工程
- STM32Cubeprogrammer:用于下载工程
- Git:用于获取 OpenHarmony LiteOS-M 内核源码
/target
目录下生成工程。printf
。添加用户自定义任务。https://gitee.com/openharmony/kernel_liteos_m
,获取Git仓库地址。https://gitee.com/openharmony/kernel_liteos_m.git
/third_party
目录,用于存放第三方依赖文件(STM32 所需的 CMSIS 等),拉取第三方依赖文件。cd kernel_liteos_m
mkdir ./third_party
cd third_party
git clone https://gitee.com/openharmony/third_party_bounds_checking_function.git ./bounds_checking_function
git clone https://gitee.com/openharmony/third_party_cmsis.git ./cmsis
git clone https://gitee.com/openharmony/third_party_musl.git ./musl
到这里 OpenHarmony LiteOS-M 内核源码就获取完毕了。
进入/targets
目录,使用 STM32CubeMX 生成工程 STM32F429ZI_Harmony_LiteOS_M
与FreeRTOS类似,由于LiteOS会占用SysTick定时器,因此需要修改HAL库延时的基础时钟,改为其他非SysTick的定时器,避免HAL库延时的定时器和系统运行的定时器冲突。
配置:下载调试端口SW、串口USART、LED_GPIO、时钟树。
开发环境选择 Makefile
Code Generator
中一定要选择 Copy only necessary library files
! 如果选择所有库文件都添加的话,那么就会生成很多模板文件。由于我们需要在 Makefile 中添加文件,如果目录中有模板文件的话,我们就无法直接使用筛选功能将所有源文件快速添加到工程中了。
至此工程配置已结束,点击 Generate 即可生成工程。
targets
下的工程目录,新建liteos_file_path.mk
用于将内核源码文件添加到工程Makefile中,该文件相当于C语言中的头文件,主 Makefile 文件可以直接包含该文件。liteos_file_path.mk
中。# Topdir 顶层目录 LITEOSTOPDIR := ../../ LITEOSTOPDIR := $(realpath $(LITEOSTOPDIR)) # Common 内核源文件及头文件目录 C_SOURCES += \ $(wildcard $(LITEOSTOPDIR)/kernel/src/*.c) \ $(wildcard $(LITEOSTOPDIR)/kernel/src/mm/*.c) \ $(wildcard $(LITEOSTOPDIR)/components/cpup/*.c) \ $(wildcard $(LITEOSTOPDIR)/components/power/*.c) \ $(wildcard $(LITEOSTOPDIR)/components/backtrace/*.c) \ $(wildcard $(LITEOSTOPDIR)/components/exchook/*.c) \ $(wildcard $(LITEOSTOPDIR)/components/signal/*.c) \ $(wildcard $(LITEOSTOPDIR)/utils/*.c) C_INCLUDES += \ -I$(LITEOSTOPDIR)/utils \ -I$(LITEOSTOPDIR)/kernel/include \ -I$(LITEOSTOPDIR)/components/cpup \ -I$(LITEOSTOPDIR)/components/power \ -I$(LITEOSTOPDIR)/components/backtrace \ -I$(LITEOSTOPDIR)/components/exchook \ -I$(LITEOSTOPDIR)/components/signal # Third party related 第三方依赖文件及头文件目录 C_SOURCES += \ $(wildcard $(LITEOSTOPDIR)/third_party/bounds_checking_function/src/*.c)\ $(wildcard $(LITEOSTOPDIR)/kal/cmsis/*.c)\ $(wildcard $(LITEOSTOPDIR)/kal/posix/src/*.c) C_INCLUDES += \ -I$(LITEOSTOPDIR)/third_party/bounds_checking_function/include \ -I$(LITEOSTOPDIR)/third_party/bounds_checking_function/src\ -I$(LITEOSTOPDIR)/third_party/cmsis/CMSIS/RTOS2/Include \ -I$(LITEOSTOPDIR)/third_party/musl/porting/liteos_m/kernel/include\ -I$(LITEOSTOPDIR)/kal/cmsis \ -I$(LITEOSTOPDIR)/kal/posix/include \ -I$(LITEOSTOPDIR)/kal/posix/musl_src/internal # Arch related ASM_SOURCES += $(wildcard $(LITEOSTOPDIR)/arch/arm/cortex-m4/gcc/*.s) ASMS_SOURCES += $(wildcard $(LITEOSTOPDIR)/arch/arm/cortex-m4/gcc/*.S) C_SOURCES += $(wildcard $(LITEOSTOPDIR)/arch/arm/cortex-m4/gcc/*.c) C_INCLUDES += -I. \ -I$(LITEOSTOPDIR)/arch/include \ -I$(LITEOSTOPDIR)/arch/arm/cortex-m4/gcc CFLAGS += -nostdinc -nostdlib ASFLAGS += -imacros $(LITEOSTOPDIR)/kernel/include/los_config.h -DCLZ=CLZ # list of ASM .S program objects OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASMS_SOURCES:.S=.o))) vpath %.S $(sort $(dir $(ASMS_SOURCES))) $(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR) $(CC) -c $(CFLAGS) $(ASFLAGS) $< -o $@
这里注意:最后一行前面的缩进必须为tab,而不是空格。否则编译会报错。
liteos_file_path.mk
*.S
文件的编译规则# list of ASM .S program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASMS_SOURCES:.S=.o)))
vpath %.S $(sort $(dir $(ASMS_SOURCES)))
$(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR)
$(CC) -c $(CFLAGS) $(ASFLAGS) $< -o $@
target_config.h
用于配置裁剪内核。该文件相当于FreeRTOS的FreeRTOSConfig.h
/**@defgroup los_config System configuration items * @ingroup kernel */ #ifndef _TARGET_CONFIG_H #define _TARGET_CONFIG_H #include "stm32f4xx.h" #include "stm32f4xx_it.h" #ifdef __cplusplus #if __cplusplus extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ /*============================================================================= System clock module configuration =============================================================================*/ #define OS_SYS_CLOCK SystemCoreClock #define LOSCFG_BASE_CORE_TICK_PER_SECOND (1000UL) #define LOSCFG_BASE_CORE_TICK_HW_TIME 0 #define LOSCFG_BASE_CORE_TICK_WTIMER 0 #define LOSCFG_BASE_CORE_TICK_RESPONSE_MAX SysTick_LOAD_RELOAD_Msk /*============================================================================= Hardware interrupt module configuration =============================================================================*/ #define LOSCFG_PLATFORM_HWI 0 #define LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT 0 #define LOSCFG_PLATFORM_HWI_LIMIT 128 /*============================================================================= Openharmony Kernel configuration =============================================================================*/ /*============================================================================= Task module configuration =============================================================================*/ #define LOSCFG_BASE_CORE_TSK_LIMIT 24 #define LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE (0x500U) #define LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE (0x2D0U) #define LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE (0x130U) #define LOSCFG_BASE_CORE_TIMESLICE 1 #define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 20000 /*============================================================================= Semaphore module configuration =============================================================================*/ #define LOSCFG_BASE_IPC_SEM 1 #define LOSCFG_BASE_IPC_SEM_LIMIT 48 /*============================================================================= Mutex module configuration =============================================================================*/ #define LOSCFG_BASE_IPC_MUX 1 #define LOSCFG_BASE_IPC_MUX_LIMIT 24 /*============================================================================= Queue module configuration =============================================================================*/ #define LOSCFG_BASE_IPC_QUEUE 1 #define LOSCFG_BASE_IPC_QUEUE_LIMIT 24 /*============================================================================= Software timer module configuration =============================================================================*/ #define LOSCFG_BASE_CORE_SWTMR 1 #define LOSCFG_BASE_CORE_SWTMR_ALIGN 1 #define LOSCFG_BASE_CORE_SWTMR_LIMIT 48 /*============================================================================= Memory module configuration =============================================================================*/ #define LOSCFG_MEM_MUL_POOL 1 #define OS_SYS_MEM_NUM 20 /*============================================================================= Exception module configuration =============================================================================*/ #define LOSCFG_PLATFORM_EXC 1 /*============================================================================= TestSuite configuration =============================================================================*/ #define LOSCFG_TEST 0 #ifndef LOSCFG_BACKTRACE_TYPE #define LOSCFG_BACKTRACE_TYPE 1 #endif /** * @ingroup los_config * Configuration backtrace depth. */ #ifndef LOSCFG_BACKTRACE_DEPTH #define LOSCFG_BACKTRACE_DEPTH 15 #endif #ifdef __cplusplus #if __cplusplus } #endif /* __cplusplus */ #endif /* __cplusplus */ #endif /* _TARGET_CONFIG_H */
STM32F407ZGTx_FLASH.ld
_sstack = 0x20000000; /* start of RAM */
_stext = .;
Core\Src\stm32f4xx_it.c
#include "los_arch_context.h" #include "los_tick.h" /* ......... */ void PendSV_Handler(void) { /* USER CODE BEGIN PendSV_IRQn 0 */ HalPendSV(); /* USER CODE END PendSV_IRQn 0 */ /* USER CODE BEGIN PendSV_IRQn 1 */ /* USER CODE END PendSV_IRQn 1 */ } /* ......... */ void SysTick_Handler(void) { /* USER CODE BEGIN SysTick_IRQn 0 */ OsTickHandler(); /* USER CODE END SysTick_IRQn 0 */ /* USER CODE BEGIN SysTick_IRQn 1 */ /* USER CODE END SysTick_IRQn 1 */ } /* ......... */
Core\Src\main.c
#include "stdio.h"
printf
/* USER CODE BEGIN 0 */ #if 1 int _write(int fd, char *ptr, int len) { osStatus_t result; osKernelState_t state; if (osKernelGetState() == osKernelInactive) { //系统未启动时不使用DMA HAL_UART_Transmit(&huart1, ptr, len, 0xFFFF); return len; } else { //获取信号,如果上一个DMA传输完成 //信号就能获取到,没有传输完成任务就挂起 //等到传输完成再恢复 result = osSemaphoreAcquire(UART1_TX_DMA_SemaphoreHandle, 0xFFFF); if (result == osOK) { HAL_UART_Transmit_DMA(&huart1, ptr, len); //获取成功,发送数据 return len; } else { return -1; //获取失败 } } } #endif // DMA 传输完成后会调用传输完成回调函数,在该函数中我们释放信号 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == huart1.Instance) osSemaphoreRelease(UART1_TX_DMA_SemaphoreHandle); } /* USER CODE END 0 */
Core\Src\main.c
#include "cmsis_os.h"
/* ......... */ #include "cmsis_os.h" /* ......... */ /* USER CODE BEGIN PV */ osSemaphoreId_t UART1_TX_DMA_SemaphoreHandle; const osSemaphoreAttr_t UART1_TX_DMA_Semaphore_attributes = { .name = "UART1_TX_DMA_Semaphore", }; osThreadId_t uart_taskHandle; const osThreadAttr_t uart_task_attributes = { .name = "uart_task", .stack_size = 512 * 2, .priority = (osPriority_t)osPriorityNormal3, }; /* USER CODE END PV */ /* ......... */ /* USER CODE BEGIN 0 */ /* ......... */ void Uart_Task(void *argument) { HAL_GPIO_WritePin(LED_G_GPIO_Port, LED_G_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET); while (1) { HAL_GPIO_TogglePin(LED_G_GPIO_Port, LED_G_Pin); HAL_GPIO_TogglePin(LED_R_GPIO_Port, LED_R_Pin); printf("System Runing!!!\r\n"); osDelay(1000); } } /* USER CODE END 0 */ /* ......... */ int main(){ /* ......... */ /* USER CODE BEGIN 2 */ osKernelInitialize(); printf("System Init!\r\n"); UART1_TX_DMA_SemaphoreHandle = osSemaphoreNew(1, 1, &UART1_TX_DMA_Semaphore_attributes); uart_taskHandle = osThreadNew(Uart_Task, NULL, &uart_task_attributes); osKernelStart(); /* USER CODE END 2 */ /* ......... */ }
make -j12
2. 使用STM32Cubeprogrammer下载位于/build
中的固件STM32F429ZI_Harmony_LiteOS_M.hex
3. 观察到LED交替闪烁,串口助手打印出了调试信息。
LED 交替闪烁
串口输出信息
总的来说,移植的难点还是在于对 Makefile 相关工具链的理解与应用。由于有CMSIS_OS的封装,轻度使用时,与FreeRTOS感受相差不大。对新手来说使用FreeRTOS进行入门还是不错的选择,建议基本了解 FreeRTOS 之后再深入学习 LiteOS-M 并掌握二者之间的差别。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。