Skip to content

概念先知道

  • 分区表(Partition Table):一张“地图”,告诉芯片 Flash 里每一块区域叫什么、干什么用(固件、分区表本身、PSM 掉电保存、OTA 备份等),以及每块的地址和大小。
  • 双备份机制:Flash 中存有两份分区表(表 0 / 表 1),启动时选择其中有效的一份,防止擦写中断导致“地图”损坏。
  • 激活分区(active partition):当前实际使用的那份分区表;例程用 pt_table_get_active_partition_need_lock 获取并打印它。
  • 条目字段:每条分区记录包含 type(类型)、device(设备号)、active_index(激活索引)、name(名称)、start_address[2] / max_len[2](两个备份区地址与长度)、age(老化计数,用于双表切换)。

例程功能简介

本页对应博流官方 SDK 的 partition 例程(examples/partition),演示读取并打印激活分区表

  • 注册 Flash 擦除/写/读回调(pt_table_set_flash_operation),分区表组件通过这些回调访问 Flash;
  • 调用 pt_table_get_active_partition_need_lock 读取激活分区表(自动完成双表校验与切换);
  • _dump_partition 打印表头与每个分区条目,包含 magicCode、version、entryCnt、age、crc32 及各条目地址/长度/名称。
  • 该例程输出与烧录进 Flash 的 partition*.bin(由分区配置文件生成)对应,可用于核对实际分区布局。

提示

分区表的实际布局由构建配置(partition_cfg / pt 文件)决定,本页例程只是“读出来打印”。修改分区布局属于高风险操作:改错会让固件找不到启动分区,一般保持官方默认分区即可。

操作步骤

1
进入例程目录

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

cd examples/partition
2
编译工程

执行编译命令。Ai-M62(BL616)与 Ai-M61(BL618)同属一个系列,统一填写引脚最少的 bl616 即可(该例程依赖 CONFIG_PARTITION,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)。程序读取激活的分区表并打印:表头信息(magicCode、version、entryCnt、age、crc32)和每一行的分区条目(序号、type、device、active_index、name、两个地址、两个长度、age)。

代码执行流程

例程从启动到打印分区表的完整流程如下:

例程调用的 API 介绍

pt_table_set_flash_operation(erase, write, read)

把分区表组件读写 Flash 的操作函数注册为 SDK 的 bflb_flash_erase / bflb_flash_write / bflb_flash_read

参数

  • erase:擦除回调
  • write:写入回调
  • read:读取回调

返回值:无

pt_table_get_active_partition_need_lock(ptStuff[2])

读取激活的分区表(内部带锁,线程安全)。读取时自动校验两份表,返回有效的那份。

参数

  • ptStuffpt_table_stuff_config 数组(2 份表的空间)

返回值pt_table_id_typePT_TABLE_ID_0 / PT_TABLE_ID_1;失败为 PT_TABLE_ID_INVALID

pt_table_get_active_entries_by_name(pt_stuff, name, pt_entry)

按名称查找分区条目(例程未调用,实际项目常用):如按 "PSM""FW" 等名称获取对应分区地址与大小。

参数

  • pt_stuff:分区表内容
  • name:分区名称
  • pt_entry:接收条目信息

返回值pt_table_error_type(成功为 PT_SUCCESS

完整代码

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

📜 点击展开 partition/main.c 完整代码
c
#include "bflb_flash.h"
#include "partition.h"
#include "board.h"

#define DBG_TAG "MAIN"
#include "log.h"

#define USER_UNUSED(a) ((void)(a))

static void _dump_partition(pt_table_stuff_config *part)
{
    int i;

    USER_UNUSED(i);
    USER_UNUSED(part);

    printf("======= PtTable_Config @%p=======\r\n", part);
    printf("magicCode 0x%08X;", (unsigned int)(part->pt_table.magicCode));
    printf(" version 0x%04X;", part->pt_table.version);
    printf(" entryCnt %u;", part->pt_table.entryCnt);
    printf(" age %lu;", part->pt_table.age);
    printf(" crc32 0x%08X\r\n", (unsigned int)part->pt_table.crc32);

    printf("idx  type device active_index     name   Address[0]  Address[1]  Length[0]   Length[1]   age\r\n");
    for (i = 0; i < part->pt_table.entryCnt; i++) {
        printf("[%02d] ", i);
        printf(" %02u", part->pt_entries[i].type);
        printf("     %u", part->pt_entries[i].device);
        printf("         %u", part->pt_entries[i].active_index);
        printf("     %8s", part->pt_entries[i].name);
        printf("  0x%08lx", (part->pt_entries[i].start_address[0]));
        printf("  0x%08lx", (part->pt_entries[i].start_address[1]));
        printf("  0x%08lx", (part->pt_entries[i].max_len[0]));
        printf("  0x%08lx", (part->pt_entries[i].max_len[1]));
        printf("  %lu\r\n", (part->pt_entries[i].age));
    }
}

int main(void)
{
    board_init();

    pt_table_set_flash_operation(bflb_flash_erase, bflb_flash_write, bflb_flash_read);

    pt_table_stuff_config ptstuff[2];
    pt_table_id_type active_id;

    active_id = pt_table_get_active_partition_need_lock(ptstuff);

    if (active_id < PT_TABLE_ID_INVALID) {
        _dump_partition(&ptstuff[active_id]);
    } else {
        printf("partition init fail!\r\n");
    }

    while (1) {
    }
}

FAQ

打印 partition init fail

分区表读取失败。常见原因:Flash 中分区表被破坏(两份都无效)、分区表地址与固件不匹配,或工程没有启用 CONFIG_PARTITION。重新完整烧录固件(含 partition*.bin)可恢复。

打印的条目与期望布局不一致

打印内容来自实际烧入 Flash 的分区表。核对构建用的分区配置文件(partition_cfg / pt 文件)与烧录的 partition*.bin 是否一致;修改分区配置后必须重新生成并烧录分区表。

如何按名称找到某个分区

使用 pt_table_get_active_entries_by_name(pt_stuff, "PSM", &entry),通过返回的 pt_entry 拿到 start_addressmax_len,再配合 MTD 接口读写该分区。

遇到问题?

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

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