介绍基于STM32F407IGT6
芯片在拓维信息Niobe407开发板上移植OpenHarmony LiteOS-M轻量系统,提供交通、工业领域开发板解决方案。
移植架构采用Board
与SoC
分离方案,使用arm gcc
工具链Newlib C
库,实现了lwip
、littlefs
、hdf
等子系统及组件的适配,开发了配套应用示例代码,支持通过Kconfig图形化配置编译选项。
适配准备
- 下载stm32cubemx图形工具。
- 准备ubuntu20.04系统环境,安装arm-none-eabi-gcc交叉编译工具链。
生成可用工程
通过stm32cubemx工具生成STM32F407IGT6
芯片的Makefile工程,在此给出如下配置建议:
- 系统相关配置采用默认配置。
- 时钟配置时将SYSCLK选项配置为168MHz,发挥芯片最强性能。
- 配置USART1用作调试串口,用来打印适配过程中的调试信息。
- 配置stm32cubemx工程选项时,将Toolchain/IDE选项选为Makefile。
生成的工程目录如下:
├── Core
│ ├── Inc
│ │ ├── main.h
│ │ ├── stm32f4xx_hal_conf.h
│ │ └── stm32f4xx_it.h
│ └── Src
│ ├── main.c --- 主函数
│ ├── stm32f4xx_hal_msp.c --- HAL库弱函数配置文件
│ ├── stm32f4xx_it.c --- 中断回调函数文件
│ └── system_stm32f4xx.c --- 系统
├── Drivers
│ ├── CMSIS --- CMSIS接口
│ └── STM32F4xx_HAL_Driver --- HAL库驱动
├── Makefile --- Makefile编译
├── STM32F407IGTx_FLASH.ld --- 链接文件
├── startup_stm32f407xx.s --- 启动文件
└── stm32f407_output.ioc --- stm32cubemx工程文件
验证生成的工程
将生成的工程拷贝至Ubuntu,进入工程目录下执行make命令编译,确定能够编译成功。
arm-none-eabi-gcc build/main.o build/stm32f4xx_it.o build/stm32f4xx_hal_msp.o build/stm32f4xx_hal_tim.o build/stm32f4xx_hal_tim_ex.o build/stm32f4xx_hal_uart.o build/stm32f4xx_hal_rcc.o build/stm32f4xx_hal_rcc_ex.o build/stm32f4xx_hal_flash.o build/stm32f4xx_hal_flash_ex.o build/stm32f4xx_hal_flash_ramfunc.o build/stm32f4xx_hal_gpio.o build/stm32f4xx_hal_dma_ex.o build/stm32f4xx_hal_dma.o build/stm32f4xx_hal_pwr.o build/stm32f4xx_hal_pwr_ex.o build/stm32f4xx_hal_cortex.o build/stm32f4xx_hal.o build/stm32f4xx_hal_exti.o build/system_stm32f4xx.o build/startup_stm32f407xx.o -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -specs=nano.specs -TSTM32F407IGTx_FLASH.ld -lc -lm -lnosys -Wl,-Map=build/stm32f407_output.map,--cref -Wl,--gc-sections -o build/stm32f407_output.elf
arm-none-eabi-size build/stm32f407_output.elf
text data bss dec hex filename
5000 20 1636 6656 1a00 build/stm32f407_output.elf
arm-none-eabi-objcopy -O ihex build/stm32f407_output.elf build/stm32f407_output.hex
arm-none-eabi-objcopy -O binary -S build/stm32f407_output.elf build/stm32f407_output.bin
编译完成会生成一个.bin文件,为了确认该程序能在开发板中成功运行,需要main函数中的串口初始化之后,通过串口输出一段字符串,运行时若收到打印信息,则开发板启动成功。
printf("hello world!!\r\n");
适配printf输出到串口,只需要重写_write函数即可,参考如下:
#include <stdio.h>
int _write(int fd, char *ptr, int len)
{
return HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 0xFFFF);
}
重新编译代码,将其烧录至开发板中验证。
编译构建
目录规划
芯片适配目录规划为:
device
├── board --- 单板厂商目录
│ └── talkweb --- 单板厂商名字:拓维信息
│ └── niobe407 --- 单板名:与产品名一致
└── soc --- SoC厂商目录
└── st --- SoC厂商名称
└── stm32f4xx --- SoC Series名:stm32f4xx是一个系列,包含该系列soc相关代码
产品样例目录规划为:
vendor
└── talkweb --- 开发产品样例厂商目录
└── niobe407 --- 产品名字:niobe407
获取OpenHarmony源码,根据上述目录规划,创建相应文件夹。
预编译适配
预编译适配内容就是围绕hb set
命令的适配,使工程能够通过该命令设置根目录、单板目录、产品目录、单板公司名等环境变量,为后续适配编译做准备。
具体的预编译适配步骤如下:
- 在
vendor/talkweb/niobe407
目录下新增config.json
文件,用于描述这个产品样例所使用的单板、内核等信息,描述信息可参考如下内容:
{
"product_name": "niobe407", --- 用于hb set进行选择时,显示的产品名称
"type": "mini", --- 构建系统的类型,mini/small/standard
"version": "3.0", --- 构建系统的版本,1.0/2.0/3.0
"device_company": "talkweb", --- 单板厂商名,用于编译时找到/device/board/talkweb目录
"board": "niobe407", --- 单板名,用于编译时找到/device/board/talkweb/niobe407目录
"kernel_type": "liteos_m", --- 内核类型,因为OpenHarmony支持多内核,一块单板可能适配了多个内核,所以需要指定某个内核进行编译
"kernel_version": "3.0.0", --- 内核版本,一块单板可能适配了多个linux内核版本,所以需要指定某个具体的内核版本进行编译
"subsystems": [ ] --- 选择所需要编译构建的子系统
}
- 在
//device/board/talkweb/niobe407
目录下创建board
目录,在创建的目录下新增一个config.gni
文件,用于描述该产品的编译配置信息:
# Kernel type, e.g. "linux", "liteos_a", "liteos_m".
kernel_type = "liteos_m" --- 内核类型,跟config.json中kernel_type对应
# Kernel version.
kernel_version = "3.0.0" --- 内核版本,跟config.json中kernel_version对应
- 验证
hb set
配置是否正确,输入hb set
能够显示如下信息:
- 通过
hb env
可以查看选择出来的预编译环境变量:
-
hb介绍
hb
是OpenHarmony为了方便开发者进行代码构建编译,提供的python脚本工具,其源码就在//build/lite
仓库目录下。在执行hb set
命令时,脚本会遍历//vendor/<product_company>/<product_name>
目录下的config.json
,给出可选产品编译选项。在config.json文件中,product_name
表示产品名,device_company
和board
用于关联出//device/board/<device_company>/<board>
目录,匹配该目录下的<any_dir_name>/config.gni
文件,其中<any_dir_name>
目录名可以是任意名称,但建议将其命名为适配内核名称(如:liteos_m、liteos_a、linux)。hb命令如果匹配到了多个config.gni
,会将其中的kernel_type
和kernel_version
字段与vendor/<device_company>
下config.json
文件中的字段进行匹配,从而确定参与编译的config.gni
文件。
至此,预编译适配完成,但工程还不能执行hb build
进行编译,还需要准备好后续的LiteOS-M
内核移植。
内核移植
内核移植需要完成LiteOS-M Kconfig
适配、gn
的编译构建和内核启动最小适配。
Kconfig文件适配
-
在
//vendor/talkweb/niobe407
目录下创建kernel_configs目录,并创建空文件,命名为debug.config。 -
打开
//kernel/liteos_m/Kconfig
文件,可以看到在该文件通过orsource命令导入了//device/board
和//device/soc
下多个Kconfig文件,后续需要创建并修改这些文件:
orsource "../../device/board/*/Kconfig.liteos_m.shields"
orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.defconfig.boards"
orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.boards"
orsource "../../device/soc/*/Kconfig.liteos_m.defconfig"
orsource "../../device/soc/*/Kconfig.liteos_m.series"
orsource "../../device/soc/*/Kconfig.liteos_m.soc"
- 在
//device/board/talkweb
下参考如下目录结构创建相应的Kconfig文件:
.
├── Kconfig.liteos_m.boards
├── Kconfig.liteos_m.defconfig.boards
├── Kconfig.liteos_m.shields
└── niobe407
├── Kconfig.liteos_m.board --- 开发板配置选项
├── Kconfig.liteos_m.defconfig.board --- 开发板默认配置选项
└── liteos_m
└── config.gni
-
修改
Kconfig
文件内容:-
在
//device/board/talkweb/Kconfig.liteos_m.boards
文件中添加:if SOC_STM32F407 orsource "niobe407/Kconfig.liteos_m.board" --- 可根据SOC定义,加载指定board目录定义 endif
-
在
//device/board/talkweb/Kconfig.liteos_m.defconfig.boards
文件中添加:orsource "*/Kconfig.liteos_m.defconfig.board"
-
在
//device/board/talkweb/Kconfig.liteos_m.defconfig.boards
文件中添加:orsource "shields/Kconfig.liteos_m.shields"
-
在
//device/board/talkweb/niobe407/Kconfig.liteos_m.board
文件中添加:menuconfig BOARD_NIOBE407 bool "select board niobe407" depends on SOC_STM32F407 --- niobe407使用的是stm32f407的SoC,只有SoC被选择后,niobe407的配置选项才可见、可以被选择。
-
在
//device/board/talkweb/niobe407/Kconfig.liteos_m.defconfig.board
中添加:if BOARD_NIOBE407 --- 用于添加BOARD_NIOBE407默认配置 endif #BOARD_NIOBE407
-
-
在
//device/soc/st
下参考如下目录结构创建相应的Kconfig文件,并将stm32cubemx
自动生成工程中的Drivers目录拷贝至stm32f4xx/sdk
目录下:. ├── Kconfig.liteos_m.defconfig ├── Kconfig.liteos_m.series ├── Kconfig.liteos_m.soc └── stm32f4xx ├── Kconfig.liteos_m.defconfig.series ├── Kconfig.liteos_m.defconfig.stm32f4xx ├── Kconfig.liteos_m.series ├── Kconfig.liteos_m.soc └── sdk └── Drivers ├── CMSIS └── STM3