摘要:本文是 Zephyr BSP 系列的第 30 篇,聚焦Board Support Package(BSP)的核心概念与落地方法。文章首先厘清 SoC、Board、BSP、Driver、Devicetree 的层次关系,指出SoC BSP 与 Board BSP 的本质区别;随后以 Company X1 EVK 为例,系统讲解 Board 目录结构、
x1_evk.dts如何描述板级硬件、为何 Board DTS 要 include SoC DTSI,以及 Kconfig、defconfig、board.cmake 各自承担的职责。文中强调“SoC DTSI 描述芯片事实,Board DTS 描述板级事实”这一关键原则,并给出 Board 与 Driver 的边界划分。最后通过west build -b x1_evk的完整流程,展示 BSP 如何驱动 DTS → DT macros →struct device的落地,并给出 BSP 的"完成标准"——以hello_world与blinky能否成功构建、烧录、运行为准。下一篇将深入west build -b xxx背后的 Board Discovery 机制。
Board Support Package(BSP)
前面20~29我们已经从"理解 Zephyr"一路进入了:
20理解 Zephyr BSP ↓21SoC Port Skeleton ↓22CPU / Architecture ↓23Startup ↓24Interrupt Controller ↓25Clock / Reset ↓26Devicetree ↓27Binding ↓28UART Driver ↓29GPIO / SPI / I2C / Timer ↓30Board Support Package30 篇的核心问题是:
到现在为止,我们已经把 Company SoC 接进 Zephyr 了。
但是 Zephyr 还不知道"公司到底哪一块开发板可以跑这个 SoC"。
这就是Board Support Package(BSP)要解决的问题。
一、先把一个非常重要的概念分清楚
很多初学者会把:
SoC Board BSP Zephyr Driver Devicetree混在一起。
实际上它们负责的层次不同。
可以先建立这样一张图:
Zephyr Application │ ▼ ┌─────────────────┐ │ Board │ │ Company EVK │ └────────┬────────┘ │ Board Devicetree │ ┌─────────────┴─────────────┐ │ │ ▼ ▼ Company SoC Board peripherals │ LED / Button / UART ▼ SoC Support │ ┌──────┼──────┐ ▼ ▼ ▼ CPU IRQ Clock/Reset │ ▼ Drivers所以:
SoC BSP和Board BSP不是一回事。
二、SoC 和 Board 到底有什么区别?
假设公司开发了一颗 SoC:
CompanySoC-X1
它可能有:
Cortex-M4 UART0 UART1 GPIO0 SPI0 I2C0 TIMER0 NVIC PLL Clock Controller Reset Controller那么这些属于:
SoC 本身
而公司可能做三块板:
Company EVK Company DevBoard Company Evaluation Board它们虽然全部使用:
CompanySoC-X1但是外围连接可能完全不同。
例如:
Board A
UART0 → USB-UART GPIO0_5 → Green LED GPIO0_6 → User Button SPI0 → Flash I2C0 → SensorBoard B
UART1 → USB-UART GPIO1_2 → Red LED GPIO1_3 → User Button SPI1 → Display I2C1 → PMICSoC 没变。
Board 变了。
因此:
SoC="芯片有什么能力"Board="这块板子把这些能力怎么连接出来"三、所以 Board Support Package 到底是什么?
在 Zephyr 里面,可以把 BSP 简化理解成:
让 Zephyr 知道某一块具体硬件板子应该如何启动、有哪些硬件、这些硬件连接在哪里。
它通常包含:
zephyr/ │ ├── boards/ │ └── company/ │ └── x1_evk/ │ │ │ ├── board.yml# Board 元数据(Board Discovery 的"身份证")│ │# - name: 人类可读名称,用于日志展示│ │# - compatible: 与 x1_evk.dts 根节点 compatible 保持一致,是匹配主键│ │# - arch / toolchain / ram / flash: 决定架构脚本、工具链与内存规划│ │# - 被谁消费:west build 启动时由 boards.cmake 解析,用于锁定本目录│ │ │ ├── x1_evk.dts# Board 级 Devicetree(板级硬件事实)│ │# - include <company/x1.dtsi> 引入 SoC 节点│ │# - 定义 chosen(console 走 UART0)、aliases(led0/sw0)、LED/Button 节点│ │# - 被谁消费:cpp 预处理器展开 → dtc 编译 → gen_defines.py 生成 DT 宏│ │ │ ├── x1_evk_defconfig# Board 默认 Kconfig(硬件默认配置)│ │# - 如 CONFIG_SOC_COMPANY_X1=y、CONFIG_SERIAL=y、CONFIG_GPIO=y│ │# - 只描述"硬件需要什么",不塞应用配置│ │# - 被谁消费:Kconfig 系统在 CMake 配置阶段加载,与 prj.conf 叠加生效│ │ │ ├── Kconfig.board# 定义 CONFIG_BOARD_X1_EVK 选项│ │# - depends on SOC_COMPANY_X1,select SERIAL/GPIO 等子系统│ │# - 被谁消费:Kconfig 系统解析,生成 CONFIG_BOARD_X1_EVK=y│ │ │ ├── Kconfig.defconfig# Board 级 Kconfig 默认值入口│ │# - 配合 x1_evk_defconfig 一起被 Kconfig 系统加载│ │# - 被谁消费:Kconfig 系统在配置阶段读取,提供默认值│ │ │ ├── CMakeLists.txt# Board 构建脚本(接入 Zephyr CMake 构建流程)│ │# - 把 board.cmake、DTS、defconfig 等接入构建系统│ │# - 被谁消费:CMake 在 west build 配置阶段执行│ │ │ └── board.cmake# 烧录/调试支持(flash runner 配置)│# - 告诉 west flash 如何调用 company_flash / J-Link / OpenOCD│# - 被谁消费:west flash 命令加载,选择并调用对应 runner│ ├── dts/ │ └── arm/ │ └── company/ │ └── x1.dtsi │ ├── soc/ │ └── company/ │ └── x1/ │ ├── CMakeLists.txt │ ├── Kconfig │ ├── Kconfig.soc │ └──... │ └── drivers/ ├── serial/ ├── gpio/ ├── spi/ ├── i2c/ └── timer/这些文件在 west build / west flash 流程中分别被谁消费?
┌─────────────────────────────────────────────────────┐ │ west build-bx1_evk │ └──────────────────────────┬──────────────────────────┘ │ ┌────────────────────────┼────────────────────────┐ ▼ ▼ ▼ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │ board.yml │ │ CMakeLists.txt │ │ Kconfig.board │ │(Board Discovery)│ │(构建脚本入口)│ │ Kconfig.defconfig │ └──────────┬──────────┘ └──────────┬──────────┘ └──────────┬──────────┘ │ │ │ │ ① 解析 name/compatible │ ② 加载 Board 构建配置 │ ③ 解析 Kconfig 选项 │ 锁定 boards/company/ │ 引入 DTS/defconfig │ 生成 CONFIG_* │ x1_evk/ 目录 │ 到 CMake 流程 │ 默认值 ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ CMake / Kconfig 配置阶段 │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ x1_evk.dts → cpp 预处理器 → dtc 编译 → gen_defines.py │ │ (板级硬件描述) (展开 x1.dtsi) (生成 DTB) (生成 DT 宏) │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ devicetree_generated.h → DEVICE_DT_DEFINE → struct device │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ zephyr.elf / zephyr.bin │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ west flash → board.cmake → company_flash / J-Link / OpenOCD │ │ (烧录命令) (选择 runner) (写入 Flash) │ └─────────────────────────────────────────────────────────────────────┘数据流向说明:
- board.yml→ 被
west build的 Board Discovery 阶段解析,用于把-b x1_evk映射到boards/company/x1_evk/目录; - CMakeLists.txt→ 被 CMake 在配置阶段执行,把 Board 的 DTS、defconfig、board.cmake 全部拉进构建流程;
- Kconfig.board / Kconfig.defconfig / x1_evk_defconfig→ 被 Kconfig 系统解析,生成
CONFIG_BOARD_X1_EVK=y及各子系统默认配置; - x1_evk.dts→ 被
cpp预处理器展开(includex1.dtsi),再经dtc编译成 DTB,最后由gen_defines.py生成devicetree_generated.h中的 DT 宏; - board.cmake→ 被
west flash加载,选择并调用company_flash等烧录工具,把固件写入 Flash。
不同 Zephyr 版本、Board 类型和需求下,具体文件可能有所不同。
不要把"BSP"理解成一个单独的文件。
更准确的是:
BSP=Board definition + Devicetree + Kconfig + Build configuration + Flash/debug configuration + Board-specific initialization四、Board 是怎么接到 SoC 上的?
这是 30 篇最重要的结构。
假设我们已经完成:
Company SoC Port例如:
soc/ └── company/ └── x1/ ├── CMakeLists.txt ├── Kconfig ├── Kconfig.soc ├── soc.yml ├── soc.c └──...现在创建:
boards/ └── company/ └── x1_evk/形成:
Zephyr │ ├── soc/ │ └── company/ │ └── x1/ │ ├── boards/ │ └── company/ │ └── x1_evk/ │ └── drivers/ ├── serial/ ├── gpio/ ├── spi/ ├── i2c/ └── timer/关系变成:
Board x1_evk │ │ uses ▼ SoC X1 │ ┌─────────┼─────────┐ ▼ ▼ ▼ CPU IRQ Clock │ ▼ Drivers