OpenHarmony轻量系统移植示例

Posted OpenHarmony技术社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenHarmony轻量系统移植示例相关的知识,希望对你有一定的参考价值。

1.1移植类型

OpenHarmony轻量系统的移植比较简单,代码中解耦做得非常好。从代码的设计理念上来看,移植主要是3部分的内容:
(1)ARCH部分的代码
(2)SoC部分的代码
(3)board级的代码
从上至下我们可以用一张图来做对比:

ARCH也就是架构,例如ARM架构、RISC-V架构等
SoC是具体芯片,例如STM32、海思等,一个架构可以有多个芯片。
Board是具体开发板,例如3861有润和的开发板、也有小熊派的开发板。

通常来说,相关架构的不同SoC,应该是共用一套ARCH代码,不需要为每个SoC都重新写一遍ARCH代码,可以增加代码的复用。
相关SoC的不通过board开发板,也应该共用一套SoC代码即可,板卡之间的代码差异应该放到board中。

基于如上设计,我们移植的类型可以分为3部分:
(1)ARCH移植:全新的架构级别的移植
(2)SoC移植:已支持的架构做SoC级别的移植
(3)board级别的移植:只针对开发板做少量移植。

移植的难度也是ARCH最难,SoC较难、board较简单。

1.2 相关代码

我们看下OpenHarmony轻量系统之3部分的代码分别在哪里:
(1)ARCH相关代码
ARCH相关的代码存放在kernel\\liteos_m\\arch文件夹中

可以看到目前已支持的架构有ARM(M3、M4、M33、M7、ARM9)、csky、risc-v、xtensa。

(2)SoC相关代码
SoC相关的代码位于:device\\soc

(3)board相关代码
board相关的代码位于:device/board

(4)vendor相关代码
除了以上3部分的代码之外,还有厂商配置相关代码,这一部分主要是用于编译系统、HDF配置等,路径为: vendor
内容如下:

1.3移植思路

建议是先从最简单的开始,路线如下:
vendor —— board —— soc —— ARCH
下一篇文章,将开始讲解如何创建一个自己的vendor厂商配置和编译流程。
一开始会基于GD32单片机

1.4 代码仓库

代码仓库如下:

其中,01_vendor_soc_board 是初步移植的示例,编译不通过
02_vendor_soc_board是已经可以编译通过并且烧录到GD32F303上可以正常跑的。

1.5 使用说明

(1)代码下载

开发者可以直接先下载最新的openharmony代码,参考文章:
https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-lite-sourcecode-acquire.md
然后下载本仓库的代码,将对应的代码拷贝到device/board 、device/soc、vendor中

(2)交叉编译器下载:

我们使用的编译器是arm-none-eabi-gcc,下载地址:
git clone https://gitee.com/harylee/gcc-arm-none-eabi-10-2020-q4-major.git
将交叉编译器环境变量bin目录配置到.bashrc文件中。
执行arm-none-eabi-gcc -v,有如下打印则表示交叉编译器配置正确。

(3)编译

执行hb set,选择gd32f303_lianzhian

然后执行hb build -f,如下提示,则表示编译成功

2.1 hb编译原理

当我们输入hb set命令后,会提示我们选择要编译构建的工程。

那么,hb 怎么知道有哪些工程可以编译呢?
事实上这些工程都是在vendor文件夹中的,为了验证,我们可以在vendor中创建一个空的文件夹:gd,然后gd文件夹下面又创建了gd32f303_lianzhian文件夹。
但是这里还不够,一个标准简单的vendor文件夹结构如下:

其中debug.config内容为空即可,因为它的内容是自动生成的,后面我们配置的内核的时候需要用到。
这几个文件我们可以直接复制3861的过来,然后删去我们不需要的子系统,我们只需要保留如下即可:
config.json文件:


    "product_name": "gd32f303_lianzhian",
    "type": "mini",
    "version": "3.0",
    "device_company": "lianzhian",
    "board": "gd32f303_lianzhian",
    "kernel_type": "liteos_m",
    "kernel_version": "",
    "subsystems": [
      
        "subsystem": "kernel",
        "components": [
           "component": "liteos_m",
            "features":[
            ]
          
        ]
      
    ],
    "third_party_dir": "",
    "product_adapter_dir": ""

BUILD.gn文件

group("gd32f303_lianzhian") 

此时,我们再去执行hb set,就可以看到我们自己创建的工程了:gd32f303_lianzhian

