> 文档中心 > 【起航】OpenHarmony远征03轻量系统移植

【起航】OpenHarmony远征03轻量系统移植


轻量级系统芯片移植

目前轻量级系统的典型架构有cortex-m和risc-v系列,这里顺便说一下常见的架构
CISC(复杂指令合集):
隐式总线访问

  • x86 --> 用于PC 常见的芯片core i7 (intel)

RISC(精简指令合集):
显式总线访问

  • ARM -->用于Mobile & 便携设备
  • MIPS -->机顶盒 & 网关
  • RISC-V -->智能穿戴设备

由于openharmony的整体功能较为复杂,如果没有特殊的需求,移植过程中需要关注的目录主要如下;

目录名称 描述
/build/lite OpenHarmony基础编译构建框架
/kernel/liteos_m 基础内核,其中芯片架构相关实现在arch目录下
/device 板级相关实现,各个三方厂商按照OpenHarmony规范适配实现
/vendor 产品级相关实现,主要由华为或者产品厂商贡献
OpenHarmony的device目录是基础芯片的适配目录,如果在三方芯片应用过程中发现此目录下已经有完整的芯片适配,则不需要再额外移植,直接跳过移植过程进行系统应用开发即可,如果该目录下无对应的芯片移植实现,则根据本文完成移植过程。OpenHarmony三方芯片移植主要过程如下:
在这里插入图片描述

编译构建适配流程

首先需要创建开发板目录,以芯片解决方案厂商cat为例,创建一下目录device/cat/test
1.编译工具链与编译选项的配置
构建系统默认使用ohos-clang编译工具链,也支持芯片解决方案厂商按开发板自定义配置。开发板编译配置文件编译相关的变量如下:

  • kernel_type: 开发板使用的内核类型,例如:“liteos_a”, “liteos_m”, “linux”
  • kernel_version: 开发使用的内核版本,例如:“4.19”
  • board_cpu: 开发板CPU类型,例如:“cortex-a7”, “riscv32”
  • board_arch: 开发芯片arch, 例如: “armv7-a”, “rv32imac”
  • board_toolchain: 开发板自定义的编译工具链名称,例如:“gcc-arm-none-eabi”。若为空,则使用默认为ohos-clang
    【arch】 【os】 【嵌入式应用的二进制接口】
    “gcc-arm-linux-gnueabihf” 基于arm64的Linux系统,并支持硬件浮点单元
  • board_toolchain_prefix:编译工具链前缀,例如:“gcc-arm-none-eabi”
  • board_toolchain_type:编译工具链类型,目前支持gcc和clang。例如:“gcc” ,“clang”
  • board_cflags:开发板配置的c文件编译选项
    -o 生成目标文件
    -E 只执行预处理
    -c 取消ld链接
    -w 不生成任何的告警
    -g 包含gdb调试信息
    -I 指定头文件路径
    -L 指定库文件路径
  • board_flags: 开发板配置的c文件编译选项
  • board_ld_flags: 开发板配置的链接选项

配置好的编译选项如下:
device/cat/test/liteos_m/config.gni

# Kernel type, e.g. "linux", "liteos_a", "liteos_m".kernel_type = "liteos_m"# Kernel version.kernel_version = "3.0.0"# Board CPU type, e.g. "cortex-a7", "riscv32".board_cpu = "real-m300"# Board arch, e.g. "armv7-a", "rv32imac".board_arch = ""# Toolchain name used for system compiling.# E.g. gcc-arm-none-eabi, arm-linux-harmonyeabi-gcc, ohos-clang, riscv32-unknown-elf.# Note: The default toolchain is "ohos-clang". It's not mandatory if you use the default toochain.board_toolchain = "gcc-arm-none-eabi"# The toolchain path instatlled, it's not mandatory if you have added toolchian path to your ~/.bashrc.board_toolchain_path =    rebase_path("//prebuilts/gcc/linux-x86/arm/gcc-arm-none-eabi/bin",  root_build_dir)# Compiler prefix.board_toolchain_prefix = "gcc-arm-none-eabi-"# Compiler type, "gcc" or "clang".board_toolchain_type = "gcc"# Board related common compile flags.board_cflags = []board_cxx_flags = []board_ld_flags = []

内核移植

芯片架构的适配式可选的过程,若liteos_m/arch已经支持的芯片架构,则不需要进行芯片的架构适配
Liteos_m的内核主要分为KAL,Components,Kernel和Utils这四个模块

  • KAL是整个内核对外的接口, 依赖Components模块和kernel模块
  • Components模块是可插拔的,依赖kernel模块
  • 在kernel模块中,硬件相关的代码放在kernel的arch目录中,其余的都是硬件不相关的代码,内核的相关功能集(task,sem)的实现依赖的是kernel中arch相关的代码。如任务上下文切换,原子写操作等
  • Utils是基础代码块,kernel与Components都需要依赖Utils模块

在这里插入图片描述

