板级适配实战 添加新开发板 - 第1节

1. 课程导入

做嵌入式开发这么多年,我经常被问到同一个问题:BSP 到底是个什么东西?

说白了,BSP(Board Support Package)就是一块「翻译板」。它夹在硬件和操作系统之间,把硬件那些乱七八糟的寄存器、中断、时钟,翻译成操作系统能理解的统一接口。

举个例子。你买了一块新的 ARM 开发板,上面有串口、网口、I2C、SPI。Linux 内核本身不认识这些硬件。它只知道「我要发一个字符出去」,但具体往哪个地址写、怎么配置波特率、中断来了怎么处理——这些事,BSP 来干。

BSP 的核心职责:

  • 初始化硬件(时钟、内存、外设)
  • 提供内核与硬件的「翻译层」
  • 封装板级差异,让上层代码不用改

我在项目中遇到过最典型的例子:同一颗 SoC,两家公司做的开发板,串口地址居然不一样。上层驱动完全不用动,改 BSP 里的地址映射就行。这就是 BSP 存在的意义。

1.1 BSP 在 Linux 内核中的位置

Linux 内核的代码量,现在已经是千万行级别了。但 BSP 相关的代码,其实只占很小一部分。我习惯把内核代码分成三层:

层级 内容 是否与板子相关
架构层 CPU 核心、MMU、中断控制器 与 SoC 相关
驱动层 串口、网卡、I2C 控制器驱动 与 IP 核相关
板级层 设备树、时钟配置、引脚复用 与具体板子相关

嗯,这里要注意:板级层才是我们添加新开发板时主要动的地方。架构层和驱动层,除非你换了 SoC,否则基本不用碰。

二、为什么需要添加新开发板?

你想想看,市面上有多少种 ARM 开发板?树莓派、BeagleBone、STM32MP1、i.MX 系列……每个板子的引脚分配、外设连接、内存大小都不一样。

Linux 内核官方支持了几千种板子。但总有你手里的那块,不在支持列表里。这时候怎么办?

  • 方案一:找一个最接近的板子配置,硬改设备树。能跑,但总有各种小毛病。
  • 方案二:从头到尾,完整添加一块新开发板的支持。一劳永逸。

我个人强烈推荐方案二。为什么?

我的经验:曾经有个项目,为了赶进度,我拿一块官方板子的配置改了改就上产线了。结果因为 GPIO 复用配置不对,导致 I2C 总线冲突,产线停了两天。从那以后,我再也不敢偷这个懒。

添加新开发板的好处很明显:

  1. 可维护性高——代码结构清晰,后续升级内核版本时容易移植
  2. 可复用性强——同一套 BSP 可以快速适配同系列的其他板子
  3. 调试方便——出了问题,知道该查哪个文件

三、整体流程概览

添加一块新开发板,听起来很复杂。其实拆开来看,就那么几步。我画了一张流程图,帮你理清思路。

添加新开发板整体流程 添加新开发板整体流程 1. 硬件调研 2. 创建设备树文件 3. 配置内核选项 4. 编译与调试 5. 提交与维护 每个步骤都有坑,后续章节会逐一展开 别急,跟着课程一步步来

这张图看着简单,但每一步都有不少细节。我简单说一下每个阶段要做什么。

3.1 硬件调研

拿到一块新板子,别急着写代码。先搞清楚:

  • SoC 型号、内核架构(ARMv7?ARMv8?)
  • 内存大小和地址范围
  • 外设连接(串口接在哪个引脚?网卡是 RMII 还是 RGMII?)
  • 时钟源和频率

我曾经见过有人不看原理图,直接拿别人的设备树改。结果串口不通,查了两天才发现是引脚复用配错了。嗯,原理图是 BSP 工程师最好的朋友。

3.2 创建设备树文件

设备树(Device Tree)是现代 Linux 内核描述硬件的主要方式。你要创建一个 .dts 文件,描述板子上所有硬件的信息。

一个典型的设备树文件结构:

/dts-v1/;
#include "soc.dtsi"

/ {
    model = "My Custom Board";
    compatible = "vendor,myboard";

    memory@80000000 {
        device_type = "memory";
        reg = <0x80000000 0x10000000>;
    };

    &uart1 {
        status = "okay";
        pinctrl-0 = <&uart1_pins>;
    };
};

这段代码看着简单,但每个字段都有讲究。比如 compatible 字符串,内核就是靠它来匹配驱动的。写错了,驱动就加载不上。

3.3 配置内核选项

设备树写好了,还得让内核知道你的板子存在。需要修改 arch/arm/boot/dts/Makefile,把新设备树加进去。同时,要确保内核配置打开了对应的驱动。

注意:很多人只加设备树,忘了改 Makefile。编译出来的内核镜像里根本没有你的设备树二进制文件。启动时内核报错「No FDT found」,就是这个原因。

3.4 编译与调试

这一步是最耗时间的。编译通过只是开始,真正跑起来才是关键。

我习惯的调试顺序:

  1. 先确保串口能输出(这是调试的「眼睛」)
  2. 再搞定内存和时钟
  3. 然后逐个验证外设

为什么先搞串口?因为串口通了,你才能看到内核打印的信息。否则就像在黑屋子里修电路,全靠摸。

3.5 提交与维护

板子跑起来了,工作还没完。要把代码整理好,提交到版本管理。如果是给开源项目贡献,还要遵循社区的代码规范。

我个人习惯在 BSP 代码里加详细的注释。别嫌麻烦——三个月后你自己回来看,都会感谢当初写了注释的自己。

四、本章小结

这一章我们聊了:

  • BSP 是什么——硬件和操作系统之间的翻译官
  • 为什么要添加新开发板——一劳永逸,避免踩坑
  • 整体流程——从硬件调研到提交维护,五步走

接下来的课程,我会带着你一步步走完这五个阶段。每个阶段都有实战案例,有我踩过的坑,也有我总结的技巧。

准备好了吗?我们开始吧。