2.2 设计思想

最新的master分支的代码设计采用Board和SoC解耦的设计思路,具体可以看这个文章:https://gitee.com/openharmony-sig/sig-content/blob/master/devboard/docs/board-soc-arch-design.md
按照硬件进行层次划分为芯片架构层、片上系统层和单板层。从下向上依次进行包含关系,例如:

(1)架构

ARMv7E-M架构具有ARM Cortex-M4, ARM Cortex-M7等CPU实现

(2)芯片系列

ARM Cortex-M4 CPU对应的SoC Family有STMicro STM32、NXP i.MX等,反过来,如图SoC Family 2跨越CPU1和CPU2,意味着一个SoC Family可以包含多个CPU实现,
例如STMicro STM32可以包含Cortex-M0、Cortex-M4等CPU,又例如复杂的STM32MP157 SoC包含两个Cortex-A7 CPU核与一个Cortex-M4 CPU核,对于异构多核SoC,需要通过OpenAMP来进行分解成多个同构多核的部分。

(3)芯片与开发板对应关系

STM32 SoC Family有STM32F4、STM32G4等SoC Series。
STM32F4 SoC Series 有 STM32F401、STM32F429等SoC。
STM32F429 SoC 有 野火STM32F429挑战者开发板、正点原子stm32f429阿波罗开发板等。如图Board 5上面还有一个shields,意味着一个Board可以通过增加扩展板的形式来提供更强的功能。例如,单板可以利用串口通信外接Hi3861模组,以提供WLAN能力。

基于硬件结构划分层次图,OpenHarmony顶层目录结构设计如下,

2.3 board配置

1 创建 board文件夹

当我们输入hb set命令后,
我们选择 gd32f303_lianzhian 可以看到会提示报错:

我们需要创建该文件夹:device/board/lianzhian
为啥是lianzhian ????
因为我们在vendor中的config.json中指定了device_company 设备厂家是lianzhian,大家可以回头看看

标准的board文件夹目录结构如下:

2 Kconfig配置文件

我们可以在kernel/liteos_m内核目录下执行make menuconfig进行图形化配置,Makefile文件会遍历board下的所有Kconfig文件,所以我们需要添加对应的Kconfig文件。
这里内核是分层设计的,即厂商配置和具体开发板分开,一个厂商下面可以有多个开发板。
例如我们现在移植的设备厂商是是lianzhian,那么lianzhian是厂商文件夹,lianzhian下面有Kconfig,主要是厂商级别的配置。
然后lianzhian下面可以有多个开发板,我们这里只写了gd32f303_lianzhian开发板。同样gd32f303_lianzhian文件夹下面也有Kconfig配置文件。

3 厂商Kconfig配置文件

我们先看下lianzhian厂商的Kconfig文件
(1)Kconfig.liteos_m.boards 文件内容

orsource "*/Kconfig.liteos_m.board"

可以看到很简单,事实上它就是简单的把当前目录下的所有文件夹下的Kconfig.liteos_m.board文件都导入进来。

(2)Kconfig.liteos_m.defconfig.boards文件

orsource "*/Kconfig.liteos_m.defconfig.board"

同样把当前目录下的所有文件夹下的Kconfig.liteos_m.defconfig.board文件都导入进来。

(3)Kconfig.liteos_m.shields 文件
这里我们暂时不需要,可以内容为空

4 具体开发板的Kconfig配置文件

我们先看下gd32f303_lianzhian厂商的Kconfig文件

(1)Kconfig.liteos_m.board文件
需要配置选择该单板的选项,以及它依赖的SoC

config BOARD_GD32F303_LIANZHIAN
    bool "select board gd32f303 lianzhian"
    depends on SOC_GD32F303 #只有当我们芯片型号选择为GD32F303时才可见

这里是增加一个配置选项,即后面我们可以在make menuconfig中看到"select board gd32f303 lianzhian"配置项。

(2)Kconfig.liteos_m.defconfig.board 文件
需要配置选择该单板后,默认定义 BOARD 的名字,该文件我们可以留空,也可以如下配置:

if BOARD_GD32F303_LIANZHIAN
config BOARD
    string
    default "gd32f303_lianzhian"

endif #BOARD_GD32F303_LIANZHIAN

(3)gd32f303_lianzhian_defconfig 文件
内容为:

LOSCFG_BOARD_GD32F303_LIANZHIAN=y
LOSCFG_SOC_SERIES_GD32F303=y
LOSCFG_SOC_GD32F303ZET6=y

