1 · 文档导读与阅读路径
本章说明这份文档的覆盖范围、事实来源与书写约定。博流的资料体系分散在官网、SDK 仓库与工具包里,先明确边界比直接跳进技术细节更省时间。
1.1 覆盖范围
本文档覆盖从选型到量产的完整链路:BL602/BL604 与 BL616/BL618 两代家族的对比与选型、bouffalo_sdk 的分层架构与构建系统(CMake + Kconfig/menuconfig)、启动链与镜像格式、GPIO 与常用外设、Wi-Fi 与 BLE 开发、FreeRTOS 任务设计、低功耗(PDS/HBN)、存储与文件系统、OTA 与量产烧录,以及调试诊断与故障速查。15 章的分工与阅读时机如下:
| 章 | 内容 | 什么时候读 |
|---|---|---|
| 1 导读 | 边界、来源约定、阅读路径 | 现在 |
| 2 家族与选型 | 型号对比、SiP、决策树 | 立项与硬件评审 |
| 3 工具链与 SDK | CMake/Kconfig、烧录调试工具 | 环境搭建 |
| 4 第一个工程 | 七步点灯、成功与假成功 | 第一次上手 |
| 5 工程与构建 | SDK 目录、板级、裁剪 | 从示例转正式工程 |
| 6 启动与镜像 | 启动链、镜像头、分区、OTA 机制 | 理解「烧了不跑」 |
| 7 GPIO 与外设 | 复用冲突、UART/SPI/I2C 等 | 硬件联调 |
| 8 Wi-Fi | 状态机、配网、LWIP、DTIM | 联网功能开发 |
| 9 BLE | GAP/GATT、共存、BLE 配网 | 蓝牙功能开发 |
| 10 RTOS | 任务划分、栈、回调上下文 | 业务框架定稿 |
| 11 低功耗 | PDS/HBN、唤醒源、电流分析 | 功耗不达标时 |
| 12 存储与文件系统 | 五层栈、FS 选型、磨损纪律 | 用到持久化时 |
| 13 OTA 与量产 | 升级流程、量产参数、产线清单 | 量产准备 |
| 14 调试诊断 | 日志、异常、JTAG、射频定位 | 联调与售后 |
| 15 速查表 + 附录 | 故障速查、命令与 API、清单 | 随时 |
1.2 不覆盖什么
- 不覆盖 BL808/BL606 等多核系列。这些芯片涉及多核分工与异构通信,属于独立主题,本文只在第 2 章定位对比时顺带提及。
- 不逐条翻译芯片手册。寄存器位定义、电气参数、时序图请以官方 datasheet 与参考手册为准,本文只讲「怎么用」与「哪里会出错」。
- 不覆盖 Wi-Fi/BLE 射频认证流程。CE/FCC/SRRC 认证、天线设计与 EMC 整改属于硬件与法规主题,本文不展开。
- 不覆盖云端平台的接入细节。MQTT 服务器选型、物模型设计属于云端主题,本文只写到「设备侧把连接打通并保持」。
- 不替代 SDK 发布说明。bouffalo_sdk 迭代较快,API 命名与组件目录以你锁定的 SDK 版本为准,本文在容易漂移处均有标注。
1.3 版本与事实来源标注约定
本文档中所有性能数字、容量与接口清单均来自以下三类出处,行文中会标明;写不准的地方一律标注「以官方 datasheet / SDK 文档为准」,不做臆测。
| 来源 | 查什么 | 使用方式 |
|---|---|---|
| 官网产品页 | 主频、RAM/ROM 容量、无线规格、封装、温度范围 | 选型与第 2 章对比表的依据 |
| SDK 仓库与文档 | 目录结构、构建方式、组件清单、API 签名 | 第 3、5 章架构描述的依据 |
| 官方工具文档 | DevCube/blflash 的功能边界与参数 | 第 4 章烧录与第 13 章量产的依据 |
遇到本文与官方资料冲突时,一律以官方资料为准 —— 技术文档的价值在于引用可追溯,而不是替你记忆。每个关键数字旁边都留了出处线索,复核成本被刻意压到一次检索以内。
1.4 代码与命令的书写约定
命令行一律带 $ 前缀,如 $ make CHIP=bl616 BOARD=bl616dk;代码块与配置片段不带前缀。路径分隔符一律用 /,Windows 下同样适用。涉及 Kconfig 选项、API 名与分区名的地方用等宽字体标出,例如 CONFIG_CHIP。凡与版本相关的行为(默认波特率、组件命名、分区布局)都注明「以所用 SDK 版本为准」。
两处容易误读的地方提前说明:其一,CHIP=bl616 这类变量值是 SDK 约定的小写代号,不是芯片完整型号,不要写成大写或填入具体料号;其二,示例中的串口号(COM5、/dev/ttyUSB0)只是占位,以你机器的实际枚举为准,Windows 在设备管理器里看,Linux 用内核日志或列设备文件确认。
1.5 推荐阅读路径
第一次上手请按第 2 → 3 → 4 章的顺序走完一条完整链路,不要从某一章的中间跳进去 —— 博流平台「烧录不进去」「日志不出来」这类问题,多数是环境或配置环节跳步导致的。迁移型读者可以直接读第 3 章与第 6 章,理解博流与既有平台的差异点。做无线产品的读者把第 8、9、11 章当作主线,量产与售后的读者以第 13、15 章和附录 D 的清单为主。
无论哪条路径,都建议准备一个「工程笔记本」(Markdown 文件即可),按时间记录每次踩坑的现象、原因与修法。这份文档负责把共性问题前置讲透,你的笔记本负责沉淀项目特有的那部分 —— 两者拼起来才是一个团队完整的知识库。
2 · 博流家族全景与选型
博流在「Wi-Fi + BLE 组合 MCU」这条线上有两代主力:BL602/BL604 是低成本 Wi-Fi 4 + BLE 5.0 入门家族,BL616/BL618 是 Wi-Fi 6 + BT 5.3 + 802.15.4 的多媒体主力家族。两代都是 RISC-V 单核 + SiP 常客,但存储、无线规格与外设跨度差别很大。本章先给全景,再讲选型陷阱。
2.1 博流的两个家族怎么分
看型号前两位就能分清世代:BL60x 是 Wi-Fi 4 世代,主打照明、电工、传感这类成本敏感场景;BL61x 是 Wi-Fi 6 世代,无线子系统多了 802.15.4(Zigbee/Thread),微控制器子系统多了 FPU、DSP 与一整套多媒体外设,冲着 Matter 与音视频终端去的。两代共享同一套 bouffalo_sdk 与烧录工具链,所以从 602 迁到 616 的成本主要在硬件与无线规格上,软件框架几乎是平移。
命名还有一条实用规律:同一代里,数字越大通常资源越多(BL604 相对 BL602、BL618 相对 BL616),但「代际差」永远大于「同代差」—— BL618 与 BL616 的差别是引脚和外设,BL616 与 BL602 的差别是整个无线与算力世代。选型时先定代次再定型号,顺序不要反。
2.2 BL602 与 BL604:入门双胞胎
BL602 与 BL604 是同一颗 die 的两种封装取向:BL602 用 QFN32 4x4 mm 小封装,引脚紧凑,适合灯泡、插座这类极简节点;BL604 用 QFN40,把更多引脚(含 SDIO 等)引出来,适合需要外接存储或更多外设的透传类产品。先看全景谱系,再看对比表。
来源:博流官网产品页
| 项目 | BL602 | BL604 | 说明 |
|---|---|---|---|
| 内核 | RISC-V 单核 192 MHz | 同 BL602 | 32 KB L1 Cache,1.46 DMIPS/MHz |
| 存储 | 276 KB RAM / 128 KB ROM | 同 BL602 | 另有 1 Kb eFuse 存校准与密钥 |
| 程序存储 | 外置 XIP Flash | 同 BL602 | 模块常见 1~2 MB,以模块规格为准 |
| 无线 | Wi-Fi b/g/n + BLE 5.0 | 同 BL602 | 支持 BLE Mesh 与多云同时接入 |
| 封装 | QFN32 4x4 mm | QFN40 | BL604 引出引脚更多,部分型号带 SDIO |
| 温度 | -30~105°C | 同 BL602 | 宽温后缀可到 -40~125°C,以订购页为准 |
BL602/604 的程序存储是外置 QSPI NOR Flash 走 XIP:代码经 Cache 直接从 Flash 取指执行,芯片本体只有 RAM 与 ROM。所以模块商会在 SiP 里把 Flash 一起封进去(常见 1 MB / 2 MB)。选模块时 Flash 容量要按「固件双备份 + 文件系统 + 参数区」三段算,第 12 章会展开。
2.3 BL616 与 BL618:Wi-Fi 6 多媒体主力
BL616/BL618 的 die 相同,差别在引出的资源:BL616 是精简版(19 个 GPIO),BL618 是全功能版(35 个 GPIO),并且只有 BL618 引出了摄像头(DVP)、显示(QSPI/DBI/RGB)、MJPEG 编码、音频 Codec 与以太网(EMAC)这些多媒体外设。两款的微控制器子系统都是带 FPU 与 DSP 的 32 位 RISC-V,动态频率可配置,最高 320 MHz。
| 项目 | BL616 | BL618 | 说明 |
|---|---|---|---|
| 内核 | RISC-V @ 320 MHz | 同 BL616 | 带 FPU + DSP 与 L1 Cache |
| 存储 | 532 KB SRAM / 128 KB ROM | 同 BL616 | 4 Kb eFuse;可选内嵌 4/8 MB pSRAM |
| 程序存储 | 可选内嵌 2/4/8 MB Flash | 同 BL616 | 亦可外挂 XIP QSPI Flash |
| 无线 | Wi-Fi 6 b/g/n/ax + BT 5.3 + 802.15.4 | 同 BL616 | 1T1R,峰值 229.4 Mbps |
| 多媒体 | 无 | DVP + 显示 + MJPEG + Codec | 摄像头与屏幕方案只能选 618 |
| 网络 | USB 2.0 HS OTG、SDIO、SPI、UART | 再加 10/100M 以太网 EMAC | 以太网仅 618 支持 |
| GPIO | 19 个 | 35 个 | 先数引脚再选型 |
「动态频率 1~320 MHz」是个值得展开的特性:无线产品在空闲窗把主频降下来,运行电流跟着降,这是第 11 章低功耗的手段之一。反过来做音频或显示时要把主频顶上去 —— 主频档位不是烧死在固件里的,而是按场景在运行期切换的,方案设计时要预留这个自由度。
2.4 两代平台的横向对比
把两代放在一张表里看,差异集中在三点:无线规格(Wi-Fi 4 到 Wi-Fi 6、新增 802.15.4)、存储规模(RAM 翻近一倍、可选内嵌 Flash/pSRAM)、外设跨度(多媒体与高速接口只在第二代)。选型时先看无线与协议需求,再看存储是否够 OTA 双备份,最后数引脚。
| 项目 | BL602/BL604 | BL616/BL618 |
|---|---|---|
| 主频 | 192 MHz | 320 MHz(1~320 MHz 动态可调) |
| RAM | 276 KB | 532 KB,可选 4/8 MB pSRAM |
| Wi-Fi | Wi-Fi 4(b/g/n) | Wi-Fi 6(b/g/n/ax),20/40 MHz 1T1R |
| 蓝牙 | BLE 5.0(含 Mesh) | BT 5.3 双模(经典蓝牙 + BLE),Coded PHY / 2M PHY |
| 802.15.4 | 无 | 有(Zigbee / Thread / Matter 底座) |
| 程序存储 | 外置 XIP Flash | 可选内嵌 2/4/8 MB Flash,或外挂 |
| 低功耗 | PDS / HBN | PDS / HBN,档位更多 |
| 典型场景 | 照明、电工、透传、传感节点 | Matter 终端、音视频、网关、屏类产品 |
一个常见的选型误区是「按算力选」:看到 320 MHz 比 192 MHz 高就上第二代。实际上无线产品的大头开销在协议栈与加密,算力余量是否够,取决于你要不要 TLS、要不要 Matter、要不要音视频。纯传感上报产品用 BL602 反而更省 —— 算力档位要跟着软件需求走,不是越大越好。
2.5 SiP 封装的意义:把射频设计外包出去
博流模组的主流形态是 SiP:把芯片、晶振、Flash(以及必要的匹配电路)一起封进金属屏蔽罩,对外只留引脚。它的意义不是「小」,而是把 2.4 GHz 射频布局、天线匹配与认证隔离这三件最难的事留在模组厂:整机厂只需要按参考设计画引脚、留天线净空,认证可以直接复用模组的预认证报告。代价是单位容量与单位引脚的成本高于裸 die 方案。出货量大的产品可以在稳定后转 chip-on-board,但要自己承担射频一致性与认证,这笔账要在选型时算清楚。
| 维度 | SiP 模组 | 裸片(COB) | 工程含义 |
|---|---|---|---|
| 射频设计 | 模组厂已完成 | 自己做布局与匹配 | COB 要有射频工程师与测试仪 |
| 认证 | 复用模组预认证 | 整机重新认证 | 认证周期与费用不同量级 |
| 单件成本 | 较高 | 较低 | 出货量是分水岭 |
| 开发效率 | 引脚即接口,上手快 | 要画完整参考电路 | 首版产品强烈建议模组 |
| 供应形态 | 整模组供货 | 芯片 + 外围 BOM 自购 | BOM 管理成本差异大 |
工程上的通行节奏是:第一代产品用模组把风险关掉,验证市场与固件;出货量上来后做 COB 二代,此时模组阶段的射频实测数据(天线净空、匹配参数、认证报告)就是最好的设计输入。
2.6 与同级 RISC-V 无线平台的定位差异
与同级 RISC-V Wi-Fi 平台相比(这里讲机制不讲份额),博流的差异化在三点。其一,工具链 stance 更「开放」:SDK 与烧录协议公开,社区有开源命令行烧录器(blflash),不依赖厂商私有 IDE。其二,BL616/618 把 Wi-Fi 6 + BLE + 802.15.4 三合一,在同一价位段罕见地提供了 Thread/Zigbee 底座,做 Matter 终端时不用再加一颗协处理器。其三,低功耗与安全机制规格完整(PDS/HBN、ECC-256 签名启动、OTFAD 闪存即时解密),但国内渠道的文档与社区体量仍小于头部竞品,遇到冷门问题更多要靠读 SDK 源码,这是选型时要预留的工程时间。
| 机制维度 | 博流平台的特点 | 对开发的影响 |
|---|---|---|
| SDK 形态 | 单一统一 SDK 覆盖两代与多系列 | 跨型号迁移改动小 |
| 构建体系 | CMake + Kconfig 开放组合 | 可完全 CLI 化,易接 CI |
| 烧录协议 | BootROM UART 协议公开 | 社区工具可用,产线成本低 |
| 协议覆盖 | BL616/618 三无线合一 | Matter/Thread 产品单芯片完成 |
| 生态体量 | 小于头部竞品 | 冷门问题靠读源码,排期要留量 |
2.7 选型决策树
把最常见的分叉按优先级串成一棵树。实际选型还要叠加现有代码资产、供货与模组库存,这棵树只解决技术维度。
用这棵树时的一个提醒:先走「无线规格」分叉再走「接口」分叉,顺序不要反 —— 先按接口选到 BL618,再发现需要的是低成本纯 Wi-Fi 产品,等于整轮方案重来。树上每个分叉都对应一个硬约束(协议、成本、接口),硬约束之间冲突时,回到需求方谈判,而不是在两个都不满足的方案里挑一个。
2.8 选型时最容易忽略的四件事
第一,RAM 不是净给你的:Wi-Fi/BLE 协议栈运行要吃掉一大块 RAM,BL602 的 276 KB 里应用真正能动用的远小于标称值,跑 TLS + MQTT 时要实测余量。第二,Flash 按三份算:OTA 产品至少要「当前固件 + 备份固件 + 参数/文件系统」三段规划,1 MB Flash 的 BL602 模组跑大固件会很紧。第三,引脚数先于功能:BL616 只有 19 个 GPIO,方案塞不下时只能升 BL618,这在改板后期是灾难。第四,温度后缀:户外与工控场景要确认宽温后缀,不能只看主型号。
四件事背后是同一个方法论:选型表给的是上限,设计要按下限算。RAM 按协议栈占完之后的剩余算,Flash 按扣掉系统区之后的可用算,引脚按扣掉调试口与电源之后的数量算。每一项都做「标称值打折」,方案评审时这些打折依据就是最好的答辩材料。
选型表上的 RAM/Flash 都是 die 级标称值。协议栈、日志缓冲、OTA 备份、文件系统都会从里面扣。建议在方案阶段就用目标 SDK 版本编译一个带完整无线功能的最小业务,看 size 输出与运行时剩余堆,再回头定容量档位。
2.9 资料体系与必读文档
博流的官方资料分三层:芯片层(datasheet 与参考手册)、SDK 层(bouffalo_sdk 仓库与文档)、工具层(DevCube 用户指南)。附录 A 给出渠道索引,这里只列每层的第一读物。
| 文档 | 查什么 | 什么时候读 |
|---|---|---|
| 芯片 Datasheet | 容量、封装、引脚、电气与射频指标 | 画原理图、定电源与引脚分配前 |
| 芯片参考手册 | 寄存器级行为、PMU/GLB 等模块细节 | 写裸驱动、查异常行为时 |
| SDK README 与 quick start | 环境搭建、构建命令、目录结构 | 第 3、4 章上手阶段 |
| SDK API 文档与示例 | 各组件 API 签名与 demo | 写 Wi-Fi/BLE/外设代码时 |
| DevCube 用户指南 | 烧录工具各页签功能与量产参数 | 第 4 章烧录与第 13 章量产前 |
读资料的投入产出比也有讲究:datasheet 的「概述 + 特征 + 引脚」三章占读时 10%、用场 80%,参考手册则相反。先读薄的再按需读厚的,把整本通读的时间省下来跑通一条真实链路,是上手期最划算的时间分配。资料检索的关键词也有讲究:用「芯片型号 + 章节主题」而不是「问题现象」做关键词,前者的命中率远高于后者。
3 · 工具链全景与 SDK 架构
博流没有私有 IDE,整条工具链都是开放组件的组合:T-Head 的 RISC-V GCC 做编译,CMake + Kconfig 做构建与配置,DevCube(官方 GUI)或 blflash(开源 CLI)做烧录,CKLink + OpenOCD 做调试。理解每件的职责边界,出了问题才知道该去查哪一段。
3.1 一条命令背后发生了什么
在示例目录敲下构建命令后,系统依次做了四件事:读 CHIP/BOARD 变量定位芯片与板级;把 Kconfig 的默认值与你的 menuconfig 改动合成配置;CMake 按配置生成构建脚本并调用 riscv-gcc 编译链接;最后由 objcopy 产出可烧录的 bin 镜像。烧录命令则是把这串镜像按分区表写进 Flash。哪一步出问题,就去查对应环节的日志,不要一上来就怀疑代码。
| 阶段 | 发生什么 | 失败时的第一嫌疑 |
|---|---|---|
| 读变量 | 解析 CHIP/BOARD 与工程配置 | 变量拼写、目录进错 |
| 合成配置 | Kconfig 默认值 + menuconfig 改动 | 手改过生成文件 |
| 编译链接 | CMake 生成脚本,gcc 编译 | 工具链版本、组件依赖 |
| 产物生成 | objcopy 出 .bin,size 报告 | 链接脚本与分区预算 |
| 烧录 | 按分区表写入 Flash 并校验 | 串口、供电、分区配置 |
把这五个阶段记在脑子里,报错的第一行落在哪个阶段,排查方向就定了。新手最常见的浪费是把「编译阶段的头文件缺失」当成「芯片坏了」,把「烧录阶段的握手失败」当成「代码写错了」—— 阶段归属搞对,一半的问题在动手前就消解了。
3.2 bouffalo_sdk 的分层架构
bouffalo_sdk 是博流把早年 bl_iot_sdk 与 bl_mcu_sdk 合并后的统一 SDK,分层清晰:bsp 负责板级(时钟、引脚复用、堆与控制台初始化),drivers/lhal 是跨芯片统一的外设驱动层,drivers/soc 收纳芯片私有的驱动,components 集成 FreeRTOS、LWIP、NimBLE、LittleFS、FATFS、mbedTLS 等中间件,examples 放示例。第 5 章会逐层展开目录。
合并这件事对老用户有个直接含义:网上能同时搜到 bl_iot_sdk(偏物联网框架)与 bl_mcu_sdk(偏 MCU 裸框架)两代资料,它们的目录与 API 有差异。新项目一律从 bouffalo_sdk 起步;查老资料时先看仓库根目录的名字,再决定这篇资料能不能信。
3.3 CMake + Kconfig:构建与配置如何咬合
Kconfig 体系回答「编什么、编成什么样」:每个组件与板级声明自己的配置项与默认值,menuconfig 给出可搜索的交互界面,结果落成配置文件供构建读取。CMake 体系回答「怎么编」:顶层 CMakeLists 组织子目录与组件依赖,按配置决定哪些源码参与编译、哪些宏被定义。两层的纪律是:配置改动进 Kconfig,构建改动进 CMakeLists,直接手改中间产物会被下一次构建覆盖。
menuconfig 的实用操作只有三个:/ 键搜索选项名(顺便能看到依赖它的选项与所在位置)、? 键看帮助、退出时保存。查「某个功能为什么没编进来」时,先搜对应 CONFIG 项看它的依赖链 —— 很多「开关打不开」是依赖项没满足,不是你找不到开关。定位到 Kconfig 源文件后改默认值或补依赖,再进 menuconfig 验证。
menuconfig 生成的配置、CMake 生成的构建目录都是中间产物。手改后短期有效,换台机器或清理重编就打回原形。正确做法是:配置差异落到 defconfig 或 menuconfig,工程差异落到 CMakeLists,板级差异落到 board 目录 —— 第 5 章给出新增自定义板的完整清单。
3.4 riscv 工具链:装哪个、怎么配
SDK 约定使用 riscv64-unknown-elf-gcc 前缀的 T-Head(玄铁)GNU 工具链,虽然芯片是 32 位内核,前缀不变,具体架构由编译参数控制。Windows 与 Linux 都用同一前缀,macOS 官方不提供现成包需要自建。装完只需把 bin 目录放进 PATH,再用 riscv64-unknown-elf-gcc --version 验证。注意工具链版本要与 SDK 文档推荐的代次对齐,跨大版本可能出现链接脚本或库不兼容。
安装步骤固定四步:下载与 SDK 推荐版本一致的包;解压到不含空格与中文的路径;把其 bin 目录加入系统 PATH;新开终端验证版本号。Windows 常见的两个坑:路径里有空格导致构建脚本解析失败;加 PATH 后没重开终端导致「明明装了却找不到」。Linux 下还需安装 make 与基础构建工具链(具体包名按发行版)。
| 环节 | 工具 | 说明 |
|---|---|---|
| 编译 | riscv64-unknown-elf-gcc | T-Head GNU 工具链,版本对齐 SDK 推荐 |
| 构建 | CMake + make / ninja | SDK 自带 cmake/ninja,也可用系统版本 |
| 配置 | Kconfig + menuconfig | kconfiglib 实现,交互式裁剪 |
| 烧录 | DevCube / blflash | UART 下载口,详见 3.5 |
| 调试 | CKLink + OpenOCD | JTAG 断点单步,见第 14 章 |
3.5 烧录工具的职责边界:DevCube 与 blflash
两个工具都通过 UART 下载口(BootROM 内置的下载协议)给 Flash 写镜像,职责边界是:DevCube 是官方全家桶,GUI 里集成烧录、镜像打包、量产多通道与射频测试页签,产线与调参数用它;blflash 是社区开源的命令行烧录器,适合 CI 流水线与脚本化批量操作。日常开发用哪个都行,但两者的分区表文件格式不通用 —— DevCube 用自己的配置文件,blflash 读 SDK 的 yaml 分区表,量产前先统一到一种。整条链路的职责边界如下图:
选工具还有一条隐性判据:报错信息的可读性。blflash 报错直接指出「串口打开失败」「同步失败在哪个阶段」,适合脚本环境快速定位;DevCube 的报错与 GUI 状态绑定,配合用户指南看更清楚。两个工具都装着、按场景切换,是大多数团队的实际做法。
博流的下载走 BootROM 的 UART 协议,不需要 JTAG。这也是量产成本低的原因:产线只接 USB 转串口。JTAG(CKLink)只在开发期调试断点用。芯片 Flash 里的合法镜像丢失时,BootROM 会回落到下载模式等待主机,因此「砖」在博流平台上几乎总是可救的。
3.6 IDE 与编辑器怎么选
主推 VS Code + CMake 插件:SDK 仓库自带 workspace 配置与 compile_commands.json 支持,clangd 能给出准确的跳转与补全。Keil/IAR 没有官方支持,不要规划在这条线上。Eclipse CDT 可用但维护成本高于 VS Code。无论用什么编辑器,构建与烧录都建议走命令行,保证「编辑器里的按钮」与「CI 里的脚本」是同一条命令。
clangd 的价值值得单独说一句:它读构建系统吐出的编译数据库,能准确知道每个文件用了哪些宏与头文件路径。配置一次,之后跳转、补全、改名、查引用都是对的;没有它,「这个 API 在哪个头文件里」这类问题会持续消耗时间。SDK 仓库根目录的 .clangd 已处理 64 位前缀与 32 位目标架构的映射,不要手改。
| 方案 | 优点 | 代价 | 适合 |
|---|---|---|---|
| VS Code + CMake 插件 | 免费、clangd 智能补全、与 CLI 完全一致 | 需要自己装插件与配 PATH | 绝大多数开发者 |
| 命令行为主 + 任意编辑器 | 与 CI 一致、最稳 | 没有图形化调试界面 | 脚本派与服务器环境 |
| Eclipse CDT | 图形化构建目标与调试 | 工程配置维护成本高 | 习惯了 IDE 的团队 |
3.7 环境自检清单
环境问题占了新手卡壳的大头,装完按这张清单跑一遍再开始写代码。任何一条不过,先解决它,不要带着问题往下走。
riscv64-unknown-elf-gcc --version能打印版本号。- SDK 自带 helloworld 示例能编译通过并产出 .bin。
- size 报告正常,构建无告警级错误。
- 烧录工具能识别到串口并完成握手。
- 串口终端能看到日志输出。
- 以上四步的命令都写进了团队 README,别人照抄能复现。
最后一条常被忽略,却是环境建设最有价值的一条:环境搭建知识必须沉淀成可复现的文档,而不是留在第一台配通机器的人脑子里。新人入职照文档操作半天内跑通点灯,是检验这份文档是否合格的唯一标准。
3.8 工具链版本升级的纪律
工具链与 SDK 的版本升级要当作一次小发布来管理:先在分支上验证(helloworld、Wi-Fi、BLE 三个基线示例全过),再合并主干,升级记录写清「旧版本、新版本、动机、验证结论」。直接在主干上「顺手升级」是很多项目「上周还能编、这周编不过」的根源。CI 环境与开发者本机的版本必须同步升级,并在 README 里锁版本号 —— 两边版本漂移产生的「我这能编你那不能编」,排查成本远高于同步升级的成本。
4 · 第一个工程:menuconfig 到日志点灯
本章把第一个工程拆成七步,每一步都给出「成功标志」与对应失败时的第一嫌疑。整条链路第一次走通大约需要半天,其中环境与串口占去大半时间,属于正常现象。
4.1 硬件准备与接线
最简配置是三根线:下载/日志复用的 UART(TX、RX、GND)接到 USB 转串口,外加 3.3V 供电。注意两点:一是供电能力,Wi-Fi 发射时峰值电流可达数百毫安,电脑 USB 口或劣质 USB 转串口板自带的 3.3V 常常不够,现象是「连上 Wi-Fi 就复位」;二是接线口别搞错,模组上通常有两个 UART,下载口以原理图与模组手册为准。开发板则直接用板载 USB,无需自己接线。
供电预算建议在接线前就算一次:芯片运行均值 + Wi-Fi 发射峰值 + 外设负载,再留一倍余量,就是电源的额定能力。示波器(或万用表盯电压)在「开 Wi-Fi 的瞬间」看一眼压降,比事后排查复位问题便宜得多。TX 接 RX、RX 接 TX 的交叉规则也要再确认一遍 —— 「终端里打字没反应」有一半是直连了。
4.2 七步点灯流程总览
七步是:取码与装工具链、menuconfig、编译、烧录、接串口、复位、看日志。流程图如下,后面几节逐步展开关键的合并步骤。
为什么要专门给「点灯」写一章?因为这条七步链路就是产品开发的缩影:后面的 Wi-Fi 调试、OTA 验证、产线烧录,全是这七步在不同深度上的重复。第一次就把每一步的成功标志记牢,后面的所有环节都省一遍重新摸索的时间。
4.3 第一步与第二步:取码与 menuconfig
从官方仓库获取 bouffalo_sdk 并安装工具链(第 3 章),然后进入示例目录执行 menuconfig。第一次进来不用大改,只需确认 CHIP 与 BOARD 与你的硬件一致(命令行变量也可以直接指定)。值得现在就认识的选项有三类:CONFIG_CHIP 决定芯片代次、组件类选项决定 LWIP/BLE 等是否编入、板级类选项决定控制台波特率与引脚。改动保存后退出,不要手改生成的配置文件。
menuconfig 界面里看到「不确定含义的选项」时的标准动作是按帮助键读说明,而不是去网上搜。博流的选项说明通常写明了依赖与效果,配合第 3.3 节的搜索技巧,绝大多数选项当場就能理解。第一次建议只动两类东西:确认芯片与板级、确认日志波特率,其余全部保持默认 —— 默认值是 SDK 维护者验证过的组合。
4.4 第三步与第四步:编译与烧录
编译产物在构建目录:.elf 带符号(调试用),.bin 是烧录镜像,size 报告给出代码与数据占用。烧录用 blflash 或 DevCube:命令行指定串口与分区配置(SDK 示例通常已配好),点「烧录」后工具会先复位芯片进入下载模式再写入。若工具报「等待同步失败」,优先查接线与串口占用,其次查是否别的程序(串口终端)占着口。
第一次编译后养成三个习惯:把 size 数字抄进工程笔记(它是体积回归的基线);把编译告警清零(RISC-V 工具链的告警常指向真实问题);烧录完成后立刻复位验证,不要攒到改了十处代码才发现烧录环节有问题。每一步的可复现命令记进笔记 —— 第 13 章量产脚本就是从这些命令长出来的。
4.5 第五步到第七步:串口、复位、看日志
把串口终端接到下载口,波特率对齐板级配置(不同芯片与 SDK 版本默认值不同,BL602 常见 115200,BL616 常见 2M,以板级代码为准),复位后应看到启动 banner 与任务打印。看不到任何输出时,先交换 TX/RX 再查波特率 —— 这是新手上最高频的两个错误。
终端软件的选择不重要,重要的是会两件事:一次开对了端口与波特率;会用「十六进制显示」排查乱码(乱码到底是波特率错还是编码错,切十六进制一眼分辨)。日志里有 ROM 引导信息、SDK 版本、任务启动序列三段,第一遍看不懂没关系,记住「正常长什么样」,以后靠「跟正常不一样」发现问题。
4.6 三个「成功标志」
三个标志分别守住「编的对」「烧的对」「跑的对」三道关。三张证据各有讲究:size 报告要连同工程配置一起存档,单独一个数字没有意义;回读校验是烧录工具的选项,有的工具默认关着,第一次用就要确认打开;启动日志要在「冷启动」条件下取 —— 复位不算冷启动,重新上电才算,两种条件下日志可能有差异。
证据还有一个进阶用途:把「正常状态」的证据固化成基线(正常日志全文、正常 size 报告),之后任何异常都先与基线对比。故障排查的一半工作是在找「和正常不一样的地方」,没有基线,这一半工作就变成凭记忆猜。
| 步骤 | 成功标志 | 证据在哪 |
|---|---|---|
| 编译 | 零错误,产物齐全 | 构建目录出现 .bin/.elf,size 输出合理 |
| 烧录 | 回读校验一致 | 工具报 verify 通过,而非仅「写入完成」 |
| 运行 | 启动日志完整 | 终端出现 banner、任务启动与业务打印 |
4.7 三个「假成功」
与成功标志一一对应,有三个经典假成功,每个都有明确的对策。假成功的危险在于它消耗的是后续时间:烧错口的设备让你把「烧录成功」当成前提去调业务,调了半天才发现固件根本没进去 —— 所以每个假成功都要在第一次遇到时就写进工程笔记,团队里从此没有人再掉进同一个坑。
| 假成功 | 现象 | 对策 |
|---|---|---|
| 烧错口 | 烧录工具一直等待同步 | 按原理图确认下载口,换口重试 |
| 波特率假象 | 终端全是乱码但灯亮了 | 对齐板级波特率,先看到 banner 再说 |
| 供电不足 | 空板正常,开 Wi-Fi 即复位 | 换独立 3.3V 电源,示波器看电压跌落 |
4.8 失败排查的最短路径
第一次点灯失败时按图索骥:编译失败查环境与配置(几乎不会是业务代码问题);烧录失败查接线、串口占用与供电;无日志查波特率与 TX/RX;有日志但业务异常才轮到读代码。顺序不要倒 —— 前三类的修复成本是分钟级的,值得先排除。
把七步每一步的「第一嫌疑」汇总成一张表,卡住时从上往下对号入座:
| 卡在哪一步 | 第一嫌疑 | 第二嫌疑 |
|---|---|---|
| 取码 | 仓库版本与文档不对应 | 子模块未拉取 |
| menuconfig | CHIP/BOARD 与硬件不符 | 改了含义不明的选项 |
| 编译 | 工具链版本或 PATH | 组件依赖未开 |
| 烧录 | 串口接错或被占用 | 分区配置不对 |
| 接串口 | 波特率不匹配 | TX/RX 反接 |
| 复位运行 | 供电峰值不足 | Flash 镜像不完整 |
| 看日志 | 看错串口实例 | 日志等级被关 |
4.9 第一次上手的三条纪律
第一,每一步留下证据:编译留 size 报告,烧录留工具日志,运行留串口记录,出问题时这些都是定位依据。第二,不改没看懂的配置:menuconfig 里不动含义不明的选项,默认值能跑通大多数示例。第三,示例先于业务:先跑通官方 LED/Wi-Fi 示例再合并业务代码,一旦合并后出问题,可以用二分法定位是配置还是代码引入的。
这三条纪律的共同点是把「不确定性」控制在最小范围。点灯阶段的不确定性本来就多(硬件、环境、工具全是新的),再叠加行为不可预测的改动的确会失控。等链路完全稳定之后,再逐项引入自己的变量,每引入一个验证一次 —— 这就是老手与新手在同一颗芯片上速度差五倍的原因:不是手快,是变量控制得好。
4.10 从点灯到业务工程的过渡
点灯通过只说明「工具链、烧录器、串口、最小系统」四件事是好的,它离业务工程还有一段路。推荐的过渡顺序是:先把官方示例改造成「半业务」形态(保留示例的初始化框架,替换业务逻辑),跑通后再把业务代码按模块迁入。反过来「直接在业务仓库上配环境」看似省事,一旦跑不通,无法区分是环境问题还是业务代码问题,排查时间反而是前一种路径的数倍。过渡期同样要维护一份「示例差异清单」,记录每一步引入了什么配置、什么代码,这份清单在后续接入新成员时就是最好的培训材料。
5 · 工程结构与构建系统
看懂 SDK 目录与构建传导,是「示例跑通」到「自己做产品」之间最短的路。本章按五层结构讲目录,再讲 Kconfig 与板级,最后给出新增自定义板的完整清单。
5.1 SDK 仓库的目录分层
bouffalo_sdk 的目录就是它的架构图:上层 examples 只依赖 components 的接口,components 依赖 drivers,drivers 通过 bsp 落到具体芯片。业务代码放在 examples 同级或独立的工程目录里,永远不要为了「图方便」去改 drivers 与 components 的源码 —— 升级 SDK 时这些改动会全部丢失。
判断一段代码该放哪,问一个问题是「它跟着谁走」:跟着芯片走 → drivers;跟着板子走 → bsp/board;跟着产品走 → 你的工程目录;跟着协议走 → components(通常意味着向上游回馈或做适配层)。这个问题问清楚了,目录结构自然就不会乱,升级 SDK 时的合并冲突也最少。
5.2 一层一层看:bsp / drivers / components
bsp/board 是板级的家:时钟初始化、默认 pinmux、内存堆配置与控制台都在这里定义,一块板对应一个目录。drivers/lhal 把 UART/SPI/I2C 等常用外设抽象成跨芯片统一 API,同一份应用代码可以不改动地跨 BL602 与 BL616 编译;芯片特有的能力放在 drivers/soc。components 收纳协议栈与文件系统等中间件,每个组件都有自己的 Kconfig 开关。
lhal 统一 API 是这层架构里最值得利用的设计:应用代码里外设调用写成 lhal 风格,将来从 BL602 换到 BL616(或反向降本)时,业务与驱动代码基本零改动,改的只有板级目录与构建变量。反过来,如果图省事直接调了 drivers/soc 里的芯片私有接口,这笔迁移债就会在换型时一次性还清。
| 层 | 目录 | 改动频率 | 谁有权改 |
|---|---|---|---|
| 示例层 | examples | 每产品一份 | 所有人 |
| 中间件层 | components | 随 SDK 升级 | 只改配置不改源码 |
| 统一驱动层 | drivers/lhal | 随 SDK 升级 | 只提 issue,不本地改 |
| 板级层 | bsp/board | 每板一份 | 板级负责人 |
| 芯片层 | 芯片与射频固件 | 不可改 | 厂商 |
5.3 examples 的组织方式
每个示例是自包含目录:入口源码、本示例专属的 Kconfig 与 CMakeLists。跑示例的标准姿势是「进目录、指定 CHIP/BOARD、编译、烧录」,示例之间互不依赖。自己的产品工程建议从最接近的示例复制出来再改,而不是从零手搭工程文件 —— 示例里的链接脚本引用、组件依赖与编译参数都是现成且验证过的。
| 示例类别 | 典型内容 | 复用价值 |
|---|---|---|
| helloworld | 最小启动与日志 | 验证环境的基线 |
| peripherals | GPIO/UART/SPI/I2C/PWM/ADC | 外设初始化模板 |
| wifi | station/SoftAP/配网/扫描 | 联网产品骨架 |
| ble | 广播/GATT 服务/配网 | 蓝牙产品骨架 |
| storage | 文件系统与参数存储 | 持久化模板 |
| 组合类 | Wi-Fi+BLE 共存、OTA | 复杂产品的参考实现 |
5.4 Kconfig 与板级配置
Kconfig 的价值是「配置有源头」:每个配置项都声明在组件或板级的 Kconfig 文件里,带默认值与依赖关系,menuconfig 只是它的一个视图。配置传导链如下图,记住结论:改动要落在源头(defconfig、board 目录、CMakeLists),不要落在生成物上。
5.5 CHIP 与 BOARD 两个变量决定了什么
CHIP(如 bl602/bl616)决定芯片代次:链接脚本、启动文件、驱动实现、无线固件都跟着换。BOARD(如 bl602dk/bl616dk)决定板级:引脚复用表、控制台串口、外设使能与默认配置都从 board 目录取。两个变量通常在命令行传入并被记录进构建产物,编译出的镜像自带「身份」—— 烧错芯片代次的镜像会被启动校验拒绝,这本身是一道防线。
团队协作时的约定做法:把「CHIP + BOARD + 关键 Kconfig 摘要」写进版本命名与发布单,让每个固件 bin 都能回答「我为哪块板而生」。多板型产品(同固件不同外壳配置)用 BOARD 变体或运行期配置区分,不要用编译期宏散落各处 —— 那是「换壳重编全部」模式的起点。
5.6 新增一块自定义板要改哪些地方
自定义板的标准做法是在 bsp/board 下新增一个板级目录,从最接近的官方板复制再改。改动清单如下:
| 位置 | 改什么 | 备注 |
|---|---|---|
| board 目录 | 新建目录与板级初始化代码 | 从最接近的官方板复制起步 |
| 时钟配置 | 晶振频率与 PLL 配置 | 与硬件原理图逐项核对 |
| pinmux 表 | 每个功能引脚的复用定义 | 对照原理图,排他性检查 |
| 控制台 | 日志串口号与波特率 | 第一步先保证日志能出来 |
| 内存布局 | 堆与静态区划分 | 大缓冲需求在此声明 |
| Kconfig 默认值 | 板级默认配置(defconfig) | 不写在生成配置里 |
| 构建变量 | BOARD 名注册与文档 | 团队与 CI 都按这个名字构建 |
顺序建议:先改控制台让日志出来,再改时钟与 pinmux,最后迁业务。日志是最早的「信号灯」,板级改得对不对,第一时间通过它反馈。
5.7 menuconfig 常用配置项速查
第一次裁剪只需要认识这几类选项(名称随 SDK 版本可能微调,以 menuconfig 内搜索为准):
| 类别 | 典型作用 | 什么时候动它 |
|---|---|---|
| 芯片与板级 | 指定 CHIP/BOARD 与板级特性 | 新工程建立时 |
| 无线组件 | Wi-Fi / BLE / 15.4 协议栈开关 | 明确不做某类无线时裁掉省空间 |
| 缓冲与内存 | 协议栈缓冲、pbuf 池大小 | RAM 紧张或高并发时 |
| 文件系统 | LittleFS / FATFS 与分区挂载 | 用到存储时 |
| 日志 | 等级与输出通道 | 开发期放宽、量产期收紧 |
| FreeRTOS | tick 频率与内核特性 | 任务设计定稿后 |
| 调试接口 | JTAG 与异常处理行为 | 第 14 章诊断配置时 |
裁剪的收益要复测:每关掉一个大组件,编译后记一次 size 与运行剩余堆。裁剪是有方向的 ——「确定不做」的才关,「可能要做」的留着,因为后期重新打开往往牵动内存布局,代价高于当初省下的那点空间。
5.8 构建产物与镜像尺寸怎么看
构建结束后看三样东西:.bin 的字节数(要放进固件分区,OTA 时要小于单分区减去头部的空间)、size 报告的 text/data/bss(text+data 是 Flash 占用主体,bss 加栈堆是 RAM 预算)、以及构建目录里的 map 文件(定位体积大户时按符号排序看)。这三个数字应该在每次裁剪后记录,体积回归通常是引入组件造成的,一眼就能看出来。
map 文件的实用读法:按「库/组件」聚合看分布,通常协议栈与加密库占大头;业务代码里突然膨胀的符号,多半是新引入的大查表或字符串常量。体积优化从「关掉不用的组件」开始,然后是降日志字符串密度,最后才是压缩业务逻辑 —— 顺序反了会白费劲。
与其在烧录或 OTA 时才发现镜像超了,不如在 CI 里加一条检查:解析 size 输出,与固件分区可用空间比对,超阈值即失败。配套给 RAM 也做同样的事 —— 标称 RAM 减去协议栈与堆栈预算,就是应用的天花板。