Skip to content

概念先知道

  • 崩溃(Crash):程序跑飞、访问非法地址、断言失败等导致芯片进入异常;崩溃时 CPU 寄存器与调用栈信息合称 coredump(核心转储)
  • core 分区:分区表中专门存放 coredump 的区域;例程通过 MTD 打开名为 core 的分区,把崩溃现场写进去,复位后仍然可以导出分析。
  • shell(命令行):串口交互命令,例程用它注册了 crash 命令来“故意崩溃”,方便演示 coredump 生成流程。
  • 分析工具tools/byai/coredump.py 读取 coredump 与编译产物(.elf),还原崩溃时的函数调用栈与寄存器,帮助定位是哪一行代码崩溃。

例程功能简介

本页对应博流官方 SDK 的 crash 例程(examples/crash),演示崩溃现场(coredump)的生成、保存与离线分析

  • 初始化 MTD,打开分区表中的 core 分区并打印其地址与大小;
  • core_partition_init 配置 coredump 写入位置;
  • 启动串口 shell,注册 crash 命令:执行 assert(0) 故意触发崩溃;
  • 崩溃时 coredump 写入 Flash core 分区,串口同时输出崩溃信息;
  • 导出 core 分区后用 tools/byai/coredump.py 结合 ELF 还原调用栈。
  • 该例程依赖 FreeRTOS、shell、MTD 与分区表组件;官方 README 注明分析流程支持 Linux 环境。

注意

崩溃调试依赖分区表中的 core 分区:如果固件/分区表没有 core 分区,程序会打印 No valid coredump partition found,无法保存 coredump。另外 assert(0) 崩溃后需要重新进入下载模式烧录或复位,才能继续导出数据。

操作步骤

1
进入例程目录

本页不需要额外接线。在终端进入 SDK 的崩溃调试例程目录(前提:已按快速开始(Linux)Windows搭建好环境):

cd examples/crash
2
编译工程

执行编译命令。Ai-M62(BL616)与 Ai-M61(BL618)同属一个系列,统一填写引脚最少的 bl616 即可(例程依赖 FreeRTOS、shell、MTD 与分区表组件,SDK 已在其 defconfig 中打开):

make CHIP=bl616 BOARD=bl616dk
3
烧录固件

用 USB 线连接开发板,按住 BOOT 键(Ai-M61-32S-Kit 为 IO2)不放、短按 EN/RST 进入下载模式,然后执行烧录(把串口号换成实际值):

make flash CHIP=bl616 COMX=/dev/ttyUSB0
4
运行并触发崩溃

打开串口助手(波特率 2000000)。程序启动后打印 core 分区的 XIP 地址 / Flash 地址 / 大小并启动 shell;在串口输入 crash 回车,shell 调用 assert(0) 制造一次崩溃,串口会输出崩溃信息,同时 coredump 被写入 Flash 的 core 分区。

crash
5
导出并分析 coredump(Linux)

崩溃后重新进入下载模式,用 SDK 工具把 core 分区读出来,再用 coredump.py 结合编译出的 ELF 文件定位崩溃位置(地址以实际打印为准):

./tools/bflb_tools/bouffalo_flash_cube/BLFlashCommand-ubuntu --chip bl616 --read --flash --start 0x2f8000 --len 0x80000 --file crash.bin --port /dev/ttyACM0
./tools/byai/coredump.py crash.bin examples/crash/build/build_out/crash_bl616.elf

代码执行流程

例程从启动到崩溃、导出分析的完整流程如下:

例程调用的 API 介绍

bflb_mtd_init()

初始化 MTD(Flash 分区抽象层),后续按分区名打开分区都需要它。

参数:无

返回值:成功返回 0;失败返回负值错误码

bflb_mtd_open("core", &handle, flags)

按名称打开 MTD 分区。例程打开 "core" 分区(flags 为 BFLB_MTD_OPEN_FLAG_BUSADDR),失败返回负值。

参数

  • name:分区名称,例程 "core"
  • handle:返回的分区句柄
  • flags:打开标志

返回值:成功返回 0;失败返回负值错误码

bflb_mtd_info(handle, &info)

获取分区信息(XIP 地址、Flash 偏移、大小),例程打印这些值。

参数

  • handle:分区句柄
  • infobflb_mtd_info_t,包含 xip_addr / offset / size

返回值:成功返回 0;失败返回负值错误码

core_partition_init(flash_addr, flash_size)

把 coredump 的保存位置配置为 core 分区(Flash 地址 + 大小),之后崩溃时自动写入。

参数

  • flash_addr:core 分区 Flash 偏移(例程 info.offset
  • flash_size:core 分区大小(例程 info.size

返回值:无

shell_init_with_task(uart_dev)

以独立任务方式启动串口 shell,之后可在串口输入 crash 等已注册命令。

参数

  • uart_dev:串口设备句柄(例程 uart0

返回值:无

SHELL_CMD_EXPORT_ALIAS(func, name, desc)

把 C 函数注册为 shell 命令:例程把 shell_crash 注册为 crash,输入该命令即调用 assert(0) 制造崩溃。

参数

  • func:命令函数
  • name:命令名("crash"
  • desc:命令说明

返回值:无

完整代码

以下为 crash/main.c 完整源码,与官方示例(examples/crash)逐字一致,默认折叠,点击展开:

📜 点击展开 crash/main.c 完整代码
c
#include <assert.h>
#include "bflb_mtimer.h"
#include "bflb_uart.h"
#include "shell.h"
#include <FreeRTOS.h>
#include "semphr.h"
#include "board.h"

#include "bflb_mtd.h"
#include "coredump.h"

static struct bflb_device_s *uart0;

extern void shell_init_with_task(struct bflb_device_s *shell);

int main(void)
{
    bflb_mtd_info_t info;
    bflb_mtd_handle_t handle;
    int ret;

    board_init();

    bflb_mtd_init();
    ret = bflb_mtd_open("core", &handle, BFLB_MTD_OPEN_FLAG_BUSADDR);
    if (ret < 0) {
        puts("No valid coredump partition found\r\n");
    }
    memset(&info, 0, sizeof(info));
    bflb_mtd_info(handle, &info);
    printf("Found Valid coredump partition, XIP Addr %08x, flash addr %08x, size %d\r\n",
           info.xip_addr,
           info.offset,
           info.size);
    core_partition_init(info.offset, info.size);

    uart0 = bflb_device_get_by_name("uart0");
    shell_init_with_task(uart0);

    vTaskStartScheduler();

    while (1) {
    }
}

int shell_crash(int argc, char **argv)
{
    printf("shell crash\r\n");
    //asm ("ebreak");
    assert(0);
    return 0;
}
SHELL_CMD_EXPORT_ALIAS(shell_crash, crash, trigger crash.);

FAQ

提示 No valid coredump partition found

分区表里没有 core 分区。检查分区配置(partition_cfg / pt 文件)是否包含名为 core 的条目,并重新生成、烧录分区表与固件。

输入 crash 命令没有反应

确认串口输入的是 shell 命令(例程是 crash 回车)且波特率 2000000;若 shell 未启动,检查 CONFIG_SHELL 是否打开、vTaskStartScheduler 是否执行。

导出地址怎么确定

以程序启动时打印的 flash addr / size 为准(官方 README 中的 0x2f80000x80000 是默认分区配置下的示例值)。使用其他分区配置时,用打印值替换 --start--len

遇到问题?

如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23