这里表示我们选中的板卡、SOC、SOC具体子型号系列等。

5 config.gni配置文件

liteos_m文件夹下的config.gni文件是用来进行内核配置的

该文件内容如下:

# Copyright (C) 2020 Hisilicon (Shanghai) Technologies Co., Ltd. All rights reserved.

# 选择内核类型, e.g. "linux", "liteos_a", "liteos_m".
kernel_type = "liteos_m"

# 内核版本,留空即可.
kernel_version = ""

# 芯片架构, e.g. "cortex-a7", "riscv32".
board_cpu = "cortex-m4"

# 这里一般不用谢, 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". Its not mandatory if you use the default toolchain.
# 交叉编译器名称
board_toolchain = "arm-none-eabi-gcc"

# The toolchain path installed, its not mandatory if you have added toolchain path to your ~/.bashrc.
# 这里一般可以不写
board_toolchain_path = ""

# 交叉编译器Compiler prefix.
board_toolchain_prefix = "arm-none-eabi-"

# 编译器类型 Compiler type, "gcc" or "clang".
board_toolchain_type = "gcc"

# 编译选项Board related common compile flags.
board_cflags = [
  "-mcpu=cortex-m4",
  "-mfpu=fpv4-sp-d16",
  "-mfloat-abi=hard",
  "-mthumb",
  "-Og",
  # "-g",
  #"-Wall",
  "-fdata-sections",
  "-ffunction-sections",
  # 注意,这里我们需要定义GD32F30X_HD宏
  "-DGD32F30X_HD",
  # 我们需要浮点数计算
  "-D__FPU_PRESENT",
]
board_cxx_flags = board_cflags
board_ld_flags = []

# 头文件路径,一般需要soc相关 Board related headfiles search path.
board_include_dirs = [
  "$ohos_root_pathdevice/soc/gd32/gd32f303/liteos_m",
  "$ohos_root_pathdevice/soc/gd32/CMSIS",
  "$ohos_root_pathdevice/soc/gd32/CMSIS/GD/GD32F30x/Include",
  "$ohos_root_pathdevice/soc/gd32/gd32f303/GD32F3XX_Driver/Inc",
  "$ohos_root_pathdevice/soc/gd32/gd32f303",
  "$ohos_root_pathutils/native/lite/include",
  "$ohos_root_pathkernel/liteos_m/components/cpup",
  "$ohos_root_pathkernel/liteos_m/components/exchook",

]

# 开发板用到哪个soc Board adapter dir for OHOS components.
board_adapter_dir = "$ohos_root_pathdevice/soc/gd32"

# Sysroot path.
board_configed_sysroot = ""

# Board storage type, it used for file system generation.
storage_type = ""

2.4 SOC配置

1 创建 SOC文件夹

我们进入到device/soc文件夹,创建 gd32文件夹,gd32文件夹内容如下:

其中GD32官方标准库文件和CMSIS都可以在GD官网下载到,而且不需要我们修改编写,故而本节不会讲其中的内容,重点放在Kconfig配置文件中。
同样,soc也是分为芯片厂家的Kconfig 和具体芯片信号的Kconfig,gd32是芯片厂家,gd32f303只是其中的一款型号而已。

2 gd32芯片厂家Kconfig配置文件

(1)先看Kconfig.liteos_m.soc文件

config SOC_COMPANY_GD32
    bool

if SOC_COMPANY_GD32
config SOC_COMPANY
    default "gd32"

rsource "*/Kconfig.liteos_m.soc"
endif # SOC_COMPANY_GD32

这里很简单,就是配置我们的芯片厂商默认为 gd32
之后导入所有文件夹的 Kconfig.liteos_m.soc 配置文件

(2)Kconfig.liteos_m.series文件
这个文件就比较简单了,导入所有文件夹的 Kconfig.liteos_m.series 配置文件

rsource "*/Kconfig.liteos_m.series"

(3)Kconfig.liteos_m.defconfig
同样,导入所有文件夹的Kconfig.liteos_m.defconfig

rsource "*/Kconfig.liteos_m.defconfig.series"

3 gd32F303芯片的Kconfig配置文件

我们来看看具体的芯片型号gd32f303的配置文件吧

(1)Kconfig.liteos_m.series文件
需要配置芯片系列,以及它的芯片架构等信息
内容:

