摘要:本文建议 Zephyr BSP 专栏不要急于创建 Board,而应先从 BSP 的整体组成、职责边界、启动链路与代码组织方式入手。核心观点是:BSP 不是"一个目录",而是 Architecture → SoC → Peripheral → Driver → Devicetree → Kconfig → Board → Build → Boot 的完整链路。在进入启动链路之前,先看一张「传统 MCU BSP vs Zephyr BSP」的对比表,帮助你理解 Zephyr 的 BSP 为什么不是"一个目录":维度传统 MCU BSPZephyr BSP目录组织方式一个集中目录,包含 startup、驱动、链接脚本等所有文件按 Architecture / SoC / Board / Driver 分层分散在多个目录硬件描述手段直接在 C 代码和头文件中硬编码寄存器地址用 Devicetree(dts / dtsi)描述硬件拓扑,代码与硬件解耦配置机制宏定义 + 条件编译,散落在各处统一由 Kconfig 管理编译开关与选项驱动抽象层级驱动直接操作寄存器,与具体芯片强耦合驱动基于 Zephyr Driver API 抽象,通过 Devicetree 绑定实例可移植性换芯片基本要重写大部分 BSP换 SoC 只需新增 SoC 层描述,驱动与上层代码可复用光看表格还不够直观,下面用一段「传统 MCU BSP vs Zephyr BSP」的目录结构实战对比,让你看清同一个功能在两种体系下分别落在哪里。传统 MCU BSP:一个目录装下所有传统 MCU 开发通常把启动、时钟、外设驱动、链接脚本全部塞进一个 BSP 目录:BSP ├── startup.s# 复位向量、中断向量表、启动入口(Reset_Handler)├── system_xxx.c# 系统时钟初始化、SystemInit()、全局时钟配置├── gpio.c# GPIO 驱动,直接操作寄存器(GPIOA-MODER 等)├── uart.c# UART 驱动,直接操作寄存器(USART1-BRR 等)├── clock.c# 时钟树配置(PLL、分频、倍频)└── linker.ld# 链接脚本,定义内存布局与段(FLASH / RAM)每个文件都直接面对具体芯片的寄存器地址,换一颗 SoC 基本要重写大半。Zephyr BSP:按职责分层分散到多个目录Zephyr 把同样的功能拆解到arch/、soc/、drivers/、dts/、boards/等目录,各司其职:zephyr/ ├── arch/arm/core/# Architecture 层:CPU 架构定义│ ├── reset.S# 复位向量与启动入口(对应传统 startup.s)│ ├── vector_table.S# 中断向量表│ └── prep_c.c# 启动早期 C 初始化(对应 system_xxx.c 的 SystemInit)│ ├── soc/arm/xxx_soc/# SoC 层:芯片级资源描述│ ├── soc.c# SoC 级初始化(时钟、电源,对应传统 clock.c)│ ├── soc.h# SoC 寄存器与内存映射定义│ └── Kconfig.soc# SoC 级 Kconfig 配置开关│ ├── drivers/# Driver 层:外设驱动实现(Zephyr Driver API)│ ├── gpio/gpio_xxx.c# GPIO 驱动,通过 Devicetree 绑定实例│ ├── serial/uart_xxx.c# UART 驱动,对应传统 uart.c│ └── clock_control/# 时钟控制驱动│ ├── dts/# Devicetree 层:硬件描述│ ├── arm/xxx_soc.dtsi# SoC 级硬件拓扑(外设节点、中断、时钟)│ ├── bindings/# Devicetree 绑定定义(节点属性 schema)│ └── arm/xxx_board.dts# Board 级引脚与设备实例化│ └── boards/arm/xxx_board/# Board 层:具体开发板组合├── xxx_board.dts# 板级 Devicetree(引脚、外设使能)├── xxx_board_defconfig# 板级 Kconfig 默认配置├── CMakeLists.txt# 板级构建配置└── Kconfig.defconfig# 板级 Kconfig 定义对应关系一目了然:startup.s → arch/arm/core/reset.S:启动入口与向量表由 Architecture 层统一提供,无需每个芯片重写。system_xxx.c → arch/arm/core/prep_c.c + soc/soc.c:早期初始化和 SoC 级时钟初始化分层承担。gpio.c / uart.c → drivers/gpio/、drivers/serial/:驱动基于 Zephyr Driver API 实现,通过 Devicetree 绑定实例,与具体芯片解耦。clock.c → soc/soc.c + drivers/clock_control/:时钟树配置下沉到 SoC 层,由时钟控制驱动统一管理。linker.ld → arch/arm/core + soc/ 的链接脚本:内存布局由架构与 SoC 共同定义,Board 只需声明存储分区。这就是「BSP 不是"一个目录"」的直观体现:传统 BSP 把一切堆在一起,Zephyr 则按 Architecture → SoC → Driver → Devicetree → Board 分层,每一层只关心自己的职责,换 SoC 时只需新增 SoC 层描述,驱动与上层代码可复用。| 扩展新 SoC 的工作量 | 大,需从零移植启动、时钟、外设驱动 | 小,主要工作是写 SoC 的 Devicetree 与 Kconfig,复用 Zephyr 生态驱动 |下面是 Zephyr BSP 从芯片到应用的完整启动链路图: