你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32 移植鸿蒙操作系统

[复制链接]
STMCU小助手 发布时间:2022-11-16 19:09
前言
随着 OpenHarmony3.1 的正式发布,其功能也在不断完善。OpenHarmony LiteOS-M 内核是面向IoT领域构建的轻量级物联网操作系统内核,具有小体积、低功耗、高性能的特点,其代码结构简单,主要包括内核最小功能集、内核抽象层、可选组件以及工程目录等,分为硬件相关层以及硬件无关层,硬件相关层提供统一的HAL(Hardware Abstraction Layer)接口,提升硬件易适配性,不同编译工具链和芯片架构的组合分类,满足AIoT类型丰富的硬件和编译工具链的拓展。本文主要介绍如何在STM32上移植 OpenHarmony LiteOS-M 内核,及其注意事项。

一、开发环境
硬件:
- STM32F429I-DISC1 开发板
88f82b9af38d4a1ebf55de3ce20ec3cc.png

软件:
- VSCode:用于编辑代码
- STM32CubeMX:用于生成工程
- make、arm-none-eabi-gcc:用于编译工程
- STM32Cubeprogrammer:用于下载工程
- Git:用于获取 OpenHarmony LiteOS-M 内核源码

二、移植内核
1. 操作流程

拉取仓库代码。
使用STM32CubeMX在 /target 目录下生成工程。
修改Makefile文件,工程加入 OpenHarmony LiteOS-M 内核所需的文件。
添加用户代码以支持printf。添加用户自定义任务。
编译下载程序

2. 获取源码

d705d7f0048c488f8f14b5594c0d1c4d.png

使用Git Bush,拉取内核源码到本地。

dc7910cb5c514699be84cb1ba2fe39e4.png

创建 /third_party 目录,用于存放第三方依赖文件(STM32 所需的 CMSIS 等),拉取第三方依赖文件。

b2f839576df54ee7aee9ae5f4e16240f.png

到这里 OpenHarmony LiteOS-M 内核源码就获取完毕了。

3. 生成工程
进入/targets 目录,使用 STM32CubeMX 生成工程 STM32F429ZI_Harmony_LiteOS_M

6676c6dde05c4d5a94c86f352f83f9f5.png

与FreeRTOS类似,由于LiteOS会占用SysTick定时器,因此需要修改HAL库延时的基础时钟,改为其他非SysTick的定时器,避免HAL库延时的定时器和系统运行的定时器冲突。

49ebb64304a34008a89fa4c7cd1bf76d.png

配置:下载调试端口SW、串口USART、LED_GPIO、时钟树。

de7c845c652f498ab3b9efbdb6e91dba.png

开发环境选择 Makefile

1ee230f036a341969839d9b848a860a7.png

Code Generator 中一定要选择 Copy only necessary library files ! 如果选择所有库文件都添加的话,那么就会生成很多模板文件。由于我们需要在 Makefile 中添加文件,如果目录中有模板文件的话,我们就无法直接使用筛选功能将所有源文件快速添加到工程中了。

9fa06158193d49a69ac5e73b83e8c17e.png

至此工程配置已结束,点击 Generate 即可生成工程。

4. 修改工程文件
1.使用 VS Code 打开targets下的工程目录,新建liteos_file_path.mk用于将内核源码文件添加到工程Makefile中,该文件相当于C语言中的头文件,主 Makefile 文件可以直接包含该文件。

f25a0d2c8002420d9a127891f40574ad.png