config SOC_SERIES_GD32F303
    bool "GD32F303 chip"
    select ARM
    select SOC_COMPANY_GD32
    select CPU_CORTEX_M4
    help
        Enable support for GD32F303

这个是芯片系列的选择,我们的芯片系列是GD32F303,架构是ARM、CORTEX_M4 芯片厂家是 SOC_COMPANY_GD32,这个在上一级gd32的Kconfig配置文件中有定义。

(2)Kconfig.liteos_m.soc文件
需要配置芯片系列有多少个型号的芯片。
内容:

choice
    prompt "GD32F303 series SoC"
    depends on SOC_SERIES_GD32F303  #只有选择了芯片系列SOC_SERIES_GD32F303后才会出现如下选项

config SOC_GD32F303ZET6     #增加一个SOC_GD32F303ZET6选项,我们现在只有GD32F303ZET6,后面可以还有GD32F303RCT6等。
    bool "SoC GD32F303ZET6"

endchoice

(3)Kconfig.liteos_m.defconfig.series 文件
选择芯片系列后默认的配置
内容:

if SOC_SERIES_GD32F303

rsource "Kconfig.liteos_m.defconfig.gd32f303"

config SOC_SERIES
    string
    default "gd32f303"

config NUM_IRQS  #中断数量,跟具体芯片相关
    int
    default 90

config SYS_CLOCK_HW_CYCLES_PER_SEC  #时钟周期,GD32F303是120MHz
    int
    default 120000000

endif

(4)Kconfig.liteos_m.defconfig.gd32f303 文件
Gd32f303的配置,内容比较简单:

config SOC
    string
    default "gd32f303zet6"
    depends on SOC_GD32F303ZET6

默认是gd32f303zet6

至此我们的soc的kconfig配置基本完成

4 内核配置头文件

还有一个比较重要的内核配置头文件,target_config.h。这个大家可以直接复制我的就行,主要是内核功能配置相关。

其中有一个比较重要的配置项:

/**
 * @ingroup los_config
 * Memory size
 */
#define LOSCFG_SYS_HEAP_SIZE                                (60*1024)

这个是配置内核的堆栈大小,这里可以根据自己芯片的内存大小来定,GD32F303内存是64KB,这里我用60k即可。

2.5 make menuconfig配置

完成上面移植内容后,接下来,我们就可以进行menuconfig配置了。
注意,这里我们需要先执行一次hb set选择我们的开发板gd32f303_lianzhian。

我们进入 kernel/liteos_m 文件夹
执行 make menuconfig

进入Platform,我们选择gd32f303芯片、gd32f303_lianzhian开发板,如下:

退出保存。
结果将自动保存在$(PRODUCT_PATH)/kernel_configs/debug.config

2.6 gn编译

在上一步Kconfig的图形化配置后,将其生成的配置结果可以作为gn编译的输入,以控制不同模块是否编译。另外为了解决之前gn编写时,随意include的问题,内核编译做了模块化编译的设计,使得整个编译逻辑更加清晰。
我们需要编写device/board/lianzhian 和 device/soc/gd32两个文件夹下的BUILD.gn。
这几个BUILD.gn文件比较简单,都是模块化编译,大家可以直接参考我的。

2.7 编译器安装

我们使用的编译器是arm-none-eabi-gcc,下载地址:
git clone https://gitee.com/harylee/gcc-arm-none-eabi-10-2020-q4-major.git
将交叉编译器环境变量bin目录配置到.bashrc文件中。

2.8 开始编译

配置完BUILD.gn后,我们就可以开始执行hb build -f编译了。
可以看到已经能编译过一大半了:

我们今天的目标就是要能让编译系统能开始编译我们的开发板
一步一脚印,接下来我们将继续开始移植,接下来将配置libc库、系统启动、main函数、链接脚本,直到编译通过并且在开发板中成功运行~

想了解更多关于鸿蒙的内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://ost.51cto.com/#bkwz

::: hljs-center

以上是关于OpenHarmony轻量系统移植示例的主要内容,如果未能解决你的问题,请参考以下文章

OpenHarmony轻量系统开发初始OpenHarmony

OpenHarmony移植案例: build lite源码分析之hb命令__entry__.py

OpenHarmony移植 3.1 版本系统到 STM32

OpenHarmony移植 3.1 版本系统到 STM32

OpenHarmony移植 3.1 版本系统到 STM32

OpenHarmony移植:如何适配utils子系统之KV存储部件