# 硬件点亮指引

硬件点亮（ Bring up）是嵌入式系统开发的第一步，是将硬件设计从图纸变为实际可用设备的关键环节。通过点亮过程，可以验证硬件设计的正确性、初步运行最小系统、并为后续功能开发打下基础。以下将从 **最小系统制作**、**硬件回板检查与调试**、**系统功能初步验证** 等方面，详细介绍硬件点亮的基本流程和关键步骤。

## 硬件点亮基本流程

这一章节将梳理硬件点亮的整体流程，为之后的开发提供清晰的指引。在接下来的章节中，我们将对每个阶段涉及的开发任务进行详细说明，帮助用户按步骤完成开发工作。

### 最小系统准备阶段

在硬件回板前，软件上可以提前完成以下开发，当硬件回板时快速进行验证调试。

- 板级配置与基本驱动开发
  - 在 BSP（源码在 SDK 交付包的 board_support_package/platform_source_code.tar.gz）代码中新增板级配置文件，例如 `board_xxx_config.mk` （`xxx` 是用户自定义的名称，例如 `x5_evb_release`），以适配新硬件平台。
  - 在 U-Boot 中添加新硬件的 Board ID。
  - 在 U-Boot 和 Kernel 中添加相关配置文件和设备树（ DTB），包括管脚复用配置、功能开关设置等。
  - 根据硬件设计完成低速总线外设驱动（如 UART、 I2C、 SPI、 PWM 等）的移植，确保完成以太网和 USB 等的驱动适配。
  - 根据产品设计需求规划分区表。
- 硬件设计检查与电压域配置
  - 根据设计确认所有功能模块的管脚电压域配置，确保与硬件电路设计一致。
  - <font color=red>**特别注意：错误的电压域配置可能导致芯片损坏或设备不可预测行为，应格外重视。**</font>

参与人： 软件工程师为主，硬件工程师配合澄清硬件设计上的规格。

### 硬件回板检查与调试

- 硬件检查
  - **外观检查**：确保元器件无漏贴、错贴或焊接问题。
  - **供电检查**：上电后，使用万用表或示波器测量芯片供电是否稳定、符合设计要求。
- 初步功能验证
  - 通过串口连接设备，观察 debug 串口输出日志：
    - **无日志**：需重点检查供电、复位信号及时钟源是否正常。
    - **日志异常**：根据错误提示定位问题原因。
    - **正常日志**： 为烧录系统镜像的硬件，上电启动时，正常会进入串口下载模式，在串口上连续打印 `C` 字符。
- 系统烧录
  - 烧录最小系统镜像，具体操作参考 [ 系统镜像烧写指南 ](../quick_start/update_system_firmware.md)。

参与人： 硬件工程师为主，软件工程师提供系统镜像，同步协调完成系统烧录。

### 启动异常排查

- miniboot 阶段卡住
  - 检查 DDR 的型号、容量是否识别正确，确保参数 Training 成功。
  - 确认 U-Boot 加载流程无异常。
- U-Boot 阶段卡住
  - 检查硬件 Board ID 是否识别正确。
  - 检查 Kernel 加载参数（ bootargs/cmdline）是否正确。
  - 检查是否加载了正确的设备树。

参数人： 软件工程师为主，硬件工程师配合澄清硬件设计上的规格。

### 系统功能摸底

- 内核启动验证
  - 检查内核启动日志，确认驱动模块加载和设备驱动初始化无误。
  - 验证根文件系统、应用程序（ app）、用户数据分区（ userdata）挂载是否正常。
- 功能接口测试
  - 测试网络接口（如 SSH 登录）、 USB 端口功能（如 ADB 连接）是否正常。
  - 硬件上有以太网的情况下，确保系统可以进入 shell 并完成基本操作。
  - 硬件上有 USB 从设备接口的情况下，确保系统可以进入 adb shell 并完成基本操作。

参与人： 软件工程师。

### 系统稳定性测试

- 压力测试
  - 对 CPU、 DDR、 BPU 、 eMMC / Nand Flash 等核心硬件进行高负载测试。
  - 根据具体产品需求测试特定功能模块的性能和稳定性。

参与人： 测试工程师为主，软件工程师提供必要的测试软件和环境搭建方法。

## <span id="new_board_config"/> 新增板级配置

板级配置是系统开发中，为特定硬件平台定制的编译和运行环境设置文件。通过板级配置，开发者可以定义硬件的关键参数，如芯片型号、架构、交叉工具链路径、分区信息以及根文件系统等。这些配置文件确保编译系统能够生成适配目标硬件的固件，同时简化了不同硬件版本之间的切换和维护。

在多硬件平台共用一套代码的场景中，每款硬件需要单独的板级配置文件，以便根据硬件特性启用特定功能、加载对应驱动，并保证系统的兼容性和稳定性。

以下是 `device/horizon/x5/board_x5_evb_release_config.mk` 的示例内容，展示了典型的板级配置文件结构和设置：

