Skip to content

Concepts First

  • PSRAM: external large memory (cheaper than SRAM, faster than Flash) for big caches/buffers.
  • Cache coherency: the CPU data cache can hide stale values when reading/writing PSRAM; the example disables/cleans the cache first so results are real.
  • What the test does: writes incrementing data at different widths and reads it back for comparison, checking memory correctness bit by bit.

Example Overview

This page is based on the psram example in the official Bouffalo SDK (examples/peripherals/psram), which demonstrates onboard PSRAM read/write testing:

  • Gets the PSRAM size with board_psram_size_get();
  • Writes incrementing data and reads it back at uint8 / uint16 / uint32 widths;
  • Disables/cleans the data cache first (bflb_l1c_dcache_disable + clean_all) so reads reflect the real memory.

Operation Steps

1
Enter the Example Directory

This page reads/writes the onboard PSRAM directly; no external wiring is needed (the board must have PSRAM). Open a terminal and enter the PSRAM example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):

cd examples/peripherals/psram
2
Build the Project

Run the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616:

make CHIP=bl616 BOARD=bl616dk
3
Flash the Firmware

Connect the board with a USB cable, hold the BOOT button (IO2 on the Ai-M61-32S-Kit), briefly press EN/RST to enter download mode, then flash (replace the serial port with the one on your computer):

make flash CHIP=bl616 COMX=/dev/ttyUSB0
4
Run and Verify

Open a serial tool (baud rate 2000000). The example prints the PSRAM size, then runs 8/16/32-bit write/read checks; it prints test success when all pass, or psram check fail and stops on error.

Code Execution Flow

The complete execution flow from startup to running is shown below (loop arrows mean repeated execution):

APIs Used by the Example

board_psram_size_get()

Gets the onboard PSRAM size in bytes (printed in MB).

Parameters: none

Return: PSRAM size in bytes

bflb_l1c_dcache_disable()

Disables the data cache so reads/writes go directly to memory, avoiding cache coherency issues.

Parameters: none

Return: none

bflb_l1c_dcache_clean_all()

Cleans the whole data cache, writing dirty data back to memory.

Parameters: none

Return: none

BFLB_PSRAM_BASE(macro)

PSRAM mapping base address; the example reads/writes at BFLB_PSRAM_BASE + offset.

Parameters: none

Return: PSRAM base address

Complete Code

The complete source below matches the effect described on this page. It is based on the official example (examples/peripherals/psram); the LED pins are adapted to the Ai-M61/62-32S-Kit onboard RGB LED. Collapsed by default, click to expand:

📜 Click to expand psram/main.c full code
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

First confirm the board has PSRAM (module variant with PSRAM); verify board_psram_size_get() returns non-zero; if you changed cache handling, check that the cache is disabled/cleaned correctly before read/write.

Why start the test address at 0?

The example tests the first 1 MB from the PSRAM base. In a real project, avoid areas already used by the linker/heap.

Does disabling the cache hurt performance?

Yes. Cache is disabled only for test correctness; keep it enabled in real use and manage DMA-shared regions with bflb_l1c_dcache_clean/invalidate_range.

Have questions?

For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

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