.├── arch      --- 内核指令架构层代码│   ├── arm   --- arm32架构的代码│   │   ├── cortex-m3--- cortex-m3架构的代码│   │   │   ├── iar  --- iar编译工具链实现│   │   │   ├── keil --- keil编译工具链实现│   │   │   └── xxx  --- xxx编译工具链实现│   │   └── cortex-m4--- cortex-m4架构的代码│   │ ├── iar --- iar编译工具链实现 │   │ ├── keil--- keil编译工具链实现│   │ └── xxx --- xxx编译工具链实现│   ├── include      --- 所有的arch需要实现的函数定义,内核依赖│   └── risc-v--- risk-v架构│ └── gcc     --- gcc编译工具链实现├── components--- 移植可选组件,依赖内核,单独对外提供头文件├── kal--- 内核抽象层,提供内核对外接口,当前支持cmsis接口和部分posix接口├── kernel    --- 内核最小功能集代码│   ├── include      --- 内核最小功能集代码│   └── src   --- 内核最小功能集代码  └──utils      --- 基础代码,作为依赖的最底层,被系统依赖

芯片架构的适配点

内核目录结构如图所示,arch/inclue定义了所有的arch需要实现的函数定义,芯片相关的一些代码也会有部分汇编代码,这部分代码会分局编译工具链的不同而不同,因此在具体的芯片架构下还会包含具体的工具链的实现

内核基础适配

在完成芯片架构适配之后,liteos-m提供系统运行所需的系统初始化流程和定制化配置选项。在移植时需要去关注初始化流程中与硬件配置相关的函数
1.启动文件startup.S和相应链接配置文件
2.main.c中的串口初始化和tick中断注册
在这里插入图片描述
启动文件startup.S需要确保中断向量表的入口函数放在RAM的首地址,通常是由链接配置文件进行指定的,如果startup.S能够正常完成系统时钟的初始化,并且能够引导到main函数,则启动文件不需要进行修改,采用厂商自带的startup.S即可

main.c文件中,需要去关注串口的舒适化UartInit和系统的Tick handler函数注册。

  1. UartInit函数表示单板串口的初始化,具体的函数名根据单板自行定义。这个函数是可选的,用户可以根据硬件单板是否支持串口来自行选择调用该函数。如果硬件单板支持串口,则该函数需要完成使能串口TX和RX通道,设置波特率。

  2. HalTickStart设置tick中断的handler函数OsTickHandler。
    对于中断向量表不可重定向的芯片,需要关闭LOSCFG_PLATFORM_HWI宏,并且在startup.S中新增tick中断的handler函数。

特性配置项

liteos_m的完整能力以及默认配置在los_config.h定义,该头文件中的配置项可以适配不同的单板进行裁剪配置。
针对这些配置项需要进行不同的板级配置,将对应的配置项,则可将对应的配置项直接定义到对应单板的device/xxxx/target_config.h文件中,其他未定义的配置项就采用los_config.h中的默认值
内核典型配置项说明

配置项 说明
LOSCFG_BASE_CORE_SWTMR 软件定时器特性开关,1表示打开,0表示关闭
LOSCFG_BASE_CORE_SETMR_ALIGN 对齐软件定时器特性开,1表示打开,依赖软件定时器特性打开,0表示关闭
LOSCFG_BASE_IPC_QUEUE 队列功能开关,1表示打开,0表示关闭
LOSCFG_BASE_CORE_TSK_LIMIT 除idle task之外,总的可用task的个数限制
LOSCFG_KERNEL_PRINTF 打印特性开关,1表示打开,0表示关闭

内核移植验证

由于xts依赖的框架比较多,无法支撑内核单独跑xts,只需要去验证最小系统的核心流程基本OK。
官方测试case如下:

VOID TaskSampleEntry2(VOID) // 任务2的入口函数{    while(1) {      LOS_TaskDelay(10000);      printf("taskSampleEntry2 running...\n");    }}VOID TaskSampleEntry1(VOID) // 任务1的入口函数{    while(1) {      LOS_TaskDelay(2000);      printf("taskSampleEntry1 running...\n");    }}UINT32 TaskSample(VOID){    UINT32 uwRet;    UINT32 taskID1,taskID2;    TSK_INIT_PARAM_S stTask1={0};    stTask1.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry1;    stTask1.uwStackSize  = 0X1000;    stTask1.pcName= "taskSampleEntry1";    stTask1.usTaskPrio   = 6; //stTask1的任务优先级设定,不同于stTask2    uwRet = LOS_TaskCreate(&taskID1, &stTask1);    stTask1.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry2;    stTask1.uwStackSize  = 0X1000;    stTask1.pcName= "taskSampleEntry2";    stTask1.usTaskPrio   = 7;    uwRet = LOS_TaskCreate(&taskID2, &stTask1);    return LOS_OK;}LITE_OS_SEC_TEXT_INIT int main(void){    UINT32 ret;    UartInit(); // 硬件串口配置,通过串口输出调试日志,实际函数名根据单板实现不一样而不一样。    printf("\n\rhello world!!\n\r");    ret = LOS_KernelInit();     TaskSample();    if (ret == LOS_OK) { LOS_Start(); // 开始系统调度,循环执行stTask1/stTask2任务,串口输出任务日志    }    while (1) { __asm volatile("wfi");    }}

51mike麦克疯