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_infoviabflb_efuse_get_device_infoto 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 zeroinstruction 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_infoto 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_mainacross 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
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.
Open a terminal and enter the SDK memtester example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):
cd examples/memtesterRun 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=bl616dkConnect 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/ttyUSB0Open 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: outputbflb_efuse_device_info_typestructure
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 addresssize: bytes to testmemsuffix: 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
#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.

