Skip to content

Concepts First

  • Stress test: repeatedly writing memory with various data patterns to expose hidden faults such as bit flips, address-line errors, or timing instability — commonly used in production testing and stability validation.
  • PSRAM: an external memory chip; capacity depends on the model. The example reads psram_info via bflb_efuse_get_device_info to get the size (4/8/16 MB).
  • memtester: a classic open-source memory test program (memtester_main) supporting many algorithms: random values, XOR inversions, 8/16/32/64-bit data-line patterns, etc.
  • Cache toggle: the test can enable/disable D-Cache; with the cache off it reads/writes PSRAM directly, exposing timing issues the cache would hide.
  • XIP address: the example accesses PSRAM directly at addresses such as 0xA8000000 (BL616), then uses a div zero instruction to induce a long-latency stall after testing.

Example Overview

This page is based on the memtester example in the official Bouffalo SDK (examples/memtester), which demonstrates full-capacity PSRAM stress testing:

  • Reads psram_info to determine capacity (4/8/16 MB) and the PSRAM clock frequency;
  • Prints the test parameters: base 0xA8000000, test size, 1000 loops, 1 KB page size, cache enable;
  • Runs memtester_main across the whole capacity, checking page by page;
  • Prints memtester stress test done! at the end, then enters a long-latency stall loop (div zero) to avoid heat and interference.
  • Sibling examples: examples/bflb_block_pool (memory pool) and the "RAM Speed Bandwidth Test" page in Basic Peripherals (ram_speed).

Note

A full-capacity run takes several minutes; if errors appear mid-run, the PSRAM or timing config is suspect — try lowering dramFreq or rerun without cache to isolate the problem.

Operation Steps

1
Hardware Preparation

You need a board with PSRAM. The example reads psram_info from the chip’s efuse to pick the test size (4/8/16 MB). Boards without PSRAM print This chip has no psram and halt.

2
Enter the Example Directory

Open a terminal and enter the SDK memtester example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):

cd examples/memtester
3
Build the Project

Run the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616 (the example defconfig already enables CONFIG_PSRAM=y):

make CHIP=bl616 BOARD=bl616dk
4
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
5
Run and Verify

Open a serial tool (baud rate 2000000). The example prints the PSRAM test settings (base address, size, 1000 loops, frequency, cache enable), then stress-tests the whole PSRAM with multiple memtester algorithms (random values, inversions, 8/16/32-bit patterns, etc.). On success it prints memtester stress test done!.

Code Execution Flow

The flow from boot to test completion is:

APIs Used by the Example

bflb_efuse_get_device_info(&device_info)

Reads chip factory info; device_info.psram_info is the PSRAM capacity tier (1=4 MB, 2=8 MB, 3=16 MB).

Parameters:

  • device_info: output bflb_efuse_device_info_type structure

Returns: 0 on success; negative on failure

memtester_main(base, size, &suffix, loops, page_size)

Runs the memory stress test. The example passes the base address, test size, unit suffix, 1000 loops, and 1 KB page size.

Parameters:

  • base: start address
  • size: bytes to test
  • memsuffix: capacity unit ('B')
  • loops: loop count (1000 here)
  • page_size: page size (1 KB here)

Returns: none

Clock_Peripheral_Clock_Get(BL_PERIPHERAL_CLOCK_PSRAMB)

Gets the PSRAM bus clock; the example uses it to print the PSRAM frequency in MHz.

Parameters:

  • peripheral: peripheral clock enum (PSRAMB)

Returns: clock frequency

bflb_l1c_dcache_clean_all / bflb_l1c_dcache_disable()

Disables D-Cache (only when enableCache=0) so the test reads/writes PSRAM directly, validating stability without the cache.

Parameters: none

Returns: none

Complete Code

The following is the complete source of memtester/main.c, identical to the official example, collapsed by default:

📜 Click to expand memtester/main.c full code
c
#include "bflb_mtimer.h"
#include "bflb_efuse.h"
#include "board.h"
#include "stdlib.h"
#include "string.h"
#include "memtester.h"

#if defined(BL616)
#include "bl616_common.h"
#include "bl616_glb.h"
// #include "bl616_sec_eng.h"
#include "bl616_tzc_sec.h"
#include "bl616_psram.h"
#endif

#if defined(BL616CL)
#include "bl616cl_common.h"
#include "bl616cl_glb.h"
// #include "bl616_sec_eng.h"
#include "bl616cl_tzc_sec.h"
#include "bl616cl_psram.h"
#endif

#if defined(BL618DG)
#include "bl618dg_common.h"
#include "bl618dg_glb.h"
// #include "bl606p_sec_eng.h"
#include "bl618dg_psram.h"
#endif

#define UHS_PSRAM_ADDR       (0x50000000)
#define BL616_X8_PSRAM_ADDR  (0xA8000000)
#define BL616CL_X8_PSRAM_ADDR (0x88000000)
#define BL618DG_X8_PSRAM_ADDR (0xB8000000)
#define MEMTESTER_M0
// #define MEMTESTER_D0