```bash
#!/bin/bash

export HR_TARGET_VENDOR="horizon"
export HR_TARGET_CHIP="x5"
export HR_SECURE_CHIP=y
export HR_TARGET_BIT="64"
export HR_TARGET_MODE="release"

# 板级名称，对应每一个新的硬件型号
export HR_BOARD_TYPE="soc"

# 编译 out 目录
export HR_BUILD_OUTPUT_DIR=${HR_TOP_DIR}/out
# 编译中间文件输出目录，如 uboot、 kernel、 hbre 的编译目录
export HR_TARGET_BUILD_DIR=${HR_BUILD_OUTPUT_DIR}/build
# 产出镜像输出路径，本目录下的镜像文件用于烧录和发布
export HR_TARGET_PRODUCT_DIR=${HR_BUILD_OUTPUT_DIR}/product
# 从 build 到 product 的中间产物，如内核、设备树、根文件系统的原始目录和文件
export HR_TARGET_DEPLOY_DIR=${HR_BUILD_OUTPUT_DIR}/deploy
# 编译日志保存目录
export HR_BUILD_LOG_DIR=${HR_BUILD_OUTPUT_DIR}/build_log

# 板级配置文件存放目录
export HR_BOARD_CONF_DIR=${HR_TOP_DIR}/"device/horizon/${HR_TARGET_CHIP}/board_cfg/${HR_BOARD_TYPE}"

# 配置交叉编译工具链
export ARCH="arm64"
export TOOLCHAIN_PATH=/opt/arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu
export CROSS_COMPILE=${TOOLCHAIN_PATH}/bin/aarch64-none-linux-gnu-

# 使能 ccache，加速编译
export HR_CCACHE_SUPPORT=y
export CCACHE_COMMAND="ccache"
export HR_APPEND_CXX_OPTIONS="-DCMAKE_CXX_COMPILER=\"${CCACHE_COMMAND}\" -DCMAKE_CXX_COMPILER_ARG1=\"${CROSS_COMPILE}g++\" -DCMAKE_C_COMPILER=\"${CCACHE_COMMAND}\" -DCMAKE_C_COMPILER_ARG1=\"${CROSS_COMPILE}gcc\""
export HR_CCACHE_DIR="$HOME/.ccache"

# 构建系统常用的工具软件存放路径，比如 fiptool
export HR_BUILD_TOOL_PATH=${HR_TOP_DIR}/build/tools
# 分区表， mbr， gpt 内容处理的工具软件存放路径
export HR_PARTITION_TOOL_PATH=${HR_TOP_DIR}/build/tools/partition_tools
# avbtools 工具脚本存放路径，在对 kernel 和分区文件系统添加校验信息时需要使用到（ mk_system.sh）
export HR_AVB_TOOLS_PATH=${HR_TOP_DIR}/build/tools/android_tools/avbtools
export HR_BD_IMG_TOOLS_PATH=${HR_TOP_DIR}/build/tools/android_tools/build_image

# 分区表配置文件所在目录和文件名
export HR_PART_CONF_FILENAME=${HR_BOARD_CONF_DIR}/x5-soc-release-gpt.json
export BLK_SZ=512
export MMC_UFS_ERASE_SIZE=524288
export NOR_ERASE_SIZE=32768
export HYPER_ERASE_SIZE=262144

# uboot 编译配置文件
export HR_UBOOT_CONFIG_FILE=hobot_x5_auto_defconfig
export HR_ARCH_UBOOT="arm"
# 指定 uboot 源码的输出目录，如果不设置，则在源码目录下编译
export HR_UBOOT_OUTPUT_DIR=${HR_TARGET_BUILD_DIR}/uboot

# kernel 配置
# kernel 编译配置文件
export HR_KERNEL_CONFIG_FILE=hobot_x5_soc_perf_defconfig
export HR_ARCH_KERNEL="arm64"
# 指定内核源码的输出目录，如果不设置，则在源码目录下编译
export HR_KERNEL_OUTPUT_DIR=${HR_TARGET_BUILD_DIR}/kernel

# system 配置
# 指定根文件系统类型和预编译的文件系统路径
export HR_SYSTEM_TYPE="buildroot"
export HR_SYSTEM_DIR=${HR_TOP_DIR}/system/buildroot/prebuilt
# 根文件系统的分区名，需要和分区表配置对应
export HR_SYSTEM_PART_NAME="system"
# system verify method: dm-verity, crypt
export HR_SYSTEM_VERIFY="dm-verity"

# 设置 SDK 版本
source "${HR_TOP_DIR}/device/${HR_TARGET_VENDOR}/${HR_TARGET_CHIP}/dr_release_version.mk"
export HR_BUILD_VERSION="${HR_RELEASE_VERSION}"

# antirollback version
export ANTIROLLBACK_SEC_UPDATE="false"
export ANTIROLLBACK_SEC_VER=0
export ANTIROLLBACK_NOSEC_UPDATE="false"
export ANTIROLLBACK_NOSEC_VER=0

# 环境变量配置标志，用来标识当前 env 环境已经完成了板级配置项的设置
export HR_IS_BOARD_CONFIG_EXPORT="true"
```

### 关键配置项解析

1. **目标硬件信息**
   - `HR_TARGET_VENDOR` 和 `HR_TARGET_CHIP` 定义了目标硬件的供应商和芯片型号。
   - `HR_BOARD_TYPE` 用于区分具体的硬件板型。
2. **编译输出路径**
   - `HR_BUILD_OUTPUT_DIR` 是所有编译产物的总目录，`HR_TARGET_PRODUCT_DIR` 用于存放最终产出的镜像文件。
3. **工具链配置**
   - 使用 `CROSS_COMPILE` 配置交叉编译工具链，支持指定编译架构和工具路径。
4. **分区表选择**
   - 使用 `HR_BOARD_CONF_DIR`、`HR_PART_CONF_FILENAME` 指定使用的分区表配置文件。
5. **模块配置**
   - 包括 U-Boot、 Kernel、系统分区表等模块的编译配置文件和路径设置。
6. **优化与工具支持**
   - 启用 `ccache` 可以加速编译，通过工具路径定义便于调用构建工具和分区工具。

### <span id="bsp_part_conf"> 分区配置

分区表的配置通过 `HR_BOARD_CONF_DIR`、`HR_PART_CONF_FILENAME` 关键选项指定：

```bash
# 板级配置文件存放目录
export HR_BOARD_CONF_DIR=${HR_TOP_DIR}/"device/horizon/${HR_TARGET_CHIP}/board_cfg/${HR_BOARD_TYPE}"

# 分区表配置文件所在目录和文件名
export HR_PART_CONF_FILENAME=${HR_BOARD_CONF_DIR}/x5-soc-release-gpt.json
```

分区表定义了存储设备上的数据布局，包含关键的分区信息，如系统、用户数据、引导分区等。开发新硬件时，需要根据硬件特性和产品需求调整分区表配置文件。

