Skip to content

概念先知道

  • Flash:掉电不丢数据的存储芯片,固件和用户数据都存在里面;本页演示最基础的数据区读写。
  • 先擦后写:Flash 只能把 1 变成 0(写),把 0 变回 1 必须先擦除,且擦除按扇区(例程 4KB)进行。
  • 擦除后的状态:Flash 擦除后所有位恢复为 1,即读回每个字节都是 0xFF,例程用它校验擦除是否成功。
  • 注意安全:写 Flash 前务必确认目标地址不在固件、分区表与 OTA 区域内,否则会破坏程序。

例程功能简介

本页对应博流官方 SDK 的 flash_read_write 例程(examples/peripherals/flash/flash_read_write),演示内部 Flash 最基础的擦除、写入与读取校验

  • 从偏移 0x10000 开始,每次擦除 4KB(一页),共操作 10 页(40KB);
  • 擦除后读回,逐字节确认全部为 0xFF
  • 写入 0~255 递增的测试数据(4KB 内循环),再读回逐字节比对,任何不一致都会打印失败信息并停住;
  • 每页校验通过打印 check success,10 页全部完成打印 flash read write success
  • 同族例程examples/peripherals/flash/):flash_dma(DMA 读取,见「基础外设 → Flash 内部存储」)、flash_xip_read(XIP 读取)、flash_iomode(IO 模式)、flash_get_image_hash(镜像哈希)、flash_secreg / flash_secreg_lock(安全寄存器)、flash_secure_read_write(安全读写)。

注意

例程操作的是 0x10000 偏移的 Flash 区域,这是官方示例预留的测试区。实际项目写 Flash 前务必确认目标地址不在固件、分区表与 OTA 区域内,否则会破坏程序。

操作步骤

1
进入例程目录

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

cd examples/peripherals/flash/flash_read_write
2
编译工程

执行编译命令。Ai-M62(BL616)与 Ai-M61(BL618)同属一个系列,统一填写引脚最少的 bl616 即可:

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

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

make flash CHIP=bl616 COMX=/dev/ttyUSB0
4
运行验证

打开串口助手(波特率 2000000)。程序从偏移 0x10000 开始,按 4KB 一页逐页操作 10 页(共 40KB):先擦除并读回校验(应全为 0xFF),再写入 0~255 递增数据并读回逐字节校验,每页打印 check success,全部完成后打印 flash read write success

代码执行流程

例程从启动到运行的完整流程如下(图中的循环箭头表示反复执行):

例程调用的 API 介绍

bflb_flash_erase(addr, len)

擦除 Flash 区域。擦除按扇区进行,len 不足一扇区时按一扇区处理;擦除后该区域读回为 0xFF

参数

  • addr:Flash 地址(例程从 0x10000 开始,按 4KB 递增)
  • len:擦除长度(例程 4096)

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

bflb_flash_write(addr, data, len)

向 Flash 写入数据。写之前必须先擦除对应扇区,且写入地址要按 Flash 的最小编程单位对齐。

参数

  • addr:Flash 地址
  • data:待写入数据缓冲区
  • len:写入长度

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

bflb_flash_read(addr, data, len)

从 Flash 读取数据到内存缓冲区。

参数

  • addr:Flash 地址
  • data:接收缓冲区
  • len:读取长度

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

完整代码

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

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

#define FLASH_RW_TOTAL_SIZE (10 * 4096)
#define FLASH_RW_START_ADDR 0x10000

static uint8_t write_buf[4096];
static uint8_t read_buf[4096];

int main(void)
{
    uint32_t i, j;
    uint32_t flash_addr;

    board_init();

    for (i = 0; i < sizeof(write_buf); i++) {
        write_buf[i] = i;
    }

    for (uint32_t offset = 0; offset < FLASH_RW_TOTAL_SIZE; offset += sizeof(write_buf)) {
        flash_addr = FLASH_RW_START_ADDR + offset;
        printf("erase addr:%08x\r\n", flash_addr);

        /* erase flash */
        bflb_flash_erase(flash_addr, sizeof(write_buf));

        memset(read_buf, 0, sizeof(read_buf));
        /* read flash data */
        bflb_flash_read(flash_addr, read_buf, sizeof(read_buf));

        for (j = 0; j < sizeof(read_buf); j++) {
            if (read_buf[j] != 0xff) {
                printf("flash erase fail at %d, expect:%d but get %d\r\n", j, 0xff, read_buf[j]);
                while (1) {
                }
            }
        }

        /* write flash data */
        bflb_flash_write(flash_addr, write_buf, sizeof(write_buf));

        memset(read_buf, 0, sizeof(read_buf));
        /* read flash data */
        bflb_flash_read(flash_addr, read_buf, sizeof(read_buf));

        for (j = 0; j < sizeof(read_buf); j++) {
            if (read_buf[j] != write_buf[j]) {
                printf("flash read fail at %d, expect:%d but get %d\r\n", j, write_buf[j], read_buf[j]);
                while (1) {
                }
            }
        }
        printf("check success\r\n");
    }

    printf("flash read write success\r\n");

    while (1) {
    }
}

FAQ

打印 flash erase fail

擦除后读回不是 0xFF。常见原因是该地址并非空闲区域(如固件、分区表所在),或 Flash 型号/扇区大小与例程假设不符。换用官方预留的测试区地址再试。

打印 flash read fail

写入后读回与写入值不一致。先确认写入前已擦除(先擦后写),并确认地址对齐、长度不超过扇区/Flash 容量。

烧录后程序跑飞或反复重启

很可能例程写坏了固件所在区域。重新进入下载模式完整烧录一次即可恢复;以后做 Flash 读写实验时,把地址限定在官方预留的测试区。

遇到问题?

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

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