typedef struct _semc_test_config {
    uint32_t baseAddr;
    uint32_t testSize;
    uint32_t loopNum;
    uint32_t dramFreq;
    uint32_t enableCache;
} semc_test_config_t;

int fail_stop = 1;

// uint64_t l1c_hit = 0, l1c_miss = 0;
// uint32_t read_hit_h = 0, read_hit_l = 0, read_miss_h = 0, read_miss_l = 0;
// uint32_t write_hit_h = 0, write_hit_l = 0, write_miss_h = 0, write_miss_l = 0;

int main(void)
{
    bflb_efuse_device_info_type device_info;

    board_init();

    char memsuffix = 'B';
    /* --------------- stress test --------------- */
    semc_test_config_t testConfig;
#if defined(BL616)
    testConfig.baseAddr = BL616_X8_PSRAM_ADDR;
    testConfig.dramFreq = Clock_Peripheral_Clock_Get(BL_PERIPHERAL_CLOCK_PSRAMB) / 1000000;
#elif defined(BL616CL)
    testConfig.baseAddr = BL616CL_X8_PSRAM_ADDR;
    testConfig.dramFreq = Clock_Peripheral_Clock_Get(BL_PERIPHERAL_CLOCK_PSRAMB) / 1000000;
#elif defined(BL618DG)
    testConfig.baseAddr = BL618DG_X8_PSRAM_ADDR;
    testConfig.dramFreq = Clock_Peripheral_Clock_Get(BL_PERIPHERAL_CLOCK_PSRAMB) / 1000000;
#endif
    testConfig.testSize = 0;
    testConfig.loopNum = 1000;
    testConfig.enableCache = 1;

    printf("mtimer clk:%d\r\n", CPU_Get_MTimer_Clock());
    printf("psram clk :%d\r\n", testConfig.dramFreq);
    printf("Now CPU size_t:%d\r\n", sizeof(size_t));

    bflb_efuse_get_device_info(&device_info);
    if (device_info.psram_info == 0) {
        printf("This chip has no psram, please disable CONFIG_PSRAM\r\n");
        while (1) {}
    }
#if 0
    switch (device_info.psram_info) {
        case 2:
            testConfig.testSize = 32 * 1024 * 1024;
            break;
        case 3:
            testConfig.testSize = 64 * 1024 * 1024;
            break;
        default:
            printf("Psram info error\r\n");
            while (1) {}
            break;
    }
#else
    switch (device_info.psram_info) {
        case 1:
            testConfig.testSize = 4 * 1024 * 1024;
            break;
        case 2:
            testConfig.testSize = 8 * 1024 * 1024;
            break;
        case 3:
            testConfig.testSize = 16 * 1024 * 1024;
            break;
        default:
            printf("Psram info error\r\n");
            while (1) {}
            break;
    }
#endif

#if defined(MEMTESTER_M0)
    if (!testConfig.enableCache) {
        /* Disable D cache */
        bflb_l1c_dcache_clean_all();
        bflb_l1c_dcache_disable();
    }

    printf("\r\n########## Print out from target board ##########\r\n");
    printf("\r\n PSRAM r/w test settings:\r\n");
    printf("      Base Addr: 0x%x;\r\n", testConfig.baseAddr);
    printf("      Test Size: %d Bytes;\r\n", testConfig.testSize);
    printf("      Test Loop: %d;\r\n", testConfig.loopNum);
    printf(" PSRAM PLL Freq: %d MHz;\r\n", testConfig.dramFreq);
    printf("   Enable Cache: %d;\r\n\r\n", testConfig.enableCache);

    /* Run memory stress test: 64MByte, loop=1, page_size = 1kbyte */
    memtester_main(testConfig.baseAddr, testConfig.testSize, &memsuffix, testConfig.loopNum, (1 * 1024));
#endif

    while (1) {
#ifdef __riscv_muldiv
        int dummy;
        /* In lieu of a halt instruction, induce a long-latency stall. */
        __asm__ __volatile__("div %0, %0, zero"
                             : "=r"(dummy));
#endif
    }

    printf("memtester stress test done!\r\n");
    while (1) {
        bflb_mtimer_delay_ms(1000);
    }
}

FAQ

\"This chip has no psram\" — what now?

The chip has no PSRAM or efuse does not record capacity. Confirm your board model has PSRAM (e.g., Ai-M61-32S-Kit / Ai-M62-32S); if it does, check that CONFIG_PSRAM=y is enabled in defconfig.

Errors appear mid-test?

The stress test found data mismatches. Common causes: PSRAM frequency too high (try lowering dramFreq), insufficient power, or board layout interference. Rerun with enableCache=0 (no-cache mode) to narrow it down.

Why does the program sit in a dead loop after the test?

After completion the example uses a div zero instruction to create a long-latency stall (not a real crash) so the CPU waits in a low-power state. Press reset to restart.

How long does the test take?

It depends on PSRAM size and frequency: 4 MB takes a few minutes, 16 MB ten minutes or more. For a quick check, lower testConfig.loopNum (e.g., 10) and rebuild.

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