2.添加内核源文件目录到 liteos_file_path.mk 中。
  1. # Topdir 顶层目录
  2. LITEOSTOPDIR := ../../
  3. LITEOSTOPDIR := $(realpath $(LITEOSTOPDIR))

  4. # Common 内核源文件及头文件目录
  5. C_SOURCES   +=  \
  6.     $(wildcard $(LITEOSTOPDIR)/kernel/src/*.c) \
  7.     $(wildcard $(LITEOSTOPDIR)/kernel/src/mm/*.c) \
  8.     $(wildcard $(LITEOSTOPDIR)/components/cpup/*.c) \
  9.     $(wildcard $(LITEOSTOPDIR)/components/power/*.c) \
  10.     $(wildcard $(LITEOSTOPDIR)/components/backtrace/*.c) \
  11.     $(wildcard $(LITEOSTOPDIR)/components/exchook/*.c) \
  12.     $(wildcard $(LITEOSTOPDIR)/components/signal/*.c) \
  13.     $(wildcard $(LITEOSTOPDIR)/utils/*.c)

  14. C_INCLUDES  +=  \
  15.     -I$(LITEOSTOPDIR)/utils \
  16.     -I$(LITEOSTOPDIR)/kernel/include \
  17.     -I$(LITEOSTOPDIR)/components/cpup \
  18.     -I$(LITEOSTOPDIR)/components/power \
  19.     -I$(LITEOSTOPDIR)/components/backtrace \
  20.     -I$(LITEOSTOPDIR)/components/exchook \
  21.     -I$(LITEOSTOPDIR)/components/signal


  22. # Third party related 第三方依赖文件及头文件目录
  23. C_SOURCES    += \
  24.         $(wildcard         $(LITEOSTOPDIR)/third_party/bounds_checking_function/src/*.c)\
  25.     $(wildcard $(LITEOSTOPDIR)/kal/cmsis/*.c)\
  26.     $(wildcard $(LITEOSTOPDIR)/kal/posix/src/*.c)

  27. C_INCLUDES   += \
  28.         -I$(LITEOSTOPDIR)/third_party/bounds_checking_function/include \
  29.     -I$(LITEOSTOPDIR)/third_party/bounds_checking_function/src\
  30.     -I$(LITEOSTOPDIR)/third_party/cmsis/CMSIS/RTOS2/Include \
  31.     -I$(LITEOSTOPDIR)/third_party/musl/porting/liteos_m/kernel/include\
  32.     -I$(LITEOSTOPDIR)/kal/cmsis \
  33.     -I$(LITEOSTOPDIR)/kal/posix/include \
  34.     -I$(LITEOSTOPDIR)/kal/posix/musl_src/internal


  35. # Arch related
  36. ASM_SOURCES   += $(wildcard $(LITEOSTOPDIR)/arch/arm/cortex-m4/gcc/*.s)

  37. ASMS_SOURCES  += $(wildcard $(LITEOSTOPDIR)/arch/arm/cortex-m4/gcc/*.S)

  38. C_SOURCES     += $(wildcard $(LITEOSTOPDIR)/arch/arm/cortex-m4/gcc/*.c)

  39. C_INCLUDES    += -I. \
  40.                  -I$(LITEOSTOPDIR)/arch/include \
  41.                  -I$(LITEOSTOPDIR)/arch/arm/cortex-m4/gcc

  42. CFLAGS        += -nostdinc -nostdlib
  43. ASFLAGS       += -imacros $(LITEOSTOPDIR)/kernel/include/los_config.h -DCLZ=CLZ

  44. # list of ASM .S program objects
  45. OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASMS_SOURCES:.S=.o)))
  46. vpath %.S $(sort $(dir $(ASMS_SOURCES)))

  47. $(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR)
  48.         $(CC) -c $(CFLAGS) $(ASFLAGS) lt; -o $@
复制代码

这里注意:最后一行前面的缩进必须为tab,而不是空格。否则编译会报错。

3.修改项目Makefile
在Makefile中包含liteos_file_path.mk

558f1379e42749678db37b7ceee1b255.png

增加*.S文件的编译规则
  1. # list of ASM .S program objects
  2. OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASMS_SOURCES:.S=.o)))
  3. vpath %.S $(sort $(dir $(ASMS_SOURCES)))

  4. $(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR)
  5.         $(CC) -c $(CFLAGS) $(ASFLAGS) lt; -o $@
复制代码

1f332cdb4c32450aac6fb082ccb2cd1f.png

4.添加 target_config.h 用于配置裁剪内核。该文件相当于FreeRTOS的FreeRTOSConfig.h
  1. /**@defgroup los_config System configuration items
  2. * @ingroup kernel
  3. */

  4. #ifndef _TARGET_CONFIG_H
  5. #define _TARGET_CONFIG_H

  6. #include "stm32f4xx.h"
  7. #include "stm32f4xx_it.h"

  8. #ifdef __cplusplus
  9. #if __cplusplus
  10. extern "C"
  11. {
  12. #endif /* __cplusplus */
  13. #endif /* __cplusplus */

  14. /*=============================================================================
  15.                                         System clock module configuration
  16. =============================================================================*/
  17. #define OS_SYS_CLOCK SystemCoreClock
  18. #define LOSCFG_BASE_CORE_TICK_PER_SECOND (1000UL)
  19. #define LOSCFG_BASE_CORE_TICK_HW_TIME 0
  20. #define LOSCFG_BASE_CORE_TICK_WTIMER 0
  21. #define LOSCFG_BASE_CORE_TICK_RESPONSE_MAX SysTick_LOAD_RELOAD_Msk

  22. /*=============================================================================
  23.                                         Hardware interrupt module configuration
  24. =============================================================================*/
  25. #define LOSCFG_PLATFORM_HWI 0
  26. #define LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT 0
  27. #define LOSCFG_PLATFORM_HWI_LIMIT 128

  28. /*=============================================================================
  29.                                         Openharmony Kernel configuration
  30. =============================================================================*/

  31. /*=============================================================================
  32.                                        Task module configuration
  33. =============================================================================*/
  34. #define LOSCFG_BASE_CORE_TSK_LIMIT 24
  35. #define LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE (0x500U)
  36. #define LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE (0x2D0U)
  37. #define LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE (0x130U)
  38. #define LOSCFG_BASE_CORE_TIMESLICE 1
  39. #define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 20000
  40. /*=============================================================================
  41.                                        Semaphore module configuration
  42. =============================================================================*/
  43. #define LOSCFG_BASE_IPC_SEM 1
  44. #define LOSCFG_BASE_IPC_SEM_LIMIT 48

  45. /*=============================================================================
  46.                                        Mutex module configuration
  47. =============================================================================*/
  48. #define LOSCFG_BASE_IPC_MUX 1
  49. #define LOSCFG_BASE_IPC_MUX_LIMIT 24
  50. /*=============================================================================
  51.                                        Queue module configuration
  52. =============================================================================*/
  53. #define LOSCFG_BASE_IPC_QUEUE 1
  54. #define LOSCFG_BASE_IPC_QUEUE_LIMIT 24
  55. /*=============================================================================
  56.                                        Software timer module configuration
  57. =============================================================================*/
  58. #define LOSCFG_BASE_CORE_SWTMR 1
  59. #define LOSCFG_BASE_CORE_SWTMR_ALIGN 1
  60. #define LOSCFG_BASE_CORE_SWTMR_LIMIT 48
  61. /*=============================================================================
  62.                                        Memory module configuration
  63. =============================================================================*/
  64. #define LOSCFG_MEM_MUL_POOL 1
  65. #define OS_SYS_MEM_NUM 20
  66. /*=============================================================================
  67.                                        Exception module configuration
  68. =============================================================================*/
  69. #define LOSCFG_PLATFORM_EXC 1

  70. /*=============================================================================
  71.                                         TestSuite configuration
  72. =============================================================================*/
  73. #define LOSCFG_TEST 0

  74. #ifndef LOSCFG_BACKTRACE_TYPE
  75. #define LOSCFG_BACKTRACE_TYPE 1
  76. #endif
  77. /**
  78. * @ingroup los_config
  79. * Configuration backtrace depth.
  80. */
  81. #ifndef LOSCFG_BACKTRACE_DEPTH
  82. #define LOSCFG_BACKTRACE_DEPTH 15
  83. #endif
  84. #ifdef __cplusplus
  85. #if __cplusplus
  86. }
  87. #endif /* __cplusplus */
  88. #endif /* __cplusplus */

  89. #endif /* _TARGET_CONFIG_H */
复制代码

5.修改链接脚本文件 STM32F407ZGTx_FLASH.ld
添加程序起始地址 _sstack = 0x20000000; /* start of RAM */
添加.text 段的起始地址,这是链接脚本的语法,将当前位置地址赋值给_stext。_stext = .;

a7e3f37fb6aa47cf933009daf2a334e6.png

6.修改中断服务函数 Core\Src\stm32f4xx_it.c
添加 LiteOS 头文件
在PendSV异常中进入LiteOS HalPendSV 异常处理函数,进行任务切换操作
在SysTick中断服务函数添加OsTickHandler函数,为系统提供时间基准
  1. #include "los_arch_context.h"
  2. #include "los_tick.h"
  3. /*
  4. .........
  5. */
  6. void PendSV_Handler(void)
  7. {
  8.     /* USER CODE BEGIN PendSV_IRQn 0 */
  9.     HalPendSV();
  10.     /* USER CODE END PendSV_IRQn 0 */
  11.     /* USER CODE BEGIN PendSV_IRQn 1 */
  12.     /* USER CODE END PendSV_IRQn 1 */
  13. }
  14. /*
  15. .........
  16. */
  17. void SysTick_Handler(void)
  18. {
  19.     /* USER CODE BEGIN SysTick_IRQn 0 */
  20.     OsTickHandler();
  21.     /* USER CODE END SysTick_IRQn 0 */
  22.     /* USER CODE BEGIN SysTick_IRQn 1 */
  23.     /* USER CODE END SysTick_IRQn 1 */
  24. }
  25. /*
  26. .........
  27. */
复制代码

7.修改串口映射 Core\Src\main.c
包含头文件#include "stdio.h"
修改串口映射以支持printf
  1. /* USER CODE BEGIN 0 */
  2. #if 1
  3. int _write(int fd, char *ptr, int len)
  4. {
  5.     osStatus_t result;
  6.     osKernelState_t state;

  7.     if (osKernelGetState() == osKernelInactive)
  8.     {
  9.         //系统未启动时不使用DMA
  10.         HAL_UART_Transmit(&huart1, ptr, len, 0xFFFF);
  11.         return len;
  12.     }
  13.     else
  14.     {
  15.         //获取信号,如果上一个DMA传输完成
  16.         //信号就能获取到,没有传输完成任务就挂起
  17.         //等到传输完成再恢复
  18.         result = osSemaphoreAcquire(UART1_TX_DMA_SemaphoreHandle, 0xFFFF);
  19.         if (result == osOK)
  20.         {
  21.             HAL_UART_Transmit_DMA(&huart1, ptr, len); //获取成功,发送数据
  22.             return len;
  23.         }
  24.         else
  25.         {
  26.             return -1; //获取失败
  27.         }
  28.     }
  29. }
  30. #endif

  31. // DMA 传输完成后会调用传输完成回调函数,在该函数中我们释放信号
  32. void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
  33. {
  34.     if (huart->Instance == huart1.Instance)
  35.         osSemaphoreRelease(UART1_TX_DMA_SemaphoreHandle);
  36. }
  37. /* USER CODE END 0 */
复制代码

8.添加测试任务 Core\Src\main.c
包含os头文件#include "cmsis_os.h"
增加测试任务
  1. /*
  2. .........
  3. */
  4. #include "cmsis_os.h"
  5. /*
  6. .........
  7. */
  8. /* USER CODE BEGIN PV */
  9. osSemaphoreId_t UART1_TX_DMA_SemaphoreHandle;
  10. const osSemaphoreAttr_t UART1_TX_DMA_Semaphore_attributes = {
  11.     .name = "UART1_TX_DMA_Semaphore",
  12. };

  13. osThreadId_t uart_taskHandle;
  14. const osThreadAttr_t uart_task_attributes = {
  15.     .name = "uart_task",
  16.     .stack_size = 512 * 2,
  17.     .priority = (osPriority_t)osPriorityNormal3,
  18. };
  19. /* USER CODE END PV */
  20. /*
  21. .........
  22. */
  23. /* USER CODE BEGIN 0 */
  24. /*
  25. .........
  26. */
  27. void Uart_Task(void *argument)
  28. {
  29.     HAL_GPIO_WritePin(LED_G_GPIO_Port, LED_G_Pin, GPIO_PIN_SET);
  30.     HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET);
  31.     while (1)
  32.     {
  33.         HAL_GPIO_TogglePin(LED_G_GPIO_Port, LED_G_Pin);
  34.         HAL_GPIO_TogglePin(LED_R_GPIO_Port, LED_R_Pin);
  35.         printf("System Runing!!!\r\n");
  36.         osDelay(1000);
  37.     }
  38. }
  39. /* USER CODE END 0 */
  40. /*
  41. .........
  42. */
  43. int main(){
  44. /*
  45. .........
  46. */
  47.         /* USER CODE BEGIN 2 */
  48.     osKernelInitialize();
  49.     printf("System Init!\r\n");
  50.     UART1_TX_DMA_SemaphoreHandle = osSemaphoreNew(1, 1, &UART1_TX_DMA_Semaphore_attributes);
  51.     uart_taskHandle = osThreadNew(Uart_Task, NULL, &uart_task_attributes);
  52.     osKernelStart();
  53.     /* USER CODE END 2 */
  54. /*
  55. .........
  56. */
  57. }
复制代码

5. 编译下载

1.使用make命令编译工程,这里的-j12表示使用多线程编译,可以提高速度,12表示电脑核心数。
make -j12

7e029add83a944728b62c1e4c3c1bf56.png

2. 使用STM32Cubeprogrammer下载位于/build中的固件STM32F429ZI_Harmony_LiteOS_M.hex

c8e0ecbdbdbc452f82a9fa4b3be27874.png

3. 观察到LED交替闪烁,串口助手打印出了调试信息。

LED 交替闪烁

ec8d0b3743de44258ac76f833f276993.gif

串口输出信息

533d2a9830454754a2eac9ff022256ec.png

总结
总的来说,移植的难点还是在于对 Makefile 相关工具链的理解与应用。由于有CMSIS_OS的封装,轻度使用时,与FreeRTOS感受相差不大。对新手来说使用FreeRTOS进行入门还是不错的选择,建议基本了解 FreeRTOS 之后再深入学习 LiteOS-M 并掌握二者之间的差别。
————————————————
版权声明:PeidzzZ


收藏 评论0 发布时间:2022-11-16 19:09

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版