SRAM完整性验证——读写整个外部SRAM验证是否损坏
前言
本文记录了GD32进阶学习中小作业的解决办法,本次遇到的问题是如何读写整个外部sram,并输出信息实现对外部sram的完整性验证。
一、什么是SRAM
SRAM是静态随机存取存储器的缩写,可读可写,掉电失数据。
一般常用于cpu的一二级缓存当中,速度快,价格贵,GD32F303ZET6内部SRAM容量为96kb,本次使用的开发板上还集成有IS62WV51216外部SRAM芯片。
本次实验外部SRAM地址范围为0x6c000000--0x6c0fffff。
二、外部SRAM驱动方法
1.使用EXMC驱动
EXMC选中Bank0中的Region3区域进行控制
/*********************************************************************************************************
* 函数名称:ConfigBank0Region3
* 函数功能:配置外部存储Bank0的Region3
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2021年07月01日
* 注 意:外部SRAM位于外部存储Bank0的Region3
*********************************************************************************************************/
static void ConfigBank0Region3(void)
{
exmc_norsram_parameter_struct sram_init_struct;
exmc_norsram_timing_parameter_struct sram_timing_init_struct;
//使能EXMC时钟
rcu_periph_clock_enable(RCU_EXMC);
//外部SRAM读写时序
sram_timing_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A; //模式A,异步访问SRAM
sram_timing_init_struct.asyn_address_setuptime = 0; //异步访问地址建立时间
sram_timing_init_struct.asyn_address_holdtime = 0; //异步访问地址保持时间
sram_timing_init_struct.asyn_data_setuptime = 3; //异步访问数据建立时间
sram_timing_init_struct.bus_latency = 0; //同步/异步访问总线延时时间
sram_timing_init_struct.syn_clk_division = 0; //同步访问时钟分频系数(从HCLK中分频)
sram_timing_init_struct.syn_data_latency = 0; //同步访问中获得第1个数据所需要的等待延迟
//Region3配置
sram_init_struct.norsram_region = EXMC_BANK0_NORSRAM_REGION3; //Region3
sram_init_struct.address_data_mux = DISABLE; //禁用地址、数据总线多路复用
sram_init_struct.memory_type = EXMC_MEMORY_TYPE_SRAM; //储存器类型为SRAM
sram_init_struct.databus_width = EXMC_NOR_DATABUS_WIDTH_16B; //数据宽度16位
sram_init_struct.burst_mode = DISABLE; //禁用突发访问
sram_init_struct.nwait_config = EXMC_NWAIT_CONFIG_BEFORE; //等待输入配置
sram_init_struct.nwait_polarity = EXMC_NWAIT_POLARITY_LOW; //等待输入信号低电平有效
sram_init_struct.wrap_burst_mode = DISABLE; //禁用包突发访问
sram_init_struct.asyn_wait = DISABLE; //禁用异步等待
sram_init_struct.extended_mode = DISABLE; //禁用扩展模式
sram_init_struct.memory_write = ENABLE; //使能写入外部存储器
sram_init_struct.nwait_signal = DISABLE; //禁用等待输入信号
sram_init_struct.write_mode = EXMC_ASYN_WRITE; //写入模式为异步写入
sram_init_struct.read_write_timing = &sram_timing_init_struct; //读时序配置
sram_init_struct.write_timing = &sram_timing_init_struct; //写时序配置
//初始化Region3
exmc_norsram_init(&sram_init_struct);
//使能Region3
exmc_norsram_enable(EXMC_BANK0_NORSRAM_REGION3);
}
2.主要内部函数
static u8 ReadByte(u32 addr); //读取特定地址数据(1字节)
static void WriteByte(u32 addr, u8 data); //往特定地址内写入1字节数据
/*********************************************************************************************************
* 函数名称:ReadByte
* 函数功能:读取特定地址数据(1字节)
* 输入参数:addr:读取地址
* 输出参数:void
* 返 回 值:读到的数据
* 创建日期:2021年07月01日
* 注 意:
*********************************************************************************************************/
static u8 ReadByte(u32 addr)
{
return *(u8*)addr;
}
/*********************************************************************************************************
* 函数名称:WriteByte
* 函数功能:往特定地址内写入1字节数据
* 输入参数:addr:写入地址,data:写入数据(字节)
* 输出参数:void
* 返 回 值:void
* 创建日期:2021年07月01日
* 注 意:
*********************************************************************************************************/
static void WriteByte(u32 addr, u8 data)
{
*(u8*)addr = data;
}
3.全填充测试函数
使用一个全填充函数对所有的SRAM区域进行读写测试,主要定义一个输出信息结构体,以及全填充测试函数test_sram_full
// 测试结果结构体
typedef struct {
u32 first_fail_addr;//首次错误地址。
u8 expected;//存储测试时预期写入的数据值(例如 0xFF或 0x00)。
u8 actual;//记录从 first_fail_addr地址实际读取的数据值。
u32 total_errors;//统计整个 SRAM 测试中发生错误的总次数。
} SRAM_TestResult;
/*********************************************************************************************************
* 函数名称:test_sram_full
* 函数功能:全填充测试函数
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2021年07月01日
* 注 意:
*********************************************************************************************************/
SRAM_TestResult test_sram_full(u8 pattern)
{
u8 value;
u32 addr;
SRAM_TestResult result = {0};
for (addr = SRAM_START; addr <= SRAM_END; addr++)
{
WriteByte(addr, pattern); // 写入模式值
value = ReadByte(addr); // 读取1字节
if (value != pattern)
{
if (result.total_errors == 0)
{ // 记录首个错误
result.first_fail_addr = addr;
result.expected = pattern;
result.actual = value;
}
result.total_errors++;
}
}
return result;
}
三、调用函数输出
SRAM_TestResult test1;
SRAM_TestResult test2;
int main(void)
{
// 测试1:全写0xFF
test1 = test_sram_full(0xFF);
printf("Test 1 (0xFF): Errors=%d, First Fail: 0x%X (Exp:0x%X, Act:0x%X)\n",
test1.total_errors, test1.first_fail_addr, test1.expected, test1.actual);
// 测试2:全写0x00
test2 = test_sram_full(0x00);
printf("Test 2 (0x00): Errors=%d, First Fail: 0x%X (Exp:0x%X, Act:0x%X)\n",
test2.total_errors, test2.first_fail_addr, test2.expected, test2.actual);
}
总结
通过设置结构体动态错误记录,实现记录首个错误地址及值,并统计错误总数,避免海量输出淹没关键信息。
同时查阅资料可知传统全写相同值可能掩盖以下问题:
-
地址线故障:高位地址线断路导致地址重叠(如
0x6c000000
与0x6c000001
因A0线故障被映射到同一单元)。 -
数据线粘连:某数据位始终为高/低电平(如D3粘连导致无法写入0)。
-
控制信号异常:片选(CS)或写使能(WE)信号失效。
可以通过地址线测试(Walking Bit)完善
SRAM_TestResult test_sram_addressing() {
SRAM_TestResult result = {0};
for (u32 addr = SRAM_START; addr <= SRAM_END; addr++) {
u8 pattern = addr & 0xFF; // 地址低8位作为特征值
WriteByte(addr, pattern);
u8 value = ReadByte(addr);
if (value != pattern) {
if (result.total_errors == 0) {
result.first_fail_addr = addr;
result.expected = pattern;
result.actual = value;
}
result.total_errors++;
}
}
return result;
}
使用行走位模式(Walking Bit)写入地址特征值(如addr & 0xFF
),使每个地址写入值唯一,解决传统全写相同值不能发现的:高位地址线断路导致地址重叠(如0x6c000000
与0x6c000001
因A0线故障被映射到同一单元)的问题