
OpenHarmony设备开发 轻量带屏解决方案之恒玄芯片移植案例
本文章基于恒玄科技BES2600W
芯片的欧智通Multi-modal V200Z-R开发板,进行轻量带屏开发板的标准移植,开发了智能开关面板样例,同时实现了ace_engine_lite
、graphic_ui
、aafwk_lite
、appexecfwk_lite
、HDF
等部件基于OpenHarmony LiteOS-M
内核的适配。移植架构上采用Board
与SoC
分离的方案,工具链Newlib C
库与Musl C
库可选,LiteOS-M
内核编译采用gn
结合Kconfig
图形化配置等需求。
编译构建
目录规划
本案例在芯片移植架构方面进行了一些改进,以前的芯片适配目录规划为:
这样会导致,小熊派BearPi-HM Nano
开发板与润和的HiSpark Pegasus
开发板使用小海思的hi3861
的SoC
时,需要在这两款开发板里面都放置一份重复的代码。为了解决该问题,本案例将单板厂商与SoC
厂商进行分离,可以参考Board和SoC解耦的设计思路,并把芯片适配目录规划为:
产品样例目录规划为:
预编译适配
在进行移植之前,需要进行预编译适配。
预编译适配主要使用hb set
命令,设置整个项目的根目录、单板目录、产品目录、单板公司名等环境变量,为编译做准备。
具体的预编译适配步骤如下:
- 在
vendor/bestechnic/display_demo
目录下新增config.json
文件,用于描述这个产品样例所使用的单板、内核等信息,描述信息可参考如下内容:
- 在
device/board/fnlink/v200zr/liteos_m
目录下新增config.gni
文件,用于描述这个产品样例所使用的单板、内核等信息,描述信息可参考如下内容:
- 验证
hb set
配置是否正确,输入hb set
能够显示如下图片表示配置正确。执行hb set
输入项目根目录,并且回车,hb
命令会遍历所有//vendor/<product_company>/<product_name>
目录下的config.json
,给出可选产品编译选项,config.json
的product_name
用于显示产品名,device_company
和board
用于关联出//device/board/<device_company>/<board>
目录,并且匹配<any_dir_name>/config.gni
文件,如果能够匹配多个文件,表示该单板适配了多个内核,那么可以根据config.json
的kernel_type
和kernel_version
来唯一匹配config.gni
的kernel_type
和kernel_version
,即可确定了需要编译适配了哪个内核的单板。
在执行hb build
之前,需要准备好LiteOS-M
内核适配,具体适配步骤请参内核移植。
内核移植
内核移植需要完成LiteOS-M Kconfig
适配、gn
的编译构建和内核启动最小适配。
LiteOS-M Kconfig适配
在//kernel/liteos_m
目录下执行make menuconfig
命令,完成编译配置选项的选择。在Makefile
文件中,会将hb env
的结果转换成环境变量,即PRODUCT_PATH
、DEVICE_PATH
和BOARD_COMPANY
。如下代码块所示:
在//kernel/liteos_m/Kconfig
文件中使用这些导出的环境变量,Kconfiglib
采用ulfalizer
开发基于python
的版本,源码地址,功能介绍连接参考,里面用到了orsource
关键字,其中o
表示optional
,表示这个文件是否存在可选,r
表示relative
,表示这个文件相对当前文件的相对路径。
从//kernel/liteos_m/Kconfig
文件可以看出需要在//device/board/fnlink
目录下新增如下Kconfig
文件进行适配:
在 v200zr/Kconfig.liteos_m.board
需要配置选择该单板的选项,以及它依赖的SoC
,如下:
在 v200zr/Kconfig.liteos_m.defconfig.board
需要配置选择该单板后,默认定义 BOARD
的名字为 "v200zr"
,如下:
从//kernel/liteos_m/Kconfig
文件可以看出需要在//device/soc/bestechnic
目录下新增如下Kconfig
文件进行适配:
在 bes2600/Kconfig.liteos_m.series
需要配置bes2600 SoC series
,以及它的芯片架构等信息,如下:
在 bes2600/Kconfig.liteos_m.soc
需要提供bes2600 SoC series
下有多少个具体的SoC
可供选择,如下:
在 bes2600/Kconfig.liteos_m.defconfig.series
需要提供bes2600 SoC series
选择后的默认配置,如下:
配置完成后,还需要根据 kernel/liteos_m/Makefile
文件配置make menuconfig
的defconfig
保存路径:
在这个例子中,defconfig
配置路径为 $(PRODUCT_PATH)/kernel_configs/debug.config
,创建该文件后,内容为空,产品的目录文件结构如下:
配置完成后,在 kernel/liteos_m
目录下执行 make menuconfig
能够对SoC Series
/SoC
/Board
进行选择,如下:
结果将自动保存在$(PRODUCT_PATH)/kernel_configs/debug.config
,下次执行make menuconfig
时会导出保存的结果。
gn编译适配
在上一步Kconfig
的图形化配置后,将其生成的配置结果可以作为gn
编译的输入,以控制不同模块是否编译。另外为了解决之前gn
编写时,随意include的问题,内核编译做了模块化编译的设计,使得整个编译逻辑更加清晰,设计思路请参考LiteOS-M内核BUILD.gn编写指南。
在 kernel/liteos_m/BUILD.gn
中,指定了Board
和SoC
的编译入口为//device/board/fnlink
和//device/soc/bestechnic
。
在//device/board/fnlink/BUILD.gn
中,新增内容如下:
同理//device/soc/bestechnic/BUILD.gn
也是一样。
内核启动适配
系统启动流程分为三个阶段:
阶段名称 | 分区规划 | 描述 |
BOOT1 | [0, 0x10000] | 第一阶段启动,进行固件启动 |
BOOT2 | [0x2C010000, 0x2C020000] | 第二阶段启动,进行OTA升级启动 |
RTOS_MAIN | [0x2C080000, 0x2C860000] | 第三阶段启动,进行内核启动 |
在第三阶段内核启动中,需要适配的文件路径在 //device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/rtos/liteos/liteos_m/board.c
内核启动适配总体思路如下:
- 中断向量的初始化
os_vector_init
,初始化中断的处理函数。 - 内核初始化
osKernelInitialize
。 - 创建线程
board_main
,进行芯片平台初始化。 - 内核启动,开始调度线程
osKernelStart
。
其中,本章节详细对第3步进行展开,其他几步为对内核函数调用,不作详细描述。
第3步中board_main
在启动OHOS_SystemInit
之前,需要初始化必要的动作,如下:
OhosSystemAdapterHooks
函数在device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c
文件中,如下:
littlefs文件系统移植
V200Z-R
开发板开发板采用最大32MB
的支持XIP
的Nor Flash
,文件系统可以使用example
,适配过程中,需要在指定路径下放置文件系统预置文件,根据配置可自动生成文件系统镜像,可以实现自动化生成和打包到烧录包中。
- 配置指定目录放置打包文件系统
config.json
,通过flash_partition_dir
指定目录: - 在指定目录
vendor/bestechnic/display_demo/fs
下放置两部分内容:
-
wifi_Download_cfg.yaml
:镜像的烧录配置文件,可以根据实际情况调整分区。 -
/data/data
:第一个/data
是挂载的根目录;第二个data
是根目录里面的data
目录,里面可以存放预置文件,或者在第二个data
的同级目录再创建一个目录,打包的时候只认第一个data
挂载根目录。
-
config.json
中根据wifi_Download_cfg.yaml
最后调整结果。
-
fs_src
配置文件系统挂载名字。 -
fs_name
是最后生成文件系统的名字。 -
block_size
配置成4K
对齐,建议不修改。 -
fs_size
是生成文件系统的大小。 -
burn_name
是烧录bin
名字的大小。 -
enable
表示是否生成这个文件系统
- 在
//device/soc/bestechnic/bes2600/liteos_m/components/hdf_config/hdf.hcs
文件配置文件系统的烧录的起始地址、文件系统的大小以及读数据块的大小block_size
等信息,参考配置如下:
最后在device/soc/bestechnic/bes2600/liteos_m/components/fs/fs_init.c
中,通过hdf
加载数据,进行读写flash
,如下:
C库适配
在轻量系统中,C库适配比较复杂,设计思路请参考LiteOS-M内核支持musl与newlib平滑切换方案,由于我们的工具链采用 gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 自带newlib
的C库,那么系统移植整体采用newlib
的C库。那么在内核的make menuconfig
中选择newlib
,如下图:
malloc适配
malloc适配参考The Red Hat newlib C Library-malloc。实现malloc适配有以下两种方法:
- 实现
_sbrk_r
函数。这种方法中,内存分配函数使用newlib
中的。 - 实现
_malloc_r
,_realloc_r
,_reallocf_r
,_free_r
,_memalign_r
, 和_malloc_usable_size_r
。这种方法中,内存分配函数可以使用内核的。
为了方便地根据业务进行内存分配算法调优和问题定位,在这两种方法中,本案例选择后者。
首先,由于newlib
中已经存在这些函数的符号,因此需要用到gcc
的wrap
的链接选项替换这些函数符号为内核的实现,内核的实现为 //kernel/liteos_m/kal/libc/newlib/porting/src/malloc.c
。
然后,在//device/board/fnlink/v200zr/liteos_m/config.gni
的新增这些函数的wrap
链接选项。
vsprintf等适配
参考 https://sourceware.org/newlib/libc.html#vfprintf ,实现 vprintf
, vfprintf
, printf
, snprintf
和sprintf
。
类似malloc
适配,首先要提供这些函数的实现,//device/soc/bestechnic/bes2600/liteos_m/components/utils/src/printf.c
,本案例直接采用开源协议友好的实现。与malloc
适配不同的是,这个函数由芯片原厂提供。因为就打印来说,根据项目的需要,实现可大可小,内核不方便提供统一的实现。
然后,在//device/board/fnlink/v200zr/liteos_m/config.gni
的新增这些函数的wrap链接选项。
open等适配
这部分实现由内核统一实现,芯片适配无须关注,内核文件//kernel/liteos_m/kal/libc/newlib/porting/src/fs.c
,适配了newlib
的_read
、_write
等函数,如下:
板级系统移植
驱动移植
SoC芯片平台HDF驱动移植
驱动适配相关文件放置在drivers/adapter/platform
中,对应有gpio
,i2c
,pwm
,spi
,uart
,watchdog
,都是通过HDF
机制加载,本章节以gpio
为例进行详细说明。
GPIO驱动适配
gpio
驱动适配需要完成编译的适配、源码的适配。
在//drivers/adapter/platform/gpio/BUILD.gn
文件中,描述了恒玄gpio
驱动的编译适配。如下:
在//drivers/adapter/platform/gpio/gpio_bes.c
文件中,描述了恒玄gpio
驱动的源码适配。 首先,按照OpenHarmony
的HDF
驱动框架加载驱动基本适配框架,如下:
然后,在初始化的时候会获取hcs
参数进行初始化,如下:
编码规范和设计思想见bes 驱动适配PR的评论。
Board外设器件HDF驱动移植
Board
外设器件表示通过SoC
平台总线连接的外设器件,在本案例中,显示屏属于外设器件,其驱动适配放在//device/board/fnlink/drivers/liteos_m
目录中。
显示驱动适配
同SoC
驱动适配,在//device/board/fnlink/drivers/liteos_m/display/BUILD.gn
文件中,根据hdf_driver
模板加载驱动模块,如下:
在//device/board/fnlink/drivers/liteos_m/display/zzw395.c
文件中,根据驱动框架加载显示驱动,如下:
其中的驱动参数根据hcs
配置,在PanelDriverInit
初始化时加载,如下:
OpenHarmony子系统适配
OpenHarmony
子系统适配一般包含两部分:
- 在
config.json
中增加对应子系统和部件,这样编译系统会将该部件纳入编译目标中。 - 针对该部件的
HAL
层接口进行硬件适配,或者可选的软件功能适配。
分布式软总线子系统适配
wifi_lite部件适配
首先,在config.json
文件中,增加communication
子系统的wifi_lite
部件,如下:
wifi_lite
部件在//build/lite/components/communication.json
文件中,描述如下:
在//foundation/communication/wifi_lite/BUILD.gn
文件中,描述需要适配的接口头文件路径,如下:
因为在本案例中,wifi
属于SoC
提供的功能,所以适配源码放在SoC
的//device/soc/bestechnic/hals/communication/wifi_lite/wifiservice
目录下,包含wifi_device.c
和wifi_hotspot.c
分别适配wifi_device.h
和wifi_hotspot.h
。如下:
LWIP部件适配
LiteOS-M kernel
目录下默认配置了lwip
,因而具有编译功能,可以在kernel
组件中指定lwip
编译的目录。如下:
在//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/BUILD.gn
文件中,描述了lwip
的编译,如下:
在//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/porting/include/lwip/lwipopts.h
文件中,说明原有lwip
配置选项保持不变,软总线会依赖这些配置选项,并且新增硬件适配的配置项,如下:
在//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/porting/src/ethernetif.c
文件中,说明对ethernet
网卡初始化的适配,如下:
dsoftbus部件适配
在config.json
中增加dsoftbus
部件配置如下:
dsoftbus
部件在//foundation/communication/dsoftbus/dsoftbus.gni
文件中提供了softbus_adapter_config
配置选项可供移植过程进行配置,该配置设定了软总线移植适配的路径。
在本案例中,softbus_adapter_config
配置为//vendor/bestechnic/mini_distributed_music_player/dsoftbus_lite_config
路径,该路径下的内容为:
在config.gni
文件中规定了以下配置项:
配置项 | 描述 |
dsoftbus_feature_disc_ble | 是否开启BLE发现功能 |
dsoftbus_feature_disc_coap | 是否开启COAP发现功能 |
dsoftbus_feature_conn_tcp | 是否开启TCP连接功能 |
dsoftbus_feature_conn_br | 是否开启BR连接功能 |
dsoftbus_feature_conn_ble | 是否开启BLE连接功能 |
dsoftbus_feature_conn_p2p | 是否开启P2P连接功能 |
dsoftbus_feature_trans_udp | 是否开启UDP传输功能 |
dsoftbus_feature_trans_udp_stream | 是否开启UDP传输流功能 |
dsoftbus_feature_trans_udp_file | 是否开启UDP传输文件功能 |
dsoftbus_feature_ip_auth | 是否开启认证传输通道功能 |
dsoftbus_feature_auth_account | 是否开启基于账号认证功能 |
dsoftbus_feature_qos | 是否开启QoS功能 |
在softbus_config_adapter.c
文件中规定了以下配置项:
配置项 | 描述 |
SOFTBUS_INT_MAX_BYTES_LENGTH | SendBytes发送最大Bytes长度 |
SOFTBUS_INT_MAX_MESSAGE_LENGTH | SendMessage发送最大消息的长度 |
SOFTBUS_INT_CONN_BR_MAX_DATA_LENGTH | 蓝牙最大接收数据量 |
SOFTBUS_INT_CONN_RFCOM_SEND_MAX_LEN | 蓝牙最大接收数据量 |
SOFTBUS_INT_ADAPTER_LOG_LEVEL | 日志级别设置 |
SOFTBUS_STR_STORAGE_DIRECTORY | 存储目录设置 |
因为软总线配置了后,不会默认启动,所以需要在通过启动框架调用InitSoftBusServer
函数,如下:
RPC部件适配
在config.json
中增加rpc
部件配置如下:
同样地,rpc
部件需要通过启动框架调用StartDBinderService
函数,由于该函数正常运行依赖主机已经获取IP
地址,因此在LWIP
协议栈注册IP
地址变化事件的回调函数中调用该函数,如下:
启动恢复子系统适配
启动恢复子系统适配bootstrap_lite
/syspara_lite
两个部件。请在vendor/bestechnic_bak/display_demo/config.json
中新增对应的配置选项。
适配bootstrap_lite
部件时,需要在连接脚本文件//device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/out/best2600w_liteos/_best2001.lds
中手动新增如下段:
需要新增上述段是因为bootstrap_init
提供的对外接口,见//utils/native/lite/include/ohos_init.h
文件,采用的是灌段的形式,最终会保存到上述链接段中。主要的服务自动初始化宏如下表格所示:
接口名 | 描述 |
SYS_SERVICE_INIT(func) | 标识核心系统服务的初始化启动入口 |
SYS_FEATURE_INIT(func) | 标识核心系统功能的初始化启动入口 |
APP_SERVICE_INIT(func) | 标识应用层服务的初始化启动入口 |
APP_FEATURE_INIT(func) | 标识应用层功能的初始化启动入口 |
说明: 通过上面加载的组件编译出来的lib文件需要手动加入强制链接。
如在 vendor/bestechnic/display_demo/config.json
中配置了bootstrap_lite
部件
bootstrap_lite
部件会编译//base/startup/bootstrap_lite/services/source/bootstrap_service.c
,该文件中,通过SYS_SERVICE_INIT
将Init
函数符号灌段到__zinitcall_sys_service_start
和__zinitcall_sys_service_end
中,由于Init
函数是没有显式调用它,所以需要将它强制链接到最终的镜像。如下:
在//base/startup/bootstrap_lite/services/source/BUILD.gn
文件中,描述了在out/v200zr/display_demo/libs
生成 libbootstrap.a
,如下:
那么需要在 vendor/bestechnic/display_demo/config.json
配置强制链接库bootstrap
,如下:
适配syspara_lite
部件时,系统参数会最终写到文件中进行持久化保存。在轻量系统中,文件操作相关接口有POSIX
接口与HalFiles
接口这两套实现。
因为对接内核的文件系统,采用POSIX
相关的接口,所以features
字段中需要增加enable_ohos_startup_syspara_lite_use_posix_file_api = true
。
如果对接HalFiles
相关的接口实现的,则无须修改。
在适配GetSerial
接口时,开发板不像产线生产过程那样,会写入一个具体的Serial Number
,因而需要确定一个数据对开发板进行唯一标识。本案例采用WiFi Mac
地址进行适配。
DFX子系统适配
进行DFX
子系统适配需要添加hilog_lite
部件,直接在config.json
文件配置即可。
配置完成之后,在//device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c
中注册日志输出实现函数。
系统服务管理子系统适配
进行系统服务管理子系统适配需要添加samgr_lite
部件,直接在config.json
配置即可。
在轻量系统中,samgr_lite
配置的共享任务栈大小默认为0x800
。当函数调用栈较大时,会出现栈溢出的问题。在本次适配过程中,将其调整为0x1000
。
安全子系统适配
进行安全子系统适配需要添加huks/deviceauth_lite
部件,直接在config.json
配置即可。
huks
部件适配时,huks_key_store_path
配置选项用于指定存放秘钥路径,ohos_security_huks_mbedtls_porting_path
配置选项用于指定进行mbedtls
适配的目录,用于芯片对mbedtls
进行硬件随机数等适配。
deviceauth_lite
部件适配时,deviceauth_storage_path
配置选项用于指定存放设备认证信息的路径,deviceauth_hichain_thread_stack_size
用于指定线程栈大小。
媒体子系统适配
进行媒体子系统适配需要添加histreamer
部件,直接在config.json
配置即可。
histreamer
部件配置项说明如下:
配置项 | 说明 |
multimedia_histreamer_enable_plugin_hdi_adapter | 是否使能histreamer对接到hdi接口 |
multimedia_histreamer_enable_plugin_minimp3_adapter | 是否使能插件适配minimp3 |
multimedia_histreamer_enable_plugin_ffmpeg_adapter | 是否使能插件适配FFmpeg |
config_ohos_multimedia_histreamer_stack_size | histreamer栈大小设置 |
公共基础库子系统适配
进行公共基础库子系统适配需要添加kv_store
/js_builtin
/timer_task
/kal_timer
部件,直接在config.json
配置即可。
与适配syspara_lite
部件类似,适配kv_store
部件时,键值对会写到文件中。在轻量系统中,文件操作相关接口有POSIX
接口与HalFiles
接口这两套实现。因为对接内核的文件系统,采用POSIX
相关的接口,所以features
需要增加enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true
。如果对接HalFiles
相关的接口实现的,则无须修改。
图形子系统适配
进行图形子系统适配需要添加graphic_utils
部件,直接在config.json
配置即可。
graphic
配置文件见 //vendor/bestechnic/display_demo/graphic_config/product_graphic_lite_config.h
。
graphic
适配见//device/soc/bestechnic/bes2600/liteos_m/components/ui
, 主要功能如下:
-
display_device
:实例化BaseGfxEngine
。 -
touch_input
:实例化PointerInputDevice
。 -
UiMainTask
:初始化字体引擎,执行渲染任务等。
图形子系统层次:
图形应用示例见文件//vendor/bestechnic/display_demo/tests/app.cpp
,如下:
ACE开发框架子系统适配
进行ACE
开发框架子系统适配需要添加ace_engine_lite
部件,直接在config.json
配置即可。
ace_engine_lite
部件配置文件见 //vendor/bestechnic/display_demo/ace_lite_config/product_acelite_config.h
。
ace_lite
的应用采用js语言进行开发,详细步骤如下:
- 用
DevEco Studio
编写js应用,参考轻量级智能穿戴开发。 - 使用预览功能进行预览,并且得到js包:
entry\.preview\intermediates\res\debug\lite\assets\js\default
。 - 将js包放到对应的文件系统目录下,文件系统路径为
vendor/bestechnic/display_demo/fs/data/data/js
,如下:
- 最终编译生成系统镜像,烧录到单板后,系统会从
app.js
加载启动ace
的应用。
元能力子系统适配
进行元能力子系统适配需要添加aafwk_lite
部件,直接在config.json
配置即可。
aafwk_lite
相关的应用样例见vendor/bestechnic/display_demo/tests/ability
目录,包含launcher
和js app
这两类应用,应用的函数调用流程描述如下:
-
launcher
应用,通过InstallLauncher
安装BundleName
为"com.example.launcher"
的native ui
应用,在AbilityMgrSliteFeature
启动后会调用AbilityMgrHandler::StartLauncher()
启动launcher
应用。 -
StartJSApp
应用,通过StartAbility
启动任意Want
,通过将want data
传递JS_APP_PATH
,SetWantData(&want, JS_APP_PATH, strlen(JS_APP_PATH) + 1)
。
包管理子系统适配
进行包管理子系统适配需要添加appexecfwk_lite
部件,直接在config.json
配置即可。
兼容性认证
产品兼容性规范
产品兼容性规范文档请参考产品兼容性SIG介绍。
XTS用例
XTS
测试参考资料见xts参考资料,进行XTS
子系统适配需要添加xts_acts
/xts_tools
部件,直接在config.json
配置即可,配置如下:
其中,
-
config_ohos_xts_acts_utils_lite_kv_store_data_path
是配置挂载文件系统根目录的名字。 -
enable_ohos_test_xts_acts_use_thirdparty_lwip
表示如果使用thirdparty/lwip
目录下的源码编译,则设置为true
,否则设置为false
。
全部跑完会有显示xx Tests xx Failures xx Ignored
,如下:
报告提交
将上图XTS
用例的情况保存为测试报告,上传到OpenHarmony
兼容性测试网站进行认证,作为sig
仓库转正到master
仓库的必要条件。详细步骤如下:
步骤1:将XTS
测试报告压缩成zip
文件。
步骤2:生成测试报告的SHA
校验码。本案例是将zip
文件传到在线生成hash
的网站生成SHA
校验码。
步骤3:进入OpenHarmony
兼容性测试网站上传报告。
- 其中
API Level
填写报告中的"sdkApiLevel"
字段 -
OS
版本号填写报告中的"OS Version"
字段。
todo
后续会补充以下方面的移植:
- 蓝牙
-
bms
包安装 - 验证运行
JS
的bytecode
- 分布式能力:
dms
、dm
- 分布式音乐播放器样例
porting-bes2600w-on-minisystem-display-demo.md
