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". It's not mandatory if you use the default toolchain.
# 交叉編譯器名稱
board_toolchain = "arm-none-eabi-gcc"
# The toolchain path installed, it's 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_path}device/soc/gd32/gd32f303/liteos_m",
"${ohos_root_path}device/soc/gd32/CMSIS",
"${ohos_root_path}device/soc/gd32/CMSIS/GD/GD32F30x/Include",
"${ohos_root_path}device/soc/gd32/gd32f303/GD32F3XX_Driver/Inc",
"${ohos_root_path}device/soc/gd32/gd32f303",
"${ohos_root_path}utils/native/lite/include",
"${ohos_root_path}kernel/liteos_m/components/cpup",
"${ohos_root_path}kernel/liteos_m/components/exchook",
]
# 開發闆用到哪個soc Board adapter dir for OHOS components.
board_adapter_dir = "${ohos_root_path}device/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和華為官方合作共建的鴻蒙技術社群