• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 轻量系统STM32F407芯片移植案例
2
3介绍基于`STM32F407IGT6`芯片在拓维信息[Niobe407](https://gitee.com/openharmony-sig/device_board_talkweb)开发板上移植OpenHarmony LiteOS-M轻量系统,提供交通、工业领域开发板解决方案。移植架构采用`Board`与`SoC`分离方案,使用`arm gcc`工具链`Newlib C`库,实现了`lwip`、`littlefs`、`hdf`等子系统及组件的适配,开发了配套应用示例代码,支持通过Kconfig图形化配置编译选项。
4
5## 适配准备
6
7- 下载[stm32cubemx](https://www.st.com/en/development-tools/stm32cubemx.html)图形工具。
8- 准备ubuntu20.04系统环境,安装[arm-none-eabi-gcc](https://gitee.com/openharmony/device_board_talkweb/blob/master/niobe407/docs/software/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E4%B8%8E%E5%9B%BA%E4%BB%B6%E7%BC%96%E8%AF%91.md#6%E5%AE%89%E8%A3%85%E4%BA%A4%E5%8F%89%E7%BC%96%E8%AF%91%E5%B7%A5%E5%85%B7%E9%93%BE)交叉编译工具链。
9### 生成可用工程
10
11通过stm32cubemx工具生成`STM32F407IGT6`芯片的Makefile工程,在此给出如下配置建议:
12
13- 系统相关配置采用默认配置。
14- 时钟配置时将SYSCLK选项配置为168MHz,发挥芯片最强性能。
15- 配置USART1用作调试串口,用来打印适配过程中的调试信息。
16- 配置stm32cubemx工程选项时,将Toolchain/IDE选项选为Makefile。
17
18生成的工程目录如下:
19
20```
21├── Core
22│   ├── Inc
23│   │    ├── main.h
24│   │    ├── stm32f4xx_hal_conf.h
25│   │    └── stm32f4xx_it.h
26│   └── Src
27│        ├── main.c                --- 主函数
28│        ├── stm32f4xx_hal_msp.c   --- HAL库弱函数配置文件
29│        ├── stm32f4xx_it.c        --- 中断回调函数文件
30│        └── system_stm32f4xx.c    --- 系统
31├── Drivers
32│   ├── CMSIS                      --- CMSIS接口
33│   └── STM32F4xx_HAL_Driver       --- HAL库驱动
34├── Makefile                       --- Makefile编译
35├── STM32F407IGTx_FLASH.ld         --- 链接文件
36├── startup_stm32f407xx.s          --- 启动文件
37└── stm32f407_output.ioc           --- stm32cubemx工程文件
38```
39
40### 验证生成的工程
41
42将生成的工程拷贝至Ubuntu,进入工程目录下执行make命令编译,确定能够编译成功。
43
44```
45arm-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
46arm-none-eabi-size build/stm32f407_output.elf
47   text    data     bss     dec     hex filename
48   5000      20    1636    6656    1a00 build/stm32f407_output.elf
49arm-none-eabi-objcopy -O ihex build/stm32f407_output.elf build/stm32f407_output.hex
50arm-none-eabi-objcopy -O binary -S build/stm32f407_output.elf build/stm32f407_output.bin
51```
52
53编译完成会生成一个.bin文件,为了确认该程序能在开发板中成功运行,需要main函数中的串口初始化之后,通过串口输出一段字符串,运行时若收到打印信息,则开发板启动成功。
54```
55printf("hello world!!\r\n");
56```
57
58适配printf输出到串口,只需要重写_write函数即可,参考如下:
59
60```c
61#include <stdio.h>
62
63int _write(int fd, char *ptr, int len)
64{
65      return HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 0xFFFF);
66}
67```
68重新编译代码,将其烧录至开发板中验证。
69
70## 编译构建
71### 目录规划
72
73芯片适配目录规划为:
74
75```
76device
77├── board                                --- 单板厂商目录
78│   └── talkweb                          --- 单板厂商名字:拓维信息
79│       └── niobe407                     --- 单板名:与产品名一致
80└── soc									 --- SoC厂商目录
81    └── st                               --- SoC厂商名称
82        └── stm32f4xx					 --- SoC Series名:stm32f4xx是一个系列,包含该系列soc相关代码
83```
84
85产品样例目录规划为:
86
87```
88vendor
89└── talkweb							     --- 开发产品样例厂商目录
90    └── niobe407         			     --- 产品名字:niobe407
91```
92
93获取[OpenHarmony源码](../get-code/sourcecode-acquire.md),根据上述目录规划,创建相应文件夹。
94
95### 预编译适配
96
97预编译适配内容就是围绕`hb set`命令的适配,使工程能够通过该命令设置根目录、单板目录、产品目录、单板公司名等环境变量,为后续适配编译做准备。
98
99具体的预编译适配步骤如下:
100
1011. 在`vendor/talkweb/niobe407`目录下新增`config.json`文件,用于描述这个产品样例所使用的单板、内核等信息,描述信息可参考如下内容:
102
103   ```
104   {
105     "product_name": "niobe407",           --- 用于hb set进行选择时,显示的产品名称
106     "type": "mini",                       --- 构建系统的类型,mini/small/standard
107     "version": "3.0",                     --- 构建系统的版本,1.0/2.0/3.0
108     "device_company": "talkweb",          --- 单板厂商名,用于编译时找到/device/board/talkweb目录
109     "board": "niobe407",                  --- 单板名,用于编译时找到/device/board/talkweb/niobe407目录
110     "kernel_type": "liteos_m",            --- 内核类型,因为OpenHarmony支持多内核,一块单板可能适配了多个内核,所以需要指定某个内核进行编译
111     "kernel_version": "3.0.0",            --- 内核版本,一块单板可能适配了多个linux内核版本,所以需要指定某个具体的内核版本进行编译
112     "subsystems": [ ]                     --- 选择所需要编译构建的子系统
113   }
114   ```
115
1162. 在`//device/board/talkweb/niobe407`目录下创建`board`目录,在创建的目录下新增一个`config.gni`文件,用于描述该产品的编译配置信息:
117
118   ```
119   # Kernel type, e.g. "linux", "liteos_a", "liteos_m".
120   kernel_type = "liteos_m"                --- 内核类型,跟config.json中kernel_type对应
121
122   # Kernel version.
123   kernel_version = "3.0.0"                --- 内核版本,跟config.json中kernel_version对应
124   ```
125
1263. 验证`hb set`配置是否正确,输入`hb set`能够显示如下信息:
127
128   ![hb set](figures/niobe407_hb_set.png)
129
1304. 通过`hb env`可以查看选择出来的预编译环境变量:
131
132   ![hb env](figures/niobe407_hb_env.png)
133
1345. hb介绍。
135
136   `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`文件。
137
138至此,预编译适配完成,但工程还不能执行`hb build`进行编译,还需要准备好后续的`LiteOS-M`内核移植。
139
140## 内核移植
141
142内核移植需要完成`LiteOS-M Kconfig`适配、`gn`的编译构建和内核启动最小适配。
143
144### Kconfig文件适配
145
1461. 在`//vendor/talkweb/niobe407`目录下创建kernel_configs目录,并创建空文件,命名为debug.config147
1482. 打开`//kernel/liteos_m/Kconfig`文件,可以看到在该文件通过orsource命令导入了`//device/board`和`//device/soc`下多个Kconfig文件,后续需要创建并修改这些文件:
149
150   ```
151   orsource "../../device/board/*/Kconfig.liteos_m.shields"
152   orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.defconfig.boards"
153   orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.boards"
154   orsource "../../device/soc/*/Kconfig.liteos_m.defconfig"
155   orsource "../../device/soc/*/Kconfig.liteos_m.series"
156   orsource "../../device/soc/*/Kconfig.liteos_m.soc"
157   ```
158
1593. 在`//device/board/talkweb`下参考如下目录结构创建相应的Kconfig文件:
160
161   ```
162   .
163   ├── Kconfig.liteos_m.boards
164   ├── Kconfig.liteos_m.defconfig.boards
165   ├── Kconfig.liteos_m.shields
166   └── niobe407
167       ├── Kconfig.liteos_m.board                --- 开发板配置选项
168       ├── Kconfig.liteos_m.defconfig.board      --- 开发板默认配置选项
169       └── liteos_m
170           └── config.gni
171   ```
172
1734. 修改`Kconfig`文件内容:
174
175   - 在`//device/board/talkweb/Kconfig.liteos_m.boards`文件中添加:
176
177     ```
178     if SOC_STM32F407
179            orsource "niobe407/Kconfig.liteos_m.board"    --- 可根据SOC定义,加载指定board目录定义
180     endif
181     ```
182
183   - 在`//device/board/talkweb/Kconfig.liteos_m.defconfig.boards`文件中添加:
184
185     ```
186     orsource "*/Kconfig.liteos_m.defconfig.board"
187     ```
188
189   - 在`//device/board/talkweb/Kconfig.liteos_m.defconfig.boards`文件中添加:
190
191     ```
192     orsource "shields/Kconfig.liteos_m.shields"
193     ```
194
195   - 在`//device/board/talkweb/niobe407/Kconfig.liteos_m.board`文件中添加:
196
197     ```
198     menuconfig BOARD_NIOBE407
199         bool "select board niobe407"
200         depends on SOC_STM32F407	 --- niobe407使用的是stm32f407的SoC,只有SoC被选择后,niobe407的配置选项才可见、可以被选择。
201     ```
202
203   - 在`//device/board/talkweb/niobe407/Kconfig.liteos_m.defconfig.board`中添加:
204
205     ```
206     if BOARD_NIOBE407
207         							 --- 用于添加BOARD_NIOBE407默认配置
208     endif #BOARD_NIOBE407
209     ```
210
2115. 在`//device/soc/st`下参考如下目录结构创建相应的Kconfig文件,并将`stm32cubemx`自动生成工程中的Drivers目录拷贝至`stm32f4xx/sdk`目录下:
212
213   ```
214   .
215   ├── Kconfig.liteos_m.defconfig
216   ├── Kconfig.liteos_m.series
217   ├── Kconfig.liteos_m.soc
218   └── stm32f4xx
219       ├── Kconfig.liteos_m.defconfig.series
220       ├── Kconfig.liteos_m.defconfig.stm32f4xx
221       ├── Kconfig.liteos_m.series
222       ├── Kconfig.liteos_m.soc
223       └── sdk
224           └── Drivers
225               ├── CMSIS
226               └── STM32F4xx_HAL_Driver
227   ```
228
2296. 修改Kconfig文件内容:
230
231   - 在`//device/soc/st/Kconfig.liteos_m.defconfig`中添加:
232
233     ```
234     rsource "*/Kconfig.liteos_m.defconfig.series"
235     ```
236
237   - 在`//device/soc/st/Kconfig.liteos_m.series`中添加:
238
239     ```
240     rsource "*/Kconfig.liteos_m.series"
241     ```
242
243   - 在`//device/soc/st/Kconfig.liteos_m.soc`中添加:
244
245     ```
246     config SOC_COMPANY_STMICROELECTRONICS
247         bool
248     if SOC_COMPANY_STMICROELECTRONICS
249     config SOC_COMPANY
250         default "st"
251     rsource "*/Kconfig.liteos_m.soc"
252     endif # SOC_COMPANY_STMICROELECTRONICS
253     ```
254
255   - 在`//device/soc/st/stm32f4xx/Kconfig.liteos_m.defconfig.series`中添加:
256
257     ```
258     if SOC_SERIES_STM32F4xx
259     rsource "Kconfig.liteos_m.defconfig.stm32f4xx"
260     config SOC_SERIES
261         string
262         default "stm32f4xx"
263     endif
264     ```
265
266   - 在`//device/soc/st/stm32f4xx/Kconfig.liteos_m.defconfig.stm32f4xx`中添加:
267
268     ```
269     config SOC
270         string
271         default "stm32f4xx"
272         depends on SOC_STM32F4xx
273     ```
274
275   - 在`//device/soc/st/stm32f4xx/Kconfig.liteos_m.series`中添加:
276
277     ```
278     config SOC_SERIES_STM32F4xx
279         bool "STMicroelectronics STM32F4xx series"
280         select ARCH_ARM
281         select SOC_COMPANY_STMICROELECTRONICS
282         select CPU_CORTEX_M4
283         help
284             Enable support for STMicroelectronics STM32F4xx series
285     ```
286
287   - 在`//device/soc/st/stm32f4xx/Kconfig.liteos_m.soc`中添加:
288
289     ```
290     choice
291         prompt "STMicroelectronics STM32F4xx series SoC"
292         depends on SOC_SERIES_STM32F4xx
293     config SOC_STM32F407
294         bool "SoC STM32F407"
295     endchoice
296     ```
297
2987. 在`kernel/liteos_m`目录下执行`make menuconfig`,使得能够对`SoC Series`进行选择:
299
300    ![board make menuconfig](figures/niobe407_menuconfig.png)
301
302   结果将自动保存在`$(PRODUCT_PATH)/kernel_configs/debug.config`,下次执行`make menuconfig`时会导出保存的结果。
303
304### BUILD.gn文件适配
305
306为了快速熟悉gn的编译和适配,建议先阅读 [LiteOS-M内核BUILD.gn编写指南](https://gitee.com/caoruihong/kernel_liteos_m/wikis/LiteOS-M%E5%86%85%E6%A0%B8BUILD.gn%E7%BC%96%E5%86%99%E6%8C%87%E5%8D%97)307
308**(注意,BUILD.gn文件中不要出现tab字符,所有tab用空格代替)**
309
3101. 在 `kernel/liteos_m/BUILD.gn` 中,可以看到,通过`deps`指定了`Board`和`SoC`的编译入口:
311
312   ```
313   deps += [ "//device/board/$device_company" ]            --- 对应//device/board/talkweb目录。
314   deps += [ "//device/soc/$LOSCFG_SOC_COMPANY" ]          --- 对应//device/soc/st目录。
315   ```
316
3172. 在`//device/board/talkweb/BUILD.gn`中,新增内容如下:
318
319   ```
320   if (ohos_kernel_type == "liteos_m") {
321       import("//kernel/liteos_m/liteos.gni")
322       module_name = get_path_info(rebase_path("."), "name")
323       module_group(module_name) {
324          modules = [ "niobe407" ]
325       }
326   }
327   ```
328
3293. 在niobe407目录下创建BUILD.gn,为了方便管理,将目录名作为模块名:
330
331   ```
332   import("//kernel/liteos_m/liteos.gni")
333   module_name = get_path_info(rebase_path("."), "name")
334   module_group(module_name) {
335       modules = [
336       	"liteos_m",
337       ]
338   }
339   ```
340
3414. 将stm32cubemx生成的示例工程Core目录下的文件、`startup_stm32f407xx.s`启动文件和`STM32F407IGTx_FLASH.ld`链接文件拷贝至`//device/board/talkweb/niobe407/liteos_m/`目录下,并在该目录下创建`BUILD.gn`,添加如下内容:
342
343   ```
344   import("//kernel/liteos_m/liteos.gni")
345   module_name = get_path_info(rebase_path("."), "name")
346   kernel_module(module_name) {
347       sources = [
348           "startup_stm32f407xx.s",
349           "Src/main.c",
350           "Src/stm32f4xx_hal_msp.c",
351           "Src/stm32f4xx_it.c",
352           "Src/system_stm32f4xx.c",
353       ]
354       include_dirs = [
355           "Inc",
356       ]
357   }
358
359   config("public") {
360       ldflags = [
361           "-Wl,-T" + rebase_path("STM32F407IGTx_FLASH.ld"),
362           "-Wl,-u_printf_float",
363       ]
364       libs = [
365           "c",
366           "m",
367           "nosys",
368       ]
369   }
370   ```
371
3725. 在make menuconfig中配置`(Top) → Compat → Choose libc implementation`,选择`newlibc`。
373
3746. 由于\_write函数会与kernel的文件操作函数重名,会导致编译失败。后续会换一种方法来适配printf函数,此处我们先将main.c文件中对_write函数的重写删除,将printf函数改用如下方式进行串口打印测试。
375
376   ```
377   uint8_t test[]={"hello niobe407!!\r\n"};
378   int len = strlen(test);
379   HAL_UART_Transmit(&huart1, (uint8_t *)test, len, 0xFFFF);
380   ```
381
3827. 同理`//device/soc/st/BUILD.gn`也是一样,按照目录结构层层依赖包含,最终在`//device/soc/st/stm32f4xx/sdk/BUILD.gn`中通过`kernel_module`模板中指定需要参与编译的文件及编译参数,参考如下:
383
384   ```
385   import("//kernel/liteos_m/liteos.gni")
386   module_name = "stm32f4xx_sdk"
387   kernel_module(module_name) {
388     asmflags = board_asmflags
389     sources = [
390       "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c",
391       "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c",
392       "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c",
393       "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c",
394       "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c",
395       "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c",
396       "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c",
397       "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_exti.c",
398       "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c",
399     ]
400   }
401   #指定全局头文件搜索路径
402   config("public") {
403       include_dirs = [
404           "Drivers/STM32F4xx_HAL_Driver/Inc",
405           "Drivers/CMSIS/Device/ST/STM32F4xx/Include",
406       ]
407   }
408   ```
409
410### config.gni文件适配
411
412在预编译阶段,在`//device/board/talkweb/niobe407/liteos_m`目录下创建了一个config.gni文件,它其实就是gn脚本的头文件,可以理解为工程构建的全局配置文件。主要配置了CPU型号、交叉编译工具链及全局编译、链接参数等重要信息:
413
414```
415# Kernel type, e.g. "linux", "liteos_a", "liteos_m".
416kernel_type = "liteos_m"
417
418# Kernel version.
419kernel_version = "3.0.0"
420
421# Board CPU type, e.g. "cortex-a7", "riscv32".
422board_cpu = "cortex-m4"
423
424# Board arch, e.g.  "armv7-a", "rv32imac".
425board_arch = ""
426
427# Toolchain name used for system compiling.
428# E.g. gcc-arm-none-eabi, arm-linux-harmonyeabi-gcc, ohos-clang,  riscv32-unknown-elf.
429# Note: The default toolchain is "ohos-clang". It's not mandatory if you use the default toolchain.
430board_toolchain = "arm-none-eabi-gcc"
431
432use_board_toolchain = true
433
434# The toolchain path installed, it's not mandatory if you have added toolchain path to your ~/.bashrc.
435board_toolchain_path = ""
436
437# Compiler prefix.
438board_toolchain_prefix = "arm-none-eabi-"
439
440# Compiler type, "gcc" or "clang".
441board_toolchain_type = "gcc"
442
443#Debug compiler optimization level options
444board_opt_flags = [
445    "-mcpu=cortex-m4",
446    "-mthumb",
447    "-mfpu=fpv4-sp-d16",
448    "-mfloat-abi=hard",
449]
450
451# Board related common compile flags.
452board_cflags = [
453    "-Og",
454    "-Wall",
455    "-fdata-sections",
456    "-ffunction-sections",
457    "-DSTM32F407xx",
458]
459board_cflags += board_opt_flags
460
461board_asmflags = [
462    "-Og",
463    "-Wall",
464    "-fdata-sections",
465    "-ffunction-sections",
466]
467board_asmflags += board_opt_flags
468
469board_cxx_flags = board_cflags
470
471board_ld_flags = board_opt_flags
472
473# Board related headfiles search path.
474board_include_dirs = [ "//utils/native/lite/include" ]
475
476# Board adapter dir for OHOS components.
477board_adapter_dir = ""
478```
479
480如上所示,比较难理解的就是board_opt_flags、board_cflags、board_asmflags等几个参数配置。可以参考如下描述,从stm32cubemx生成的工程中的`Makefile`文件中提取出来:
481```
482board_opt_flags : 编译器相关选项,一般为芯片架构、浮点类型、编译调试优化等级等选项。
483board_asmflags  :汇编编译选项,与Makefile中的ASFLAGS变量对应。
484board_cflags    :C代码编译选项,与Makefile中的CFLAGS变量对应。
485board_cxx_flags :C++代码编译选项,与Makefile中的CXXFLAGS变量对应。
486board_ld_flags  :链接选项,与Makefile中的LDFLAGS变量对应。
487```
488
489### 内核子系统适配
490
491在`//vendor/talkweb/niobe407/config.json`文件中添加内核子系统及相关配置,如下所示:
492
493```
494{
495    "product_name": "niobe407",
496    "type": "mini",
497    "version": "3.0",
498    "device_company": "talkweb",
499    "board": "niobe407",
500    "kernel_type": "liteos_m",
501    "kernel_version": "3.0.0",
502    "subsystems": [
503        {
504            "subsystem": "kernel",
505            "components": [
506                {
507                    "component": "liteos_m"
508                }
509            ]
510        }
511    ],
512    "product_adapter_dir": "",
513    "third_party_dir": "//third_party"
514}
515```
516
517### target_config.h文件适配
518
519在`//kernel/liteos_m/kernel/include/los_config.h`文件中,有包含一个名为target_config.h的头文件,如果没有这个头文件,则会编译出错。
520
521该头文件的作用主要是定义一些与soc芯片相关的宏定义,可以创建一个空头文件,再配合编译报错提示信息来确定需要定义哪些宏。经验证,Cortex-M4的核适配只需定义`LOSCFG_BASE_CORE_TICK_RESPONSE_MAX`宏并包含`stm32f4xx.h`头文件即可将kernel编译通过。
522
523若前期不知如何配置,可以参考虚拟机qemu示例中`//device/qemu/arm_mps2_an386/liteos_m/board/target_config.h`的配置。
524
525```
526#ifndef _TARGET_CONFIG_H
527#define _TARGET_CONFIG_H
528
529#define LOSCFG_BASE_CORE_TICK_RESPONSE_MAX                  0xFFFFFFUL
530#include "stm32f4xx.h"			//包含了stm32f4平台大量的宏定义。
531
532#endif
533```
534
535其中宏定义`LOSCFG_BASE_CORE_TICK_RESPONSE_MAX`是直接参考的`//device/qemu/arm_mps2_an386/liteos_m/board/target_config.h`文件中的配置,`//device/qemu/arm_mps2_an386`是`cortex-m4`的虚拟机工程,后续适配可以直接参考,在此不做深入讲解。
536
537### 内核启动适配
538
539至此,已经可以成功将kernel子系统编译通过,并且在out目录下生成OHOS_Image.bin文件。将生成的OHOS_Image.bin文件烧录至开发板,验证板子能否正常启动运行,如果能成功打印出main函数中串口输出的正确的打印信息,则可以开始进行内核启动适配。
540
5411. 为liteos_m分配内存,适配内存分配函数。
542
543   在文件`//kernel/liteos_m/kernel/src/mm/los_memory.c`中,`OsMemSystemInit`函数通过LOS_MemInit进行了内存初始化。可以看到几个比较关键的宏需要我们指定,我们将其添加到`target_config.h`中:
544
545   ```
546   extern unsigned int __los_heap_addr_start__;
547   extern unsigned int __los_heap_addr_end__;
548   #define LOSCFG_SYS_EXTERNAL_HEAP 1
549   #define LOSCFG_SYS_HEAP_ADDR ((void *)&__los_heap_addr_start__)
550   #define LOSCFG_SYS_HEAP_SIZE (((unsigned long)&__los_heap_addr_end__) - ((unsigned long)&__los_heap_addr_start__))
551   ```
552
553   其中,`__los_heap_addr_start__`与`__los_heap_addr_end__`变量在`STM32F407IGTx_FLASH.ld`链接文件中被定义, 将_user_heap_stack花括号内内容修改为:
554
555   ```
556   ._user_heap_stack :
557   {
558       . = ALIGN(0x40);
559       __los_heap_addr_start__ = .;
560       __los_heap_addr_end__ = ORIGIN(RAM) + LENGTH(RAM);
561   } >RAM
562   ```
563
564   除此之外,我们还需要适配内存分配函数,由于内核中已经对_malloc_r等内存分配函数进行了实现,在此我们采用包装函数的方式来适配,用内核中的内存分配函数替换标准库中的内存分配函数即可,在`//device/board/talkweb/niobe407/liteos_m/config.gni`中board_ld_flags链接参数变量修改为:
565
566   ```
567   board_ld_flags = [
568       "-Wl,--wrap=_calloc_r",
569       "-Wl,--wrap=_malloc_r",
570       "-Wl,--wrap=_realloc_r",
571       "-Wl,--wrap=_reallocf_r",
572       "-Wl,--wrap=_free_r",
573       "-Wl,--wrap=_memalign_r",
574       "-Wl,--wrap=_malloc_usable_size_r",
575   ]
576   board_ld_flags += board_opt_flags
577   ```
578
5792. 适配printf打印。
580
581   为了方便后续调试,第一步需要先适配printf函数。而printf的函数适配可大可小,在此只做简单适配,具体实现可以参考其它各开发板源码。
582
583main.c同级目录下创建dprintf.c文件,文件内容如下:
584
585   ```
586   #include <stdarg.h>
587   #include "los_interrupt.h"
588   #include <stdio.h>
589
590   extern UART_HandleTypeDef huart1;
591
592   INT32 UartPutc(INT32 ch, VOID *file)
593   {
594       char RL = '\r';
595       if (ch =='\n') {
596           HAL_UART_Transmit(&huart1, &RL, 1, 0xFFFF);
597       }
598       return HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
599   }
600
601   static void dputs(char const *s, int (*pFputc)(int n, FILE *cookie), void *cookie)
602   {
603       unsigned int intSave;
604
605       intSave = LOS_IntLock();
606       while (*s) {
607           pFputc(*s++, cookie);
608       }
609       LOS_IntRestore(intSave);
610   }
611
612   int printf(char const  *fmt, ...)
613   {
614       char buf[1024] = { 0 };
615       va_list ap;
616       va_start(ap, fmt);
617       int len = vsnprintf_s(buf, sizeof(buf), 1024 - 1, fmt, ap);
618       va_end(ap);
619       if (len > 0) {
620           dputs(buf, UartPutc, 0);
621       } else {
622           dputs("printf error!\n", UartPutc, 0);
623       }
624       return len;
625   }
626   ```
627
628dprintf.c文件加入BUILD.gn编译脚本,参与编译。
629
630   ```
631   kernel_module(module_name) {
632       sources = [
633           "startup_stm32f407xx.s",
634       ]
635
636       sources += [
637           "Src/main.c",
638           "Src/dprintf.c",
639           "Src/stm32f4xx_hal_msp.c",
640           "Src/stm32f4xx_it.c",
641           "Src/system_stm32f4xx.c",
642       ]
643   }
644   ```
645
646   在串口初始化之后使用printf函数打印,测试是否适配成功。
647
6483. 调用LOS_KernelInit初始化内核,进入任务调度。
649
650   在main函数中串口初始化之后,调用`LOS_KernelInit`进行初始化,创建任务示例,进入任务调度。
651
652   ```
653   #include "los_task.h"
654
655   UINT32 ret;
656   ret = LOS_KernelInit();  //初始化内核。
657   if (ret == LOS_OK) {
658       TaskSample();  //示例任务函数,在此函数中创建线程任务。
659       LOS_Start();   //开始任务调度,程序执行将阻塞在此,由内核接管调度。
660   }
661   ```
662
663   其中`TaskSample()`函数内容如下:
664
665   ```
666   VOID TaskSampleEntry2(VOID)
667   {
668       while (1) {
669           printf("TaskSampleEntry2 running...\n");
670           (VOID)LOS_TaskDelay(2000); /* 2000 millisecond */
671       }
672   }
673
674   VOID TaskSampleEntry1(VOID)
675   {
676       while (1) {
677           printf("TaskSampleEntry1 running...\n");
678           (VOID)LOS_TaskDelay(2000); /* 2000 millisecond */
679       }
680   }
681   VOID TaskSample(VOID)
682   {
683       UINT32 uwRet;
684       UINT32 taskID1;
685       UINT32 taskID2;
686       TSK_INIT_PARAM_S stTask = {0};
687
688       stTask.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry1;
689       stTask.uwStackSize = 0x1000;
690       stTask.pcName = "TaskSampleEntry1";
691       stTask.usTaskPrio = 6; /* Os task priority is 6 */
692       uwRet = LOS_TaskCreate(&taskID1, &stTask);
693       if (uwRet != LOS_OK) {
694           printf("Task1 create failed\n");
695       }
696
697       stTask.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry2;
698       stTask.uwStackSize = 0x1000;
699       stTask.pcName = "TaskSampleEntry2";
700       stTask.usTaskPrio = 7; /* Os task priority is 7 */
701       uwRet = LOS_TaskCreate(&taskID2, &stTask);
702       if (uwRet != LOS_OK) {
703           printf("Task2 create failed\n");
704       }
705   }
706   ```
707
708适配完内核启动后,可以通过调试串口看到如下打印信息:
709
710 ![niobe407_boot](figures/niobe407_boot.png)
711
712后续还需要对整个基础内核进行详细适配验证。
713
714### 内核基础功能适配
715
716内核基础功能适配项包括:**[中断管理](../kernel/kernel-mini-basic-interrupt.md)**、**[任务管理](../kernel/kernel-mini-basic-task.md)**、**[内存管理](../kernel/kernel-mini-basic-memory.md)**、**[内核通信机制](../kernel/kernel-mini-basic-ipc-event.md)**、**[时间管理](../kernel/kernel-mini-basic-time.md)**、**[软件定时器](../kernel/kernel-mini-basic-soft.md)**,可以参考对应链接中的编程实例进行内核基础功能验证。在验证的过程中发现问题,针对相应问题进行具体的适配。
717
718从上一节中打印信息输出时间间隔可以看出,`LOS_TaskDelay`函数的延时时间不准确,我们可以在`target_config.h`中定义如下宏进行内核时钟适配:
719
720  ```
721  #define OS_SYS_CLOCK                                        168000000
722  #define LOSCFG_BASE_CORE_TICK_PER_SECOND                    (1000UL)
723  ```
724其它内核基础功能的适配方法大多也是围绕于`target_config.h`中的宏定义,需要大家配合`//kernel/liteos_m`下源码,自行尝试摸索,在此不做进一步讲解。
725
726## littlefs文件系统移植适配
727
728 `Niobe407`开发板外挂了16MB的SPI-FLASH,Niobe407基于该Flash进行了littlefs适配。
729
730内核已经对littlefs进行了适配,我们只需要开启Kconfig中的配置,然后适配Littlefs如下接口:
731
732```
733  int32_t LittlefsRead(const struct lfs_config *cfg, lfs_block_t block,
734                          lfs_off_t off, void *buffer, lfs_size_t size)
735  {
736      W25x_BufferRead(buffer, cfg->context + cfg->block_size * block + off, size);
737      return LFS_ERR_OK;
738  }
739
740  int32_t LittlefsProg(const struct lfs_config *cfg, lfs_block_t block,
741                          lfs_off_t off, const void *buffer, lfs_size_t size)
742  {
743      W25x_BufferWrite((uint8_t *)buffer,cfg->context + cfg->block_size * block + off,size);
744      return LFS_ERR_OK;
745  }
746
747  int32_t LittlefsErase(const struct lfs_config *cfg, lfs_block_t block)
748  {
749     W25x_SectorErase(cfg->context + cfg->block_size * block);
750     return LFS_ERR_OK;
751  }
752
753  int32_t LittlefsSync(const struct lfs_config *cfg)
754  {
755      return LFS_ERR_OK;
756  }
757```
758
759`W25x_BufferRead`等函数是spi-flash读写操作的接口,不同型号的spi-flash其实现也不同,Niobe407的SPI-Flash操作具体实现可参考`//device/board/talkweb/niobe407/liteos_m/drivers/spi_flash/src/w25qxx.c`。
760
761由于SPI已经hdf化了,而littlefs依赖于spi驱动,为了方便对文件系统进行配置,可以将littlefs的配置加入至.hcs文件中,具体参考:`//device/board/talkweb/niobe407/liteos_m/hdf_config/hdf_littlefs.hcs`文件。
762
763```
764misc {
765        littlefs_config {
766            match_attr = "littlefs_config";
767            mount_points = ["/talkweb"];
768            partitions = [0x800000];
769            block_size = [4096];
770            block_count = [256];
771        }
772}
773```
774
775## 板级驱动移植
776
777驱动适配相关文件放置在`//drivers/adapter/platform`中,对应有`gpio`,`i2c`,`pwm`,`spi`,`uart`,`watchdog`,都是通过`HDF`机制加载,本章节以`pwm`为例进行说明。
778
779### PWM驱动适配
780在HDF框架中,PWM的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDF DeviceManager的服务管理能力,但需要为每个设备单独配置设备节点。
781
782- 接口说明
783
784  ```
785  1. pwm open初始化函数:DevHandle PwmOpen(uint32_t num);
786      参数说明:
787          num:     PWM设备编号。
788          return:  获取成功返回PWM设备句柄,失败返回NULL。
789  2. pwm close去初始化函数:void PwmClose(DevHandle handle);
790      参数说明:
791          handle:   pwm设备句柄。
792          return:    无。
793  3. 设置PWM设备参数:int32_t PwmSetConfig(DevHandle handle, struct PwmConfig *config);
794      参数说明:
795          handle:   pwm设备句柄。
796          *config    参数指针。
797          return:    返回0表示设置成功,返回负数表示失败。
798  ```
799
800- PWM HDF HCS配置文件解析
801
802  `device_info.hcs`文件位于`//device/board/talkweb/niobe407/liteos_m/hdf_config/device_info.hcs`,以下示例为使用TIM2、TIM3和TIM7定时器输出PWM信号:
803
804    ```
805    device_pwm1 :: device {
806        pwm1 :: deviceNode {
807            policy = 2;
808            priority = 100;
809            moduleName = "ST_HDF_PLATFORM_PWM";
810            serviceName = "HDF_PLATFORM_PWM_1";
811            deviceMatchAttr = "config_pwm1";
812        }
813    }
814    device_pwm2 :: device {
815        pwm2 :: deviceNode {
816            policy = 2;
817            priority = 100;
818            moduleName = "ST_HDF_PLATFORM_PWM";
819            serviceName = "HDF_PLATFORM_PWM_2";
820            deviceMatchAttr = "config_pwm2";
821        }
822    }
823    device_pwm7 :: device {
824        pwm7 :: deviceNode {
825            policy = 2;
826            priority = 100;
827            moduleName = "ST_HDF_PLATFORM_PWM";
828            serviceName = "HDF_PLATFORM_PWM_7";
829            deviceMatchAttr = "config_pwm7";
830        }
831    }
832    ```
833
834  `hdf.hcs`文件位于`//device/board/talkweb/niobe407/liteos_m/hdf_config/hdf.hcs`,在此文件中配置TIM定时器具体信息:
835
836    ```
837    --- 注意:tim2-tim7、tim12-tim14时钟频率为84M,TIM1、TIM8~TIM11为168M,tim6和tim7不能输出pwm。
838    --- tim1~tim5、tim8有4个channel,tim9、tim12有2个channel,tim10、tim11、tim13、tim14只有1个channel。
839
840    pwm_config {
841        pwm1_config {
842            match_attr = "config_pwm1";
843            pwmTim = 1; 		--- 定时器ID tim2(0:tim1,1:tim2,...,tim6和tim7不可用)
844            pwmCh = 3; 			--- 对应channel数(0:ch1、1:ch2、2:ch3、3:ch4)
845            prescaler = 4199; 	--- 预分频数,例如tim2时钟为84M,(84M/(4199+1))=20khz,则以20khz为基准。
846        }
847        pwm2_config {
848            match_attr = "config_pwm2";
849            pwmTim = 2;
850            pwmCh = 0;
851            prescaler = 8399;
852        }
853        pwm3_config {
854            match_attr = "config_pwm7";
855            pwmTim = 7;
856            pwmCh = 0;
857            prescaler = 8399;
858        }
859    }
860    ```
861
862`hdf pwm`适配代码请参考:`//drivers/adapter/platform/pwm/pwm_stm32f4xx.c`
863
864`hdf pwm`使用示例可请参考:`//device/board/talkweb/niobe407/applications/206_hdf_pwm`
865
866## 子系统适配
867
868`OpenHarmony`子系统适配一般包含两部分:
869
870- 在`config.json`中增加对应子系统和部件,这样编译系统会将该部件纳入编译目标中。
871- 针对该部件的`HAL`层接口进行硬件适配,或者可选的软件功能适配。
872
873### LWIP部件适配
874
875`LiteOS-M kernel`通过Kconfig配置可以使lwip参与编译,并可以在`kernel`组件中指定`lwip`编译适配的目录。如下:
876
877```
878{
879	"subsystem": "kernel",
880	"components": [
881		{
882            "component": "liteos_m",
883            "features": [
884                "ohos_kernel_liteos_m_lwip_path = \"//device/board/talkweb/niobe407/liteos_m/lwip_adapter\"" --- 指定适配路径
885			]
886		}
887	]
888}
889```
890
891在指定的编译适配目录中,通过`#include_next "lwip/lwipopts.h"`的方式入侵修改lwip三方库中头文件配置,关于有线以太网LWIP适配部分,后续会补充详细适配步骤,在此先不做深入讲解。
892
893### 启动恢复子系统适配
894
895启动恢复子系统适配`bootstrap_lite`和`syspara_lite`两个组件。请在`//vendor/talkweb/niobe407/config.json`中新增对应的配置选项。
896
897```
898{
899      "subsystem": "startup",
900      "components": [
901        {
902          "component": "bootstrap_lite",
903          "features": []
904        },
905        {
906          "component": "syspara_lite",
907          "features": []
908        }
909      ]
910}
911```
912
913适配`bootstrap_lite`部件时,需要在链接文件`//device/board/talkweb/niobe407/liteos_m/STM32F407IGTx_FLASH.ld`中手动新增如下段:
914
915```
916__zinitcall_bsp_start = .;
917KEEP (*(.zinitcall.bsp0.init))
918KEEP (*(.zinitcall.bsp1.init))
919KEEP (*(.zinitcall.bsp2.init))
920KEEP (*(.zinitcall.bsp3.init))
921KEEP (*(.zinitcall.bsp4.init))
922__zinitcall_bsp_end = .;
923__zinitcall_device_start = .;
924KEEP (*(.zinitcall.device0.init))
925KEEP (*(.zinitcall.device1.init))
926KEEP (*(.zinitcall.device2.init))
927KEEP (*(.zinitcall.device3.init))
928KEEP (*(.zinitcall.device4.init))
929__zinitcall_device_end = .;
930__zinitcall_core_start = .;
931KEEP (*(.zinitcall.core0.init))
932KEEP (*(.zinitcall.core1.init))
933KEEP (*(.zinitcall.core2.init))
934KEEP (*(.zinitcall.core3.init))
935KEEP (*(.zinitcall.core4.init))
936__zinitcall_core_end = .;
937__zinitcall_sys_service_start = .;
938KEEP (*(.zinitcall.sys.service0.init))
939KEEP (*(.zinitcall.sys.service1.init))
940KEEP (*(.zinitcall.sys.service2.init))
941KEEP (*(.zinitcall.sys.service3.init))
942KEEP (*(.zinitcall.sys.service4.init))
943__zinitcall_sys_service_end = .;
944__zinitcall_sys_feature_start = .;
945KEEP (*(.zinitcall.sys.feature0.init))
946KEEP (*(.zinitcall.sys.feature1.init))
947KEEP (*(.zinitcall.sys.feature2.init))
948KEEP (*(.zinitcall.sys.feature3.init))
949KEEP (*(.zinitcall.sys.feature4.init))
950__zinitcall_sys_feature_end = .;
951__zinitcall_run_start = .;
952KEEP (*(.zinitcall.run0.init))
953KEEP (*(.zinitcall.run1.init))
954KEEP (*(.zinitcall.run2.init))
955KEEP (*(.zinitcall.run3.init))
956KEEP (*(.zinitcall.run4.init))
957__zinitcall_run_end = .;
958__zinitcall_app_service_start = .;
959KEEP (*(.zinitcall.app.service0.init))
960KEEP (*(.zinitcall.app.service1.init))
961KEEP (*(.zinitcall.app.service2.init))
962KEEP (*(.zinitcall.app.service3.init))
963KEEP (*(.zinitcall.app.service4.init))
964__zinitcall_app_service_end = .;
965__zinitcall_app_feature_start = .;
966KEEP (*(.zinitcall.app.feature0.init))
967KEEP (*(.zinitcall.app.feature1.init))
968KEEP (*(.zinitcall.app.feature2.init))
969KEEP (*(.zinitcall.app.feature3.init))
970KEEP (*(.zinitcall.app.feature4.init))
971__zinitcall_app_feature_end = .;
972__zinitcall_test_start = .;
973KEEP (*(.zinitcall.test0.init))
974KEEP (*(.zinitcall.test1.init))
975KEEP (*(.zinitcall.test2.init))
976KEEP (*(.zinitcall.test3.init))
977KEEP (*(.zinitcall.test4.init))
978__zinitcall_test_end = .;
979__zinitcall_exit_start = .;
980KEEP (*(.zinitcall.exit0.init))
981KEEP (*(.zinitcall.exit1.init))
982KEEP (*(.zinitcall.exit2.init))
983KEEP (*(.zinitcall.exit3.init))
984KEEP (*(.zinitcall.exit4.init))
985__zinitcall_exit_end = .;
986```
987
988需要新增上述段是因为`bootstrap_init`提供的对外接口,见`//utils/native/lite/include/ohos_init.h`文件,采用的是灌段的形式,最终会保存到上述链接段中。主要的服务自动初始化宏如下表格所示:
989
990| 接口名                 | 描述                             |
991| ---------------------- | -------------------------------- |
992| SYS_SERVICE_INIT(func) | 标识核心系统服务的初始化启动入口。 |
993| SYS_FEATURE_INIT(func) | 标识核心系统功能的初始化启动入口。 |
994| APP_SERVICE_INIT(func) | 标识应用层服务的初始化启动入口。   |
995| APP_FEATURE_INIT(func) | 标识应用层功能的初始化启动入口。   |
996
997
998
999通过上面加载的组件编译出来的lib文件需要手动加入强制链接。
1000
1001如在 `//vendor/talkweb/niobe407/config.json` 中配置了`bootstrap_lite` 部件
1002
1003```
1004    {
1005      "subsystem": "startup",
1006      "components": [
1007        {
1008          "component": "bootstrap_lite"
1009        },
1010        ...
1011      ]
1012    },
1013```
1014
1015​	`bootstrap_lite`部件会编译`//base/startup/bootstrap_lite/services/source/bootstrap_service.c`,该文件中,通过`SYS_SERVICE_INIT`将`Init`函数符号灌段到`__zinitcall_sys_service_start`和`__zinitcall_sys_service_end`中,由于`Init`函数是没有显式调用它,所以需要将它强制链接到最终的镜像。如下:
1016
1017```
1018static void Init(void)
1019{
1020    static Bootstrap bootstrap;
1021    bootstrap.GetName = GetName;
1022    bootstrap.Initialize = Initialize;
1023    bootstrap.MessageHandle = MessageHandle;
1024    bootstrap.GetTaskConfig = GetTaskConfig;
1025    bootstrap.flag = FALSE;
1026    SAMGR_GetInstance()->RegisterService((Service *)&bootstrap);
1027}
1028SYS_SERVICE_INIT(Init);   --- 通过SYS启动即SYS_INIT启动就需要强制链接生成的lib
1029```
1030
1031​	在`//base/startup/bootstrap_lite/services/source/BUILD.gn`文件中,描述了在`//out/niobe407/niobe407/libs` 生成 `libbootstrap.a`,如下:
1032
1033```
1034static_library("bootstrap") {
1035  sources = [
1036    "bootstrap_service.c",
1037    "system_init.c",
1038  ]
1039  ...
1040```
1041
1042适配`syspara_lite`部件时,系统参数会最终写到文件中进行持久化保存。在轻量系统中,文件操作相关接口有`POSIX`接口与`HalFiles`接口这两套实现。
1043
1044因为对接内核的文件系统,采用`POSIX`相关的接口,所以`features`字段中需要增加`enable_ohos_startup_syspara_lite_use_posix_file_api = true`。
1045
1046如果对接`HalFiles`相关的接口实现的,则无须修改。
1047### DFX子系统适配
1048
1049进行`DFX`子系统适配需要添加`hilog_lite`和`hievent_lite`部件,直接在`config.json`文件配置即可。
1050
1051```
1052{
1053    "subsystem": "hiviewdfx",
1054    "components": [
1055        {
1056            "component": "hilog_lite",
1057            "features": []
1058        },
1059        {
1060            "component": "hievent_lite",
1061            "features": []
1062        }
1063    ]
1064}
1065```
1066
1067配置完成之后,需要注册日志输出实现函数,并加入编译。
1068
1069```
1070bool HilogProc_Impl(const HiLogContent *hilogContent, uint32_t len)
1071{
1072    char tempOutStr[LOG_FMT_MAX_LEN];
1073    tempOutStr[0] = 0,tempOutStr[1] = 0;
1074    if (LogContentFmt(tempOutStr, sizeof(tempOutStr), hilogContent) > 0) {
1075        printf(tempOutStr);
1076    }
1077    return true;
1078}
1079
1080HiviewRegisterHilogProc(HilogProc_Impl);
1081```
1082
1083### 系统服务管理子系统适配
1084
1085进行系统服务管理子系统适配需要添加`samgr_lite`部件,直接在`config.json`配置即可。
1086
1087```
1088{
1089      "subsystem": "systemabilitymgr",
1090      "components": [
1091        {
1092          "component": "samgr_lite",
1093          "features": []
1094        }
1095      ]
1096}
1097```
1098
1099在轻量系统中,`samgr_lite`配置的共享任务栈大小默认为`2048`。在适配时可以在features中,通过`config_ohos_systemabilitymgr_samgr_lite_shared_task_size`重新设置共享任务栈大小。
1100
1101```
1102"config_ohos_systemabilitymgr_samgr_lite_shared_task_size = 4096"
1103```
1104
1105### 安全子系统适配
1106
1107进行安全子系统适配需要添加`huks`组件,直接在`config.json`配置即可。
1108
1109```
1110{
1111      "subsystem": "security",
1112      "components": [
1113        {
1114          "component": "huks",
1115          "features": [
1116            "huks_use_lite_storage = true",
1117            "huks_use_hardware_root_key = true",
1118            "huks_config_file = \"hks_config_lite.h\"",
1119            "huks_key_store_path = \"storage\""
1120          ]
1121        }
1122      ]
1123}
1124```
1125
1126`huks`部件适配时,`huks_key_store_path`配置选项用于指定存放秘钥路径,`huks_config_file`为配置头文件名称。
1127
1128### 公共基础库子系统适配
1129
1130公共基础库子系统适配添加了`kv_store`、`file`、`os_dump`组件,直接在`config.json`配置即可。
1131
1132```
1133{
1134      "subsystem": "utils",
1135      "components": [
1136        {
1137          "component": "file",
1138          "features": []
1139        },
1140        {
1141          "component": "kv_store",
1142          "features": [
1143            "enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = false"
1144          ]
1145        },
1146        {
1147          "component": "os_dump",
1148          "features": []
1149        }
1150      ]
1151},
1152```
1153
1154与适配`syspara_lite`部件类似,适配`kv_store`部件时,键值对会写到文件中。在轻量系统中,文件操作相关接口有`POSIX`接口与`HalFiles`接口这两套实现。因为对接内核的文件系统,采用`POSIX`相关的接口,所以`features`需要增加`enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true`。如果对接`HalFiles`相关的接口实现的,则无须修改。
1155
1156### HDF子系统适配
1157
1158与启动恢复子系统适配类似,我们需要在链接文件`//device/board/talkweb/niobe407/liteos_m/STM32F407IGTx_FLASH.ld`中手动新增如下段:
1159
1160```
1161_hdf_drivers_start = .;
1162KEEP(*(.hdf.driver))
1163_hdf_drivers_end = .;
1164```
1165
1166然后,在kernel初始化完成后调用DeviceManagerStart函数,执行完成后,才能调用hdf接口控制外设。
1167
1168```
1169#include "devmgr_service_start.h"   --- 注意需要包含该头文件
1170
1171#ifdef LOSCFG_DRIVERS_HDF
1172    DeviceManagerStart();
1173#endif
1174```
1175
1176`devmgr_service_start.h`头文件所在路径为: `//drivers/framework/core/common/include/manager`,为保证编译时能找到该头文件,需要将其加入到include_dirs中:
1177
1178### XTS兼容性测评子系统适配
1179
1180#### 产品兼容性规范
1181
1182产品兼容性规范文档请参考[产品兼容性SIG介绍](https://gitee.com/openharmony-sig/compatibility/tree/master)1183
1184#### 添加XTS子系统
1185
1186`XTS`测试参考资料见[xts参考资料](../device-test/xts.md),进行`XTS`子系统适配需要添加`xts_acts`与`xts_tools`组件,直接在`config.json`配置即可,配置如下:
1187
1188    {
1189          "subsystem": "xts",
1190          "components": [
1191            {
1192              "component": "xts_acts",
1193              "features": []
1194            },
1195            {
1196              "component": "xts_tools",
1197              "features": []
1198            }
1199          ]
1200    }
1201
1202我们可以在xts_acts组件的features数组中指定如下属性:
1203
1204- `config_ohos_xts_acts_utils_lite_kv_store_data_path` 配置挂载文件系统根目录的名字。
1205- `enable_ohos_test_xts_acts_use_thirdparty_lwip` 表示如果使用`thirdparty/lwip`目录下的源码编译,则设置为`true`,否则设置为`false`。
1206
1207#### 编译XTS
1208
1209在配置config.json后,使用`hb build`是不会去编译xts的,只有在debug版本编译时才会参与编译,并且需要我们强制链接需要进行测试的套件静态库。
1210
1211在我们`//device/board/talkweb/liteos_m`下包含`kernel_module`的BUILD.gn 脚本中添加如下内容:
1212
1213```
1214config("public") {
1215	if (build_xts) {
1216        lib_dirs = [ "$root_out_dir/libs" ]
1217        ldflags += [
1218        "-Wl,--whole-archive",     --- 开启whole-archive特性,可以把在其后面出现的静态库包含的函数和变量输出到动态库
1219        "-lbootstrap",
1220        "-lbroadcast",
1221        "-lhctest",
1222
1223        #公共基础库。
1224        # "-lmodule_ActsUtilsFileTest",
1225        # "-lmodule_ActsKvStoreTest",
1226
1227        #DFX
1228        "-lmodule_ActsDfxFuncTest",
1229        "-lmodule_ActsHieventLiteTest",
1230
1231        #启动恢复。
1232        # "-lmodule_ActsBootstrapTest",
1233        # "-lmodule_ActsParameterTest",
1234
1235        #分布式任务调度。
1236        # "-lmodule_ActsSamgrTest",
1237
1238        "-Wl,--no-whole-archive",  --- 关掉whole-archive这个特性
1239        ]
1240	}
1241}
1242```
1243
1244由于Niobe407开发板内存有限,xts测试时需要分套件测试。执行如下编译命令,即可生成包含xts测试的固件。
1245
1246```
1247hb build -f -b debug --gn-args build_xts=true
1248```
1249
1250此外,我们还需要修改`//vendor/talkweb/niobe407/hals/utils/sys_param/hal_sys_param.c`文件,将这些字符串定义正确。
1251
1252```
1253static const char OHOS_DEVICE_TYPE[] = {"Evaluation Board"};
1254static const char OHOS_DISPLAY_VERSION[] = {"OpenHarmony 3.1"};
1255static const char OHOS_MANUFACTURE[] = {"Talkweb"};
1256static const char OHOS_BRAND[] = {"Talkweb"};
1257static const char OHOS_MARKET_NAME[] = {"Niobe"};
1258static const char OHOS_PRODUCT_SERIES[] = {"Niobe"};
1259static const char OHOS_PRODUCT_MODEL[] = {"Niobe407"};
1260static const char OHOS_SOFTWARE_MODEL[] = {"1.0.0"};
1261static const char OHOS_HARDWARE_MODEL[] = {"2.0.0"};
1262static const char OHOS_HARDWARE_PROFILE[] = {"RAM:192K,ROM:1M,ETH:true"};
1263static const char OHOS_BOOTLOADER_VERSION[] = {"twboot-v2022.03"};
1264static const char OHOS_ABI_LIST[] = {"armm4_hard_fpv4-sp-d16-liteos"};
1265static const char OHOS_SERIAL[] = {"1234567890"};  // provided by OEM.
1266```
1267
1268#### 验证XTS
1269
1270编译完成后,将固件烧录至开发板,xts全部跑完会有显示`xx Tests xx Failures xx Ignored`等信息,以下以公共基础库测试为例:
1271
1272```
1273../../../test/xts/acts/utils_lite/kv_store_hal/src/kvstore_func_test.c:590:testKvStoreClearCache002:PASS
1274../../../test/xts/acts/utils_lite/kv_store_hal/src/kvstore_func_test.c:625:testKvStoreCacheSize001:PASS
1275../../../test/xts/acts/utils_lite/kv_store_hal/src/kvstore_func_test.c:653:testKvStoreCacheSize002:PASS
1276../../../test/xts/acts/utils_lite/kv_store_hal/src/kvstore_func_test.c:681:testKvStoreCacheSize003:PASS
1277../../../test/xts/acts/utils_lite/kv_store_hal/src/kvstore_func_test.c:709:testKvStoreMaxSize001:PASS
1278../../../test/xts/acts/utils_lite/kv_store_hal/src/kvstore_func_test.c:737:testKvStoreMaxSize002:PASS
1279../../../test/xts/acts/utils_lite/kv_store_hal/src/kvstore_func_test.c:765:testKvStoreMaxSize003:PASS
1280../../../test/xts/acts/utils_lite/kv_store_hal/src/kvstore_func_test.c:793:testKvStoreMaxSize004:PASS
1281+-------------------------------------------+
1282
1283-----------------------
128432 Tests 0 Failures 0 Ignored
1285OK
1286All the test suites finished!
1287```
1288