Skip to content

概念先知道

  • PSRAM:外挂的大容量内存(比 SRAM 便宜、比 Flash 快),适合大缓存/大缓冲场景。
  • 缓存一致性:CPU 有数据缓存,直接读写 PSRAM 可能读到旧值;例程先关闭/清理缓存再测试,保证结果真实。
  • 测试的本质:按不同数据宽度写入递增数据再读回比对,逐位检查内存读写正确。

例程功能简介

本页对应博流官方 SDK 的 psram 例程(examples/peripherals/psram),演示板载 PSRAM 的读写测试

  • 通过 board_psram_size_get() 获取 PSRAM 容量;
  • 依次以 uint8 / uint16 / uint32 三种宽度向 PSRAM 写入递增数据再读回校验;
  • 测试前先关闭/清理数据缓存(bflb_l1c_dcache_disable + clean_all),保证读到的是真实内存内容。

操作步骤

1
进入例程目录

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

cd examples/peripherals/psram
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)。例程打印 PSRAM 大小后,依次做 8/16/32 位写读校验,全部通过打印 test success;任一步失败会打印 psram check fail 并停住。

代码执行流程

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

例程调用的 API 介绍

board_psram_size_get()

获取板载 PSRAM 容量(字节),例程换算成 MB 打印。

参数:无

返回值:PSRAM 容量(字节)

bflb_l1c_dcache_disable()

关闭数据缓存,使读写直达内存,避免缓存不一致导致校验失败。

参数:无

返回值:无

bflb_l1c_dcache_clean_all()

清理全部数据缓存,把脏数据写回内存。

参数:无

返回值:无

BFLB_PSRAM_BASE(宏)

PSRAM 映射基地址,例程在 BFLB_PSRAM_BASE + 偏移 处读写测试数据。

参数:无

返回值:PSRAM 基地址

完整代码

以下为 psram/main.c 完整源码,与官方示例(examples/peripherals/psram)一致;点灯引脚已适配 Ai-M61/62-32S-Kit 板载 RGB 灯,默认折叠,点击展开:

📜 点击展开 psram/main.c 完整代码
c
#include "bflb_core.h"
#include "bflb_l1c.h"
#include "board.h"
#if __has_include("board_flash_psram.h")
#include "board_flash_psram.h"
#else
extern uint32_t board_psram_size_get(void);
#endif

#define BFLB_PSRAM_TEST_ADDR (BFLB_PSRAM_BASE + (0 * 1024 * 1024))

uint32_t psram_test_size = 0;

void test32(void)
{
    uint32_t i, val;

    printf("============= check uint32_t ==============\r\n");

    for (i = 0; i < psram_test_size; i += 4) {
        *((volatile uint32_t *)(BFLB_PSRAM_TEST_ADDR + i)) = i / 4;
    }

    for (i = 0; i < psram_test_size; i += 4) {
        val = *((volatile uint32_t *)(BFLB_PSRAM_TEST_ADDR + i));
        if (i / 4 != val) {
            printf("addr = 0x%08X, val = 0x%08X, expect = 0x%08X\r\n", (BFLB_PSRAM_TEST_ADDR + i), val, i / 4);
            printf("psram check fail\r\n");
            while (1)
                ;
        }
    }
}

void test16(void)
{
    uint32_t i, val;

    printf("============= check uint16_t ==============\r\n");

    for (i = 0; i < psram_test_size; i += 2) {
        *((volatile uint16_t *)(BFLB_PSRAM_TEST_ADDR + i)) = i / 2;
    }
    for (i = 0; i < psram_test_size; i += 2) {
        val = *((volatile uint16_t *)(BFLB_PSRAM_TEST_ADDR + i));

        if (((i / 2) & 0xffff) != val) {
            printf("addr = 0x%08X, val = 0x%08X, expect = 0x%08X\r\n", (BFLB_PSRAM_TEST_ADDR + i), val, (i / 2) & 0xffff);
            printf("psram check fail\r\n");
            while (1) {
            }
        }
    }
}

void test8(void)
{
    uint32_t i;
    uint8_t val;

    printf("============= check uint8_t ==============\r\n");

    for (i = 0; i < psram_test_size; i++) {
        *((volatile uint8_t *)(BFLB_PSRAM_TEST_ADDR + i)) = i;
    }

    for (i = 0; i < psram_test_size; i++) {
        val = *((volatile uint8_t *)(BFLB_PSRAM_TEST_ADDR + i));

        if ((i & 0xff) != val) {
            printf("addr = 0x%08X, val = 0x%08X, expect = 0x%08X\r\n", (BFLB_PSRAM_TEST_ADDR + i), val, i & 0xff);
            printf("psram check fail\r\n");
            while (1) {
            }
        }
    }
}

int main(void)
{
    board_init();

    psram_test_size = board_psram_size_get();
    printf(" psram test size: %u MB\r\n", psram_test_size / (1024 * 1024));
    printf(" psram read write test \r\n");

    bflb_l1c_dcache_clean_all();

    bflb_l1c_dcache_disable();

    test8();
    test16();
    test32();

    printf(" test success\r\n");

    while (1) {
    }
}

FAQ

psram check fail

先确认开发板带 PSRAM(模组型号带 PSRAM 版本);确认 board_psram_size_get() 返回非 0;若改动过缓存处理代码,检查是否在读写前正确关闭/清理缓存。

测试地址为什么要从 0 开始

例程从 PSRAM 基地址起始的 1MB 区间测试。实际项目注意避开已被链接器/堆使用的区域。

缓存关闭后性能会变差吗

会。关闭缓存只是为了测试正确性;实际使用中保持缓存开启,并通过 bflb_l1c_dcache_clean/invalidate_range 处理 DMA 共享区域。

遇到问题?

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

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