#### 分区表文件说明

分区表文件位于 `device/horizon/x5/board_cfg/*`，文件一般以 `gpt.json` 结尾。

以 `device/horizon/x5/board_cfg/soc/x5-soc-release-gpt.json` 为例：

```JSON
{
        "gpt": {
                "size": "20k"
        },
        "mbr": {
                "size": "4k"
        },
        "miniboot": "sub_config/miniboot.json",
        "misc": {
                "size": "4k"
        },
        "uboot": {
                "part_type": "GOLDEN",
                "size": "2m"
        },
        "ubootenv": {
                "size": "256k"
        },
        "vbmeta": {
                "part_type": "GOLDEN",
                "size": "16k"
        },
        "boot": {
                "part_type": "GOLDEN",
                "size": "12m"
        },
        "system": {
                "fs_type": "ext4",
                "part_type": "GOLDEN",
                "size": "250m"
        },
        "hbre": {
                "fs_type": "ext4",
                "part_type": "GOLDEN",
                "size": "200m"
        },
        "app": {
                "fs_type": "ext4",
                "part_type": "GOLDEN",
                "size": "700m"
        },
        "private": {
                "fs_type": "ext4",
                "part_type": "GOLDEN",
                "size": "256k"
        },
        "userdata": {
                "fs_type": "ext4",
                "size": "50m"
        }
}
```

**分区字段说明：**

- **gpt**: 此分区表镜像保存位置，U-Boot 、Kernel 和 用户态的 parted、fdisk 工具会读取此信息获得系统得分区表。
- **mbr**: 此分区存放 ROMCODE 能解析的分区信息，记录 BL2、DDR 参数、BL3x 等固件在镜像中的存放位置。
- **miniboot**: 该定义是一个分区子集，在 `sub_config/miniboot.json` 文件中包含 miniboot.img 镜像内部的分区情况。**用户不需要去修改它，否则会带来不必要的适配开发工作。**
- **misc**: 在运行时此分区记录升级信息，并在 AB 分区模式下保存当前使用的分区编号。
- **uboot**: miniboot 分区之后 **必须是以 uboot 或者 u-boot 为前缀命名的分区名**， miniboot 的镜像的整体打包会依赖该分区名做为分界线。
- **ubootenv**: 在 U-Boot 下执行 saveenv 后会保存 U-Boot 环境变量到该分区。
- **boot、system、vbmeta**: vbmeta 分区默认会储存 boot、 system 的 avb 验证信息。如果开启安全启动功能的情况下，这三个分区需要同步更新。如果用户想要修改这三个分区的命名，需要在 uboot 中修改对应的代码。根文件系统里面需要修改 hb-fstab 调整分区挂载配置。
- **其他分区**: 其他分区用户可以根据产品实际需要进行调整。

**必选属性说明：**

- **fs_type**: 定义该分区镜像的文件系统类型，必须提供。可以选择以下之一：
  - **raw/null**: 表示原始数据类型的镜像。
  - **ext4/fat32**：表示具体文件系统类型。
- **size**: 表示该分区镜像的总占用空间，必须提供（单位为 k、 m、 g）。在 NOR Flash 存储器上，必须按照 64KB 对齐；在 eMMC 存储上，必须按照 4KB 对齐。确保分区镜像的总占用空间等于分区组件占用空间之和。

**可选属性说明（不配置时可为空）**：

- **part_type**: 定义分区升级类型（可选属性）。可选择以下之一：
  - **AB**: 双分区，用于 A/B 系统更新。
  - **BAK**: 备份分区，当主分区无法正常使用时，会尝试从备份分区启动，是保证系统稳定性的一种策略。
  - **GOLDEN**: 单分区，用于常规系统更新。
  - **PERMANENT**: 永久性分区，不会进行升级的分区。**若不配置，默认为本属性**。

- **ota_is_update**: 定义分区是否可以进行 OTA 升级（可选属性）。可选择以下之一：
  - **true**: 支持进行 OTA 升级。
  - **false**: 不支持进行 OTA 升级。**若不配置，默认为本属性**。

- **ota_update_mode**: 定义分区的 OTA 升级方式（`ota_is_update` 必须为 true）。可选择以下之一：
  - **image**: 镜像全量升级。

- **medium**: 表示这个分区镜像烧录的介质。

