板级目录结构与文件职责
最小开发板目录需要三个文件:
my_board/
board_info.yaml # 板级元数据:板名、芯片、版本、描述、厂商
board_peripherals.yaml # 底层外设资源声明
board_devices.yaml # 功能设备声明
BMGR 在扫描可用开发板时以这三个文件是否同时存在作为识别条件。其余文件为可选:
my_board/
sdkconfig.defaults.board # 可选:板级默认 sdkconfig 项
setup_device.c # 可选:纯 YAML 无法描述的板级初始化逻辑
Kconfig.projbuild # 可选:板级 Kconfig 符号扩展
packages/ # 可选:板级本地组件
开发板名称以目录名为准,必须与 board_info.yaml 中的 board 字段保持一致。开发板名称只允许字母、数字和下划线,不支持中划线或其他特殊字符。不符合规范的开发板在扫描时会被忽略。
board_info.yaml 板级元数据
board_info.yaml 描述一块开发板的静态元数据。生成时写入 gen_board_info.c,可通过 esp_board_manager_print_board_info() 输出。所有字段均为可读元数据,不影响设备或外设的初始化逻辑。
board: my_board
chip: esp32s3
version: "1.0.0"
description: "My custom board"
manufacturer: "MyCompany"
字段名 |
类型 |
是否必填 |
解释 |
|---|---|---|---|
|
string |
必填 |
开发板名称,必须与板目录名一致;只允许小写字母、数字、下划线,不支持中划线或其他特殊字符。 |
|
string |
必填 |
开发板主控芯片型号,例如 |
|
string |
可选 |
YAML 解析契约的 schema 代号;当前为 |
|
string |
可选 |
开发板简介,自由文本。运行时由 |
|
string |
可选 |
开发板厂商名。运行时由 |
board_peripherals.yaml
board_peripherals.yaml 声明开发板上的底层硬件资源实例。每条记录对应一路底层资源,例如某条 I2C 总线、某个 SPI 控制器、某路 I2S 接口或某个 GPIO。
每个外设条目的基本结构:
peripherals:
- name: <peripheral_name>
type: <peripheral_type>
version: <version>
role: <role>
format: <format_string>
config: <configuration>
字段名 |
类型 |
是否必填 |
解释 |
|---|---|---|---|
|
string |
必填 |
外设实例名,必须以 type 为前缀,例如 |
|
string |
必填 |
外设类别,使用 BMGR 已支持的标准类型名,例如 |
|
string |
可选 |
该外设条目使用的 schema 代号,含义同 |
|
string |
条件必填 |
外设工作模式,例如 |
|
string |
条件必填 |
数据格式声明,仅在部分外设需要(当前仅 I2S 使用,例如 |
|
mapping |
必填 |
外设专属配置,字段来自 |
board_devices.yaml
board_devices.yaml 声明开发板上的功能设备实例。每条记录对应一个功能设备,例如音频编解码器、LCD 屏幕或按键。
每个设备条目的基本结构:
devices:
- name: <device_name>
type: <device_type>
chip: <chip_name>
version: <version>
sub_type: <sub_type>
init_skip: false
depends_on: other_device
power_ctrl_device: power_ctrl
config:
<configurations>
peripherals:
- name: <periph_name>
# 可附加 device 侧的专属参数
dependencies:
<component_name>:
require: <scope>
version: <version_spec>
字段名 |
类型 |
是否必填 |
解释 |
|---|---|---|---|
|
string |
必填 |
设备实例名,在当前文件中唯一;只允许小写字母、数字、下划线,不能纯数字。不要求以 type 为前缀,建议贴近功能语义,例如 |
|
string |
必填 |
设备类别,使用 BMGR 已支持的标准类型名,例如 |
|
string |
条件必填 |
设备外接芯片型号(与 |
|
string |
可选 |
该外设条目使用的 schema 代号,含义同 |
|
string |
条件必填 |
同一 type 下的子实现路径,例如 |
|
bool |
可选 |
默认 |
|
string / list |
可选 |
声明该设备依赖的其他设备实例名。BMGR 在初始化该设备前会先递归初始化依赖。详见 运行时生命周期。 |
|
string |
可选 |
引用一个 |
|
mapping |
必填 |
设备专属配置,字段来自 |
|
list of mappings |
条件必填 |
声明该设备运行依赖的 peripheral 实例(例如 codec 依赖 |
|
mapping |
条件必填 |
声明设备运行所需的额外 ESP-IDF 组件。生成时合并写入 |
peripherals 中引用外设并附加设备专属参数的典型写法(例如编解码器在设备侧补 I2C 地址):
devices:
- name: audio_codec_0
type: audio_codec
peripherals:
- name: i2c_main
addr: 0x18 # device 侧的专属参数
sdkconfig.defaults.board 与 Kconfig.projbuild
每块开发板可在板目录下放置以下两份可选文件,用于扩展工程的配置系统:
sdkconfig.defaults.board:声明开发板相关的 sdkconfig 默认项(PSRAM、Flash、partition、应用层CONFIG_*等),由 BMGR 在生成阶段合并到components/gen_bmgr_codes/board_manager.defaults。Kconfig.projbuild:开发板需要在menuconfig中暴露的额外 Kconfig 符号(通常是开发板特有的功能开关、子板枚举等),由 BMGR 追加到components/gen_bmgr_codes/Kconfig.projbuild。
# sdkconfig.defaults.board 示例
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
生成阶段:板级 + amend 的追加与覆盖
执行 idf.py bmgr -b <board> [-a <amend>] 时,BMGR 按以下顺序拼出最终的 board_manager.defaults 与 Kconfig.projbuild,后写覆盖前写:
BMGR 自动生成段:
CONFIG_IDF_TARGET、CONFIG_ESP_BOARD_<BOARD>=y、CONFIG_ESP_BOARD_NAME,以及根据 YAML 解析得到的CONFIG_ESP_BOARD_PERIPH_*_SUPPORT、CONFIG_ESP_BOARD_DEV_*_SUPPORT、CONFIG_ESP_BOARD_DEV_<DEV>_SUB_<SUB>_SUPPORT能力符号。板目录下的
sdkconfig.defaults.board与Kconfig.projbuild(如存在)。board_amend.yaml清单apply:中列出的sdkconfig.defaults.board与Kconfig.projbuild片段,严格按 apply: 中出现的先后顺序逐一追加。如需让某个片段覆盖其他 amend 片段,请将其写在apply:列表更靠后的位置。
当 board_manager.defaults 内出现同名 CONFIG_* 冲突时,BMGR 保留最后一次出现的值,并将更早的同名行改写为形如 # BMGR_CONFIG_OVERRIDE by <section>: <原行> 的注释,便于排查覆盖关系。Kconfig.projbuild 为纯文本拼接,每段前会插入 # --- <label>: <path> --- 标记说明来源。
备注
board_amend.yaml 清单中的 sdkconfig.defaults.board 与 Kconfig.projbuild 必须显式列在 apply: 中才会参与合并。放在 amend 目录但未列出的文件会被忽略并输出 INFO 日志。详细规则见 使用 -a/–amend。
运行时:BMGR 如何接入工程构建
构建时,ESP-IDF 读取一组 SDKCONFIG_DEFAULTS(由 SDKCONFIG_DEFAULTS 环境变量或 CMake 变量声明的、以 ; 分隔的文件列表)。BMGR 通过 idf.py 的全局回调(global callback)将生成的 components/gen_bmgr_codes/board_manager.defaults 追加到该链路末尾,将当前开发板的设备与外设能力符号、CONFIG_IDF_TARGET 以及板级 sdkconfig 默认项注入构建配置,驱动后续条件编译。
警告
请勿在工程的 sdkconfig.defaults 中手写 BMGR 的设备或外设能力符号(例如 CONFIG_ESP_BOARD_DEV_*_SUPPORT、CONFIG_ESP_BOARD_PERIPH_*_SUPPORT、CONFIG_ESP_BOARD_<BOARD>=y 等)。这些符号应仅来自 BMGR 根据当前开发板 YAML 自动生成的 board_manager.defaults。手工写在工程 defaults 中容易与 BMGR 生成结果不一致,进而导致依赖求解、条件编译或运行时初始化出现问题。板级特有的常规 sdkconfig 项(PSRAM、Flash、partition、应用层开关等)请放到板目录下的 sdkconfig.defaults.board,由 BMGR 统一合并。
切换开发板时,idf.py bmgr -b <other_board> 会重新生成 board_manager.defaults 与 Kconfig.projbuild,并备份与清理旧 sdkconfig 中由上一块开发板写入的能力宏。
setup_device.c 与 custom 自定义设备
setup_device.c 适用于纯 YAML 无法完整表达的板级初始化逻辑,例如 LCD 屏幕的特定复位时序、触摸芯片的工厂函数注册。该文件放在开发板目录下,BMGR 生成时会将其编译进 gen_bmgr_codes 组件。
为便于下游工程通过 -a/--amend 替换开发板的默认行为,建议遵循以下两条写法:
将对外暴露的工厂或钩子函数(例如
lcd_panel_factory_entry_t、lcd_touch_factory_entry_t、io_expander_factory_entry_t)声明为弱符号__attribute__((weak))。amend 目录中提供同名强符号实现,即可在链接阶段替换开发板默认实现,无需修改原开发板源码。覆盖机制见 使用 -a/–amend。将对芯片驱动头文件的
#include用__has_include包裹,并在弱符号函数实现的外层做同样的判断。这样 amend 不仅可以替换函数本身,还可以通过移除对应组件依赖(或替换为其他芯片组件)让开发板默认实现自动消失,避免出现 amend 已接管某条工厂入口、而开发板内的旧实现因找不到头文件而编译报错的情况。
// setup_device.c:弱符号 + __has_include 的常见组合,参考 esp32_s3_korvo_2_3/setup_device.c
#if __has_include(<esp_lcd_ili9341.h>)
#include "esp_lcd_ili9341.h"
__attribute__((weak)) esp_err_t lcd_panel_factory_entry_t(esp_lcd_panel_io_handle_t io,
const esp_lcd_panel_dev_config_t *cfg,
esp_lcd_panel_handle_t *ret_panel)
{
return esp_lcd_new_panel_ili9341(io, cfg, ret_panel);
}
#endif /* __has_include(<esp_lcd_ili9341.h>) */
custom 类型设备适合 BMGR 尚未内置支持的硬件,例如特定电源管理芯片或传感器。在 board_devices.yaml 中将 type 设为 custom,BMGR 生成阶段会将 config: 下的字段展开为专属配置结构体,写入 components/gen_bmgr_codes/gen_board_device_custom.h。若需要自定义初始化逻辑,在板目录下提供初始化/反初始化函数实现并用 CUSTOM_DEVICE_IMPLEMENT 宏注册,例如:
CUSTOM_DEVICE_IMPLEMENT(axp2101_power_manager,
cores3_power_manager_init,
cores3_power_manager_deinit);
配置结构体命名规则、类型推断表、注册宏用法及应用侧访问方式详见 自定义设备 custom;板级完整示例参考 boards/m5stack_cores3/power_manager.c。