- **fde_type**: 定义用户分区的加密方式，可选择以下方式：
  - **key-file**: 使用key文件直接加解密分区，详细操作方式可以参考 [用户分区加密: key-file 方案](system_component_development/security_development/fde/1-fde.html#fde_solution_3)

**注意**

如果要在 NAND 上增加新分区，请使用 ubi 类型的分区格式，分区的 ubi 镜像正常输出到 "out/product/" 下。如果此分区要支持 OTA 升级，请将 ubi 镜像中的卷镜像和 ubi 配置文件输出到 "out/deploy/ubi/" 下，卷镜像的后缀名可以是 { 卷名 }.bin|.img|.ubifs，配置文件名是 {ubi 分区名 }.cfg

### <span id="UBoot_Option_config"/>U-Boot 选项配置

板级配置文件 `board_xxx_config.mk` 会指定 U-Boot 使用的选项配置文件，相关选项在 [ 板级配置文件 ](#span-id-new-board-config) 中配置如下：

```bash
# 建议：每次新增硬件时都对应添加一套 HR_BOARD_TYPE、 HR_UBOOT_CONFIG_FILE、 HR_KERNEL_CONFIG_FILE、 uboot 和 kernel 下的 dts 设备树

# uboot 编译配置文件
export HR_UBOOT_CONFIG_FILE=hobot_x5_auto_defconfig
export HR_ARCH_UBOOT="arm"
# 指定 uboot 源码的输出目录，如果不设置，则在源码目录下编译
export HR_UBOOT_OUTPUT_DIR=${HR_TARGET_BUILD_DIR}/uboot
```

为确保系统兼容性，建议每款硬件新增专属的 U-Boot 选项配置文件和设备树文件。这些文件分别位于 U-Boot 源码树的以下目录中：

- 配置文件路径：`configs/`
- 设备树文件路径：`arch/arm/dts/`

建议每次新增核心板时，均同步更新以下内容：

- `HR_UBOOT_CONFIG_FILE`（ U-Boot 配置文件）
- U-Boot 设备树文件

### Kernel 选项配置

板级配置文件 `board_xxx_config.mk` 会指定 Kernel 使用的选项配置文件，相关选项在 [ 板级配置文件 ](#span-id-new-board-config) 中配置如下：

```bash
# kernel 编译配置文件
export HR_KERNEL_CONFIG_FILE=hobot_x5_soc_perf_defconfig
export HR_ARCH_KERNEL="arm64"
# 指定内核源码的输出目录，如果不设置，则在源码目录下编译
export HR_KERNEL_OUTPUT_DIR=${HR_TARGET_BUILD_DIR}/kernel
```

为确保系统兼容性，建议每款硬件新增专属的 Kernel 选项配置文件和设备树文件。对应文件存储路径如下：

- 配置文件路径：`arch/arm64/configs/`
- 设备树文件路径：`arch/arm64/boot/dts/hobot/`

新增硬件时，请确保以下内容得到更新：

- `HR_KERNEL_CONFIG_FILE`（ Kernel 配置文件）
- Kernel 设备树文件

## 在 U-Boot 下新增硬件

当用户需要为新型号的硬件开发适配时，为了确保同一套软件固件能够兼容不同的硬件平台，需要进行以下步骤：

1. **定义新的 Board ID**

   为新硬件分配一个唯一的 Board ID，这样可以在系统中区分不同的硬件平台。在 X5 平台上， Board ID 通过 4 个 ADC 通道来定义，基于不同的外部电压值进行硬件识别。该 Board ID 在系统启动时用于确定当前硬件平台的配置，并据此加载相应的固件或驱动。

   有关 Board ID 的详细信息，请参阅 [ 硬件 Board ID 概述 ](#board-id)。

   **注**：在 U-Boot 调试阶段，用户也可以选择在软件中强制定义 Board ID，而无需依赖硬件的 ADC 通道。这种方法可以方便地在开发和测试阶段进行硬件适配和调试。

2. **在 U-Boot 中进行移植**

   在 U-Boot 中，需要根据新硬件的特性进行适配，修改或添加相应的配置文件。具体的移植工作包括：

   - 新增 U-Boot 配置文件。

   - 添加或修改硬件相关的设备树（ Device Tree）文件，以支持新硬件的外设和功能。

通过这些步骤，用户可以确保同一套固件在多个硬件平台上正常运行，简化了不同硬件型号的开发和维护工作。

### 硬件 Board ID 概述

在 X5 平台上， Board ID 通过 4 个 ADC 通道来定义，基于不同的外部电压值进行硬件识别。当前 ADC 通道（ ADC_VINS ）的配置情况如下：

- ADC_VINS0 ：主板类型，即不同的 X5 项目用不同的 ID 区分。比如：用户内部有两个 X5 项目序列，那么可以使用 VIN0 外部配置不同分压，以进行区分。
- ADC_VINS1 ：用于在某一项目序列下，区分不同的硬件版本。比如：第一次硬件发板、第二次硬件发板。
- ADC_VINS2 ： DDR 参数配置，用户应当根据对应主板 BOM 的 DDR 配置，**必须严格按照官方硬件参考设计选择对应档位**。
- ADC_VINS6 ：预留档位，建议用户 NC。如有 ADC 需求，优先选用其他 ADC 通道（ ADC_VIN ）。

硬件 Board ID 的硬件参数设计如下，为确保 ADC 端口能够准确读取电压值，需要在其电路中设计 100nF 去耦电容和对应的分压电阻。

![image-20241225152523451](./_static/_images/board_bring_up/image-20241225152523451.png)

**ADC 外部分压电阻的选择：**

参考官方硬件参考设计，对上拉、下拉电阻进行选型，电阻值和不超过 50K Ω 。一般来说，大电阻（尤其上百 K Ω ）的时候，有如下问题：

- 高阻值电阻，会导致内部 ADC 采样存在明显的 RC 效应，影响采样精度。

- 高阻值电阻更容易引入噪声。

- ADC 在应用时，大部分时候都会在 50K Ω 以内， 100K Ω 以上应用很少见。

如下分压电阻组合，供参考：

| 模拟电压配置 | R1    | R2   | 精度 |
| ------------ | ----- | ---- | ---- |
| 100mV        | 16K   | 1K   | 1%   |
| 200mV        | 16K   | 2K   | 1%   |
| 300mV        | 10K   | 2K   | 1%   |
| 400mV        | 23.7K | 6.8K | 1%   |
| 500mV        | 5.1K  | 2K   | 1%   |

**ADC 电压档位设计要求及建议：**

建议用户按照本章节提供的参考值区分模拟电压，不要自定义模拟电压区间。即，各档位典型值必须是 100mV、 200mV，以此类推。因此，每个字段最多支持 17 档位（ ADC 电压范围 0.1 ~ 1.7 V）。

每一个模拟电压对应的软件档位序次（比如， 100mV 在软件内映射为 ID = 1 ），为软件自定义映射，无强制要求。

**ADC_VINS2 为强制约束，与 DDR Type 相关，具体说明如下：**

- X5 平台支持的 DDR 规格为 **总位宽 32 位**，采用 **2 通道设计**，每通道位宽为 16 位（即 2CH x 16 = 32 位）。 DDR 颗粒架构中的各个 Die 位宽要求为 **x16**。在设计中需确保 DDR 的频率、容量满足平台性能需求，同时注意 PCB 布线的信号完整性和等长设计，以确保系统稳定性和兼容性。

- X5 支持 LPDDR4 和 LPDDR4X 两种模式；支持单 Rank 和双 Rank 两种模式，需要通过 ADC_VINS2 区分。

- ADC_VINS2 的档位无需体现 DDR 容量， 目前支持 1GB / 2GB / 4GB / 8GB 容量的 DDR。

- 具体支持的型号，请参考 [Approved Vendor List](approved_vendor_list.md)。

**特别提示：档位值请按照1~17来配置，切勿直接将 ADC 输入下拉（档位0）或接上拉电源（档位18）。**

**ADC 采样范围、分压值、档位值分配参考如下表所示：**

![image-20241225160051067](./_static/_images/board_bring_up/image-20241225160051067.png)

### 新增 U-Boot 选项配置文件

以创建一个名为 `som` 的新硬件为例，说明开发和移植所需的具体步骤：

1. **进入 U-Boot 源码树**

   首先进入 U-Boot 的源码目录，并导航到 `configs` 子目录。

2. **复制基础配置文件**

   使用现有的 `hobot_x5_auto_defconfig` 作为基础配置文件，为新硬件生成专属配置文件。例如，对于一个名为 `som` 的核心板，可以按以下命令命名新的配置文件为 `hobot_x5_som_defconfig`：

   ```
   cd configs
   cp hobot_x5_auto_defconfig hobot_x5_som_defconfig
   ```

3. **修改配置项**

   根据新硬件的产品设计需求，编辑 `hobot_x5_som_defconfig` 文件，调整其中的配置项，例如启动参数、存储接口、外设支持等内容，以适配硬件特性。

### 新增软件 Board ID 的定义

在适配新硬件时，需要为其分配一个唯一的 **Board ID**，以区分不同硬件平台。[ 硬件 Board ID](#board-id)  通过 ADC 通道的电压值读取出来的硬件识别信息。为了增强灵活性和适配性，系统还需要定义 **软件 Board ID**，**软件 Board ID** 会映射到 **硬件 Board ID**。

以创建一个名为 `som` 的新硬件为例，说明新增软件 Board ID 的步骤：

#### 修改 Kconfig 文件

在 `drivers/horizon/Kconfig` 文件中，为新硬件添加一个 `choice` 项，用于选择新硬件的 Board ID。以下是示例代码：

```
config HOBOT_X5_SOM
        bool "X5SOM"
        help
          Select this option for Board Type X5 SOM.
```

该选项允许在编译时选择新硬件类型 `X5 SOM`。

#### 修改 Board ID 的宏定义

在 `include/dt-bindings/board/hb_board_id.h` 文件中：

- **新增软件 Board ID 的宏定义**

  为新硬件分配一个唯一的 ID，例如：

  ```
  #define HOBOT_X5_SOM_ID 0x2000
  ```

- **添加宏条件判断**

  将新的宏定义与对应的配置选项绑定，确保系统在识别硬件时正确加载相应的 Board ID。示例如下：

  ```
  #if defined(CONFIG_HOBOT_X5_FPGA)
      #define HOBOT_X5_BOARD_ID HOBOT_X5_FPGA_ID
  #elif defined(CONFIG_HOBOT_X5_EVB)
      #define HOBOT_X5_BOARD_ID HOBOT_X5_EVB_ID
  #elif defined(CONFIG_HOBOT_X5_SOM)
      #define HOBOT_X5_BOARD_ID HOBOT_X5_SOM_ID
  #elif !defined(CONFIG_HOBOT_ADC_BTYPE)
      #define CONFIG_HOBOT_ADC_BTYPE
  #endif
  ```

#### 避免软件 Board ID 冲突

官方 BSP 中使用 **0x0000 ~ 0x1FFF** 范围的软件 Board ID。为避免与 BSP 的后续更新发生冲突，建议用户新增的软件 Board ID 避免使用此范围，推荐分配范围在 **0x2000 及以上**。

#### 检查新增内容

使用 `git diff` 检查代码改动，确保新增内容正确且完整。例如：

```
diff --git a/include/dt-bindings/board/hb_board_id.h b/include/dt-bindings/board/hb_board_id.h
index 8ed2b921ee..b12f4b5505 100644
--- a/include/dt-bindings/board/hb_board_id.h
+++ b/include/dt-bindings/board/hb_board_id.h
@@ -13,6 +13,7 @@
 #define HOBOT_X5_EVB_ID    0x0201
 #define HOBOT_X5_EVB_V2_ID 0x0202
 #define HOBOT_X5_RDK_ID    0x0301
+#define HOBOT_X5_SOM_ID    0x2000

 #if defined(CONFIG_HOBOT_X5_FPGA)
     #define HOBOT_X5_BOARD_ID HOBOT_X5_FPGA_ID
@@ -24,6 +25,8 @@
     #define HOBOT_X5_BOARD_ID HOBOT_X5_EVB_ID
 #elif defined(CONFIG_HOBOT_X5_EVB_V2)
     #define HOBOT_X5_BOARD_ID HOBOT_X5_EVB_V2_ID
+#elif defined(CONFIG_HOBOT_X5_SOM)
+    #define HOBOT_X5_BOARD_ID HOBOT_X5_SOM_ID
 #elif !defined(CONFIG_HOBOT_ADC_BTYPE)
     #define CONFIG_HOBOT_ADC_BTYPE
 #endif
```

#### 硬件 Board ID 和软件 Board ID 的关系

- **硬件 Board ID** 是通过 ADC 通道的电压值，读取的唯一标识，用于启动时识别硬件平台。
- **软件 Board ID** 是在开发和编译过程中定义与硬件 Board ID 有映射关系的软件定义。

通过这种方式，硬件和软件 Board ID 的结合能够灵活适配不同的硬件平台，同时支持定制化功能开发。

### <span id="New_UBoot_Dts"/>新增 U-Boot 下的设备树

以创建一个名为 `som` 的新硬件为例，说明为其添加设备树定义的步骤：

#### 创建设备树文件

进入 U-Boot 的设备树目录 `arch/arm/dts`，复制现有的 `x5-soc.dtsi` 文件并命名为 `x5-som.dtsi`：

```
cd arch/arm/dts
cp x5-soc.dtsi x5-som.dtsi
```

在新文件 `x5-som.dtsi` 中修改以下内容：

- 修改 `supported-btype` 节点的值为 `HOBOT_X5_SOM_ID` （在新增软件 Board ID 的定义章节中添加的定义）。

```
btype-dev = &board_type;
supported-btype =
        <
        HOBOT_X5_SOM_ID
        >;
```

- 把 x5-som.dtsi 文件中所有的 `x5_soc` **替换为** `x5_som`。

#### 在主设备树文件中添加新文件

将新增的 `x5-som.dtsi` 文件包含到主设备树文件 `arch/arm/dts/x5.dtsi` 中。在文件末尾添加如下内容：

```
#include "x5-soc.dtsi"
#include "x5-som.dtsi"
```

#### 修改 `board_type` 配置

在 `arch/arm/dts/x5.dtsi` 文件中，更新 `board_type` 节点以支持新的硬件 Board ID，步骤如下：

1. 在 `board_type_array` 中新增 `HOBOT_X5_SOM_ID` 的定义。例如新增 `<51 140 151 240 HOBOT_X5_SOM_ID 5 0 0 1 4> `：

   ```
   board_type: board_type {
           compatible = "hobot,btype";
           adc_dev = &adc, &adc;
           adc_channel = <0 1>;
           board_type_array =
                           ... ( 省略 ) ...
                           <51 140 151 240 HOBOT_X5_SOM_ID 5 0 0 1 4>,
                           ... ( 省略 ) ...
           hardware_array = "x5-fpga", "x5-soc", "x5-svb", "X5_EVB_LP4", "X5_EVB_LP4X", "X5-SOM";
           ethact_array = "default";
           net_eth0_ipaddr = "192.168.1.10";
           pmic_type = "dual-pmic", "single-pmic";
           board_version = "1_A", "1_B", "V1P2", "V1P3", "V0P1";
   };
   ```

2. 确保 `hardware_array` 中新增对应的硬件名称 `"X5-SOM"`：

   ```
   hardware_array = "x5-fpga", "x5-soc", "x5-svb", "X5_EVB_LP4", "X5_EVB_LP4X", "X5-SOM";
   ```

board_type_array 中的各字段含义如下：

- 前 4 个字节定义了 ADC 通道的电压值范围，用于硬件识别：

  - `51 140`：对应 `ADC_VINS0` 通道的电压范围（ 51 ~ 140 mV），用于区分硬件类型。硬件上的分压电路将电压分压至 100 mV 左右，设置该范围以适应可能的电压波动。
  - `151 240`：对应 `ADC_VINS1` 通道的电压范围（ 151 ~ 240 mV），用于区分硬件版本。硬件上的分压电路将电压分压至 200 mV 左右，设置该范围以适应可能的电压波动。

- 第 5 个字节表示软件 Board ID （ HOBOT_X5_SOM_ID）

  - 硬件与软件 Board ID 的绑定逻辑如下：

    如果 U-Boot 选项中启用 `CONFIG_HOBOT_ADC_BTYPE`，系统会通过 `hb-btype.c` 驱动读取硬件板卡的 ADC 通道电压值，并与设备树 `board_type_array` 中定义的电压值范围进行匹配，以确定对应的硬件类型和硬件版本。匹配成功后，系统会将硬件 Board ID 映射为对应的软件 Board ID，用于后续的设备识别和适配。

    例如，对于 `board_type_array` 定义 `<51 140 151 240 HOBOT_X5_SOM_ID 5 0 0 1 4>`，当硬件的 `ADC_VINS0` 通道检测到电压值在 `51 ~ 140 mV` 范围内，且 `ADC_VINS1` 通道检测到电压值在 `151 ~ 240 mV` 范围内时，系统会识别当前硬件为 `HOBOT_X5_SOM_ID`。

- 其他字段含义

  从 `HOBOT_X5_SOM_ID` 开始，每个字段对应不同的硬件特性配置数组，数字代表对应数组的下标：

  - 硬件型号命名 (`hardware_array`)

  - 以太网配置 (`ethact_array`)

  - IP 地址 (`net_eth0_ipaddr`)

  - 硬件使用的单个 PMIC 还是双 PMIC  (`pmic_type`)，绝大部分情况都只使用 `single-pmic`

  - 硬件版本 (`board_version`)

  例如 `<51 140 151 240 HOBOT_X5_SOM_ID 5 0 0 1 4>`  中的 5 对应 hardware_array 中的 `X5-SOM`，其他字段同理。

#### **注意事项**

- **字符串长度限制**

  hardware_array 和 board_version 中的字符串会传递到 Kernel 的设备树中，影响 socinfo  驱动的以下字段：

  - `hw_name`

  - `board_version`

  - `hw_info`

​	需确保字符串长度不超过 Kernel 中的占位符限制，否则会导致 `socinfo` 驱动加载失败。

- **必要调整**

  如果字符串长度超出限制，请同时更新 Kernel 的设备树占位符，具体参考 [boardinfo 调试指南](driver_develop_guide/44-boardinfo.html#span-id-kernel-socinfo-boardinfo)。

### 在 U-Boot 配置中应用 Board ID

完成新硬件的 Board ID 定义、选项配置文件、设备树修改后，需要重新配置 U-Boot，以设置 `CONFIG_HOBOT_X5_SOM` 宏为新增的 Board ID。以下是详细步骤：

#### 使用新增的选项配置文件

执行以下命令，加载新硬件的配置文件：

```bash
make ARCH=arm hobot_x5_som_defconfig
make ARCH=arm menuconfig
Location:
  │     -> Device Drivers
    │ (1)   -> Horizon SOC drivers
```

在 `menuconfig` 界面中，导航至 `Horizon SOC drivers`，选择与新硬件对应的 Board ID（如 `HOBOT_X5_SOM`），确保配置正确：

![uboot_boardid](./_static/_images/board_bring_up/uboot_boardid.png)

#### 保存配置

在 `menuconfig` 界面中保存已配置的选项，然后使用以下命令将最简洁的选项保存到配置文件中：

```
# 使用 savedefconfig 保存最小化的配置项
make ARCH=arm savedefconfig

# 对比修改内容（如果使用 git 管理代码，可以跳过此步骤，直接使用 git diff 查看修改）
diff defconfig configs/hobot_x5_som_defconfig

# 确认无误后，将配置覆盖到源文件
cp defconfig configs/hobot_x5_som_defconfig
```

通过上述步骤，您已成功将新增的 Board ID 应用到 U-Boot 配置中，并为新硬件适配做好准备。

## 在 Kernel 下新增硬件

相对于 **U-Boot**，在 **Kernel** 中新增硬件支持有以下区别和特点：

- 不需要再定义 Board ID， U-Boot 下的定义会直接传导过来
- U-Boot 下的设备树配置更加简单，只需保证基本的初始化和引导系统启动。 Kernel 负责操作系统加载后硬件功能的全面管理，配置文件和设备树更细致，涵盖了完整的外设驱动支持（如 GPIO、 I2C、 SPI、显示设备）和功能模块的使能 / 禁用。
- Kernel 下增加的设备树文件全都可以独立编译成 DTB 文件，用户可以选择使用。 U-Boot 下的设备树文件都包含在一个 DTB 文件中，驱动根据硬件 Board ID 完成匹配。

### 新增 Kernel 配置文件

进入 Kernel 源码树后，导航到配置文件目录 `arch/arm64/configs`，复制现有的 `hobot_x5_soc_defconfig` 文件并重命名为新硬件的配置文件（例如 `hobot_x5_som_defconfig`）：

```
cd arch/arm64/configs
cp hobot_x5_soc_defconfig hobot_x5_som_defconfig
```

根据产品设计需求，修改该文件中的配置项以适配新硬件。

### 新增设备树

Kernel 设备树文件位于目录 `arch/arm64/boot/dts/hobot`，目录结构如下：

```Shell
.
├── Makefile
├── pinmux-func.dtsi
├── pinmux-gpio.dtsi
├── x5-evb-lp4-1_a.dts
├── x5-evb-lp4-1_b.dts
├── x5-evb-lp4-v1p2.dts
├── x5-evb-lp4-v1p3.dts
├── x5-evb-lp4-v2p0.dts
├── x5-evb-lp4x-v0p1.dts
├── x5-evb.dtsi
├── x5-fpga.dts
├── x5-md-v0p1.dts
├── x5-md-v0p2.dts
├── x5-memory.dtsi
├── x5-rdk-v1p0.dts
├── x5-rdk.dts
├── x5-rdk.dtsi
├── x5-som.dts
├── x5-svb.dts
└── x5.dtsi
```

- **`pinmux-func.dtsi`**：定义各个 PIN 的功能组。板级设备树 `.dts` 文件通过以下方式包含：

  ```
  #include "pinmux-func.dtsi"
  ```

- **`pinmux-gpio.dtsi`**：定义 GPIO 组，用户可直接引用具体 GPIO 组（`PINGRP`）。

- **`x5.dtsi`**：定义 X5 平台上所有模块的默认配置，作为底层功能描述，不建议用户修改里面配置。

- **`x5-evb.dtsi`**: 定义了不同 EVB 硬件版本间的通用配置项，包含 `x5.dtsi` 的默认配置。

- **`x5-<板级产品>.dts`**：板级产品设备树文件，包含 `x5.dtsi` 的默认配置，同时完成功能模块的启用 / 禁用和与硬件强相关外设的定义。 EVB 相关的 `dts` 配置是包含 `x5-evb.dtsi`， 然后在 `dts` 里面描述有差异的配置项。

以现有设备树文件为模板，新建新硬件的设备树文件，例如：

```
cd arch/arm64/boot/dts/hobot
cp x5-evb-lp4-1_b.dts x5-som.dts
```

根据新硬件的设计需求，修改 `x5-<new_board>.dts` 文件的内容，确保正确配置外设和模块。

### 模块默认状态说明

- 外设及显示相关模块默认不使能
- 图像处理及其他基础模块默认使能
- 低速总线默认不使能，用户根据硬件设计进行开启

### 编辑板级设备树

在板级设备树文件 `x5-< 板级产品 >.dts` 中：

1. **引用所有基础 dtsi 文件**：

   设备树文件需要直接包含板级产品相关的所有 dtsi 文件。例如：

   ```
   #include "x5.dtsi"
   ```

2. **配置时钟源和内存分布**：

   定义当前硬件的时钟源频率、内存分布。

3. **定义外设和模块配置**：

   将外设及其他模块的具体配置写入对应的 dtsi 文件，并根据硬件设计需求调整启用状态。

###  软件 Board ID 与设备树（ DTB）的匹配说明

在内核中，设备树（ DTS）需要与 Board ID 进行关联，以确保系统能够正确加载适配当前硬件的设备树。以下以 SOM 硬件为例，说明如何完成 Board ID 与设备树的匹配配置。

#### 配置 `its` 文件以新增设备树

在内核镜像的 `fit` 包中，需要修改对应的配置文件。路径：
`device/horizon/x5/board_cfg/soc/boot_its/x5-common.its`

1. 将新增的设备树文件（如 `x5-som.dts` 生成的 `x5-som.dtb`）打包到 `boot.img` 中。
   在 `its` 文件中按以下格式添加设备树配置项：

   ```text
   /dts-v1/;
   / {
           description = "U-Boot FIT for x5";
           #address-cells = <1>;
   
           images {
           	... ( 省略 ) ...
               fdt2 {
                       description = "FDT-SOM";
                       data = /incbin/("x5-som.dtb");
                       type = "flat_dt";
                       arch = "arm64";
                       compression = "none";
                       /*
                       hash-1 {
                               algo = "sha1";
                       };
                       */
               };
               ... ( 省略 ) ...
          };
          ... ( 省略 ) ...
   }
   ```

2. 在 `configurations` 节中，将 Board ID 与设备树关联：

   ```
   /dts-v1/;
   / {
           description = "U-Boot FIT for x5";
           #address-cells = <1>;
   
           ... ( 省略 ) ...
           configurations {
                   default = "boardid-0x0201";
                   ... ( 省略 ) ...
                   boardid-0xFE01 {
                           description = "x5-som";
                           kernel = "kernel";
                           fdt = "fdt2";
                   };
                   ... ( 省略 ) ...
           };
   };
   ```

#### 注意事项

1. **Board ID 格式：**
   - 配置项中的 **`boardid-0x0201`** 对应 U-Boot 中新增的 Board ID，例如 `HOBOT_X5_SOM_ID` 的值。
   - `boardid-0x0201` 会在 U-Boot 中被解析为字符串形式。
     如果 Board ID 中包含字母，必须 **使用大写字母**，如 `0xff10` 应写作 `0xFF10`。
2. **FDT 参数：**
   - `fdt` 字段需要对应新增的设备树配置项名称。例如，`boardid-0xFE01` 使用 `fdt2`，即 `x5-som.dtb`。

#### U-Boot 引导内核流程

在系统启动过程中， U-Boot 会根据当前硬件的 Board ID 选择对应的内核和设备树。引导命令如下：

```text
bootm ${kernel_addr}#boardid-${hb_board_id}
```

此命令中，`${hb_board_id}` 为当前硬件的软件 Board ID 值。 U-Boot 根据软件 Board ID 匹配到 `its` 文件中的 `fdt` 配置，加载正确的设备树与内核。

## 调试最小系统

在设备上电后，用户可通过调试串口检查是否有日志输出。如果没有日志输出，请检查以下问题：

- **芯片供电是否正常**
- **BOOTSEL 管脚配置是否正确**
- **调试串口与 PC 终端软件波特率是否匹配**

### 空片状态下的串口日志

当设备为空片状态时，芯片上电后的串口日志如下所示，最终进入 DFU 下载模式：

```shell
SNOTICE:  Welcome to Horizon X5 ASIC BOOTROM - V4.1
NOTICE:                 OTP config:
NOTICE:                         otp exist: true
NOTICE:                         test region size: 304
NOTICE:                         secure region size: 120
NOTICE:                         none secure region size: 56
NOTICE:   Enable MMU
NOTICE:  Booting Trusted Firmware
NOTICE:  BL1: v2.8(release):
NOTICE:  BL1: Built : 17:42:12, Oct 19 2023
NOTICE:  Enter eMMC Mode......
NOTICE:  USER AREA.
NOTICE:   eMMC clk_rate = CLK_12_5M
NOTICE:   eMMC emmc_data_width == WIDTH_DATA_1
NOTICE:   eMMC emmc_cfg.emmc_clk_latch == CLK_FALLING
NOTICE:  Enter media_source_select process(1).
ERROR:   horizon_emmc_read_blocks fail!!   checksum = 0x0 (0x0) 0x0
ERROR:    plat_error_handler 0
... ( 省略部分日志 ) ...
NOTICE:  Enter eMMC Mode......
NOTICE:  USER AREA.
NOTICE:   eMMC clk_rate = CLK_12_5M
NOTICE:   eMMC emmc_data_width == WIDTH_DATA_1
NOTICE:   eMMC emmc_cfg.emmc_clk_latch == CLK_FALLING
NOTICE:  Currtenly use dfu-util to download file
NOTICE:  Download file via USB
NOTICE:  DFU Start...
```

### 系统刷机

确认设备可以正常输出日志后，用户可将预先制作好的最小系统烧录到设备中。具体的刷机方法详见：[ 系统镜像烧写 ](../quick_start/update_system_firmware.html#span-id-system-update)。

若刷机后系统启动异常，可根据故障阶段进行逐步调试。

### 各阶段启动调试

#### 1. **miniboot 启动异常**

miniboot 负责完成 DDR 的初始化（ Training），并按顺序加载 **BL2**、**BL31** 和 **U-Boot**，最终跳转到 U-Boot。若 miniboot 启动失败，可能的原因包括：

- 镜像打包错误
- eMMC 或 Nand Flash 无法正确识别或数据读写失败
- DDR Training 未通过
- U-Boot 加载异常

#### 2. **U-Boot 启动异常**

U-Boot 用于引导 Linux 内核，启动失败的常见原因如下：

- **Kernel 分区加载异常**
- **cmdline 参数配置错误**

调试时，可通过 U-Boot 的日志确定具体问题。此外，应结合硬件设计确认常用模块功能是否正常，如网口、 USB 接口等。

**确认 USB Device 功能**
在 U-Boot 中切换到 **Fastboot 模式**，通过主机查看设备是否被识别：

```
Hobot> fastboot 0
select emmc(0) as flash medium
do fastboot usb
```

#### 3. **Kernel 启动异常**

若内核启动异常，可按以下步骤检查：

- **检查内核启动日志：** 确认内核模块和设备驱动初始化正常
- **检查文件系统挂载：** 确认根文件系统、`app` 和 `userdata` 分区是否挂载成功
- **检查终端登录：** 确认系统可正常进入 Shell 终端，并通过串口登录
- **检查外设功能：** 确认网络接口和 USB 接口工作正常

## 系统稳定性测试

完成硬件点亮后，需要针对新硬件的各个主要模块进行稳定性和压力测试，详细压测方法请参考 [ 驱动功能单元测试 ](chip_base_test)。

