Files
lishanpi/bsp/device/sdram/sdram_driver.cpp
T
hm fc10ef2e10 Initial commit: LSPi (LiangShanPi) project
GD32F470ZGT6 based project with full peripheral support:
- SDRAM (W9825G6KH) via EXMC
- LCD NT35510 (480x800) via EXMC NOR/PSRAM
- Flash (W25Q64) via SPI
- UART (USART0) debug console
- LED indicators
- CMSIS-DAP debug interface
- CMake + ARM GCC toolchain build system
2026-04-26 16:24:42 +08:00

700 lines
21 KiB
C++

#include "sdram_driver.h"
#include "exmc_driver.h"
#include "config.h"
#include "systick.h"
#include <cstddef>
#include <cstring>
#include <cstdio>
/* SDRAM模式寄存器定义 */
#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0003)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
/* SDRAM设备基地址定义 */
#define SDRAM_DEVICE0_BASE_ADDR ((uint32_t)0xC0000000)
#define SDRAM_DEVICE1_BASE_ADDR ((uint32_t)0xD0000000)
/* SDRAM超时定义 */
#define SDRAM_TIMEOUT ((uint32_t)0x0000FFFF)
/* 私有数据结构体 */
typedef struct
{
uint32_t base_address; /* SDRAM基地址 */
bool initialized; /* 初始化标志 */
} sdram_private_t;
/* 默认SDRAM配置(参照官方示例优化) */
static const sdram_config_t default_sdram_config = {
.column_address_width = EXMC_SDRAM_COW_ADDRESS_9,
.row_address_width = EXMC_SDRAM_ROW_ADDRESS_13,
.data_width = EXMC_SDRAM_DATABUS_WIDTH_16B,
.internal_bank_number = EXMC_SDRAM_4_INTER_BANK,
.cas_latency = EXMC_CAS_LATENCY_3_SDCLK,
.write_protection = false,
.sdclock_config = EXMC_SDCLK_PERIODS_3_HCLK,
.burst_read_switch = true,
.pipeline_read_delay = EXMC_PIPELINE_DELAY_1_HCLK,
.timing = {
.load_mode_register_delay = 2,
.exit_selfrefresh_delay = 7,
.row_address_select_delay = 5,
.auto_refresh_delay = 6,
.write_recovery_delay = 2,
.row_precharge_delay = 2,
.row_to_column_delay = 2,
}};
/* 全局SDRAM句柄(用于默认初始化) */
static sdram_handle_t default_sdram_handle = {
.device = SDRAM_DEVICE_0,
.config = default_sdram_config,
.private_data = NULL};
/* 私有数据实例 */
static sdram_private_t sdram_private[SDRAM_DEVICE_MAX];
/**
* @brief 获取EXMC SDRAM设备枚举值
* @param device SDRAM设备类型
* @return EXMC SDRAM设备值
*/
static uint32_t get_exmc_sdram_device(sdram_device_t device)
{
switch (device)
{
case SDRAM_DEVICE_0:
return EXMC_SDRAM_DEVICE0;
case SDRAM_DEVICE_1:
return EXMC_SDRAM_DEVICE1;
default:
return EXMC_SDRAM_DEVICE0;
}
}
/**
* @brief 获取EXMC SDRAM设备选择值
* @param device SDRAM设备类型
* @return EXMC SDRAM设备选择值
*/
static uint32_t get_exmc_sdram_bank_select(sdram_device_t device)
{
switch (device)
{
case SDRAM_DEVICE_0:
return EXMC_SDRAM_DEVICE0_SELECT;
case SDRAM_DEVICE_1:
return EXMC_SDRAM_DEVICE1_SELECT;
default:
return EXMC_SDRAM_DEVICE0_SELECT;
}
}
/**
* @brief 执行SDRAM初始化序列
* @param exmc_device EXMC SDRAM设备
* @param bank_select EXMC SDRAM设备选择
* @param config SDRAM配置
* @return 操作结果
*/
static ret_code_t execute_sdram_init_sequence(uint32_t exmc_device, uint32_t bank_select, const sdram_config_t *config)
{
exmc_sdram_parameter_struct sdram_init_struct;
exmc_sdram_timing_parameter_struct sdram_timing_init_struct;
exmc_sdram_command_parameter_struct sdram_command_init_struct;
uint32_t timeout = SDRAM_TIMEOUT;
uint32_t command_content;
printf("[SDRAM] 开始执行初始化序列 (设备: 0x%08lX, Bank: 0x%08lX)\r\n", exmc_device, bank_select);
/* 步骤1:配置SDRAM时序寄存器 */
printf("[SDRAM] 步骤1: 配置时序寄存器...\r\n");
sdram_timing_init_struct.load_mode_register_delay = config->timing.load_mode_register_delay;
sdram_timing_init_struct.exit_selfrefresh_delay = config->timing.exit_selfrefresh_delay;
sdram_timing_init_struct.row_address_select_delay = config->timing.row_address_select_delay;
sdram_timing_init_struct.auto_refresh_delay = config->timing.auto_refresh_delay;
sdram_timing_init_struct.write_recovery_delay = config->timing.write_recovery_delay;
sdram_timing_init_struct.row_precharge_delay = config->timing.row_precharge_delay;
sdram_timing_init_struct.row_to_column_delay = config->timing.row_to_column_delay;
printf("[SDRAM] 时序参数: LMRD=%ld, XSRD=%ld, RASD=%ld, ARFD=%ld, WRD=%ld, RPD=%ld, RCD=%ld\r\n",
sdram_timing_init_struct.load_mode_register_delay,
sdram_timing_init_struct.exit_selfrefresh_delay,
sdram_timing_init_struct.row_address_select_delay,
sdram_timing_init_struct.auto_refresh_delay,
sdram_timing_init_struct.write_recovery_delay,
sdram_timing_init_struct.row_precharge_delay,
sdram_timing_init_struct.row_to_column_delay);
/* 步骤2:配置SDRAM控制寄存器 */
printf("[SDRAM] 步骤2: 配置控制寄存器...\r\n");
sdram_init_struct.sdram_device = exmc_device;
sdram_init_struct.column_address_width = config->column_address_width;
sdram_init_struct.row_address_width = config->row_address_width;
sdram_init_struct.data_width = config->data_width;
sdram_init_struct.internal_bank_number = config->internal_bank_number;
sdram_init_struct.cas_latency = config->cas_latency;
sdram_init_struct.write_protection = config->write_protection ? ENABLE : DISABLE;
sdram_init_struct.sdclock_config = config->sdclock_config;
sdram_init_struct.burst_read_switch = config->burst_read_switch ? ENABLE : DISABLE;
sdram_init_struct.pipeline_read_delay = config->pipeline_read_delay;
sdram_init_struct.timing = &sdram_timing_init_struct;
/* EXMC SDRAM Bank初始化 */
printf("[SDRAM] 执行EXMC SDRAM初始化...\r\n");
exmc_sdram_init(&sdram_init_struct);
printf("[SDRAM] EXMC SDRAM初始化完成\r\n");
/* 步骤3:配置CKE高电平命令 */
sdram_command_init_struct.command = EXMC_SDRAM_CLOCK_ENABLE;
sdram_command_init_struct.bank_select = bank_select;
sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_2_SDCLK;
sdram_command_init_struct.mode_register_content = 0;
/* 等待SDRAM控制器就绪 */
timeout = SDRAM_TIMEOUT;
while ((exmc_flag_get(exmc_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0))
{
timeout--;
}
if (timeout == 0)
{
return RET_TIMEOUT;
}
/* 发送命令 */
exmc_sdram_command_config(&sdram_command_init_struct);
/* 步骤4:插入10ms延时 */
delay_1ms(10);
/* 步骤5:配置预充电所有命令 */
sdram_command_init_struct.command = EXMC_SDRAM_PRECHARGE_ALL;
sdram_command_init_struct.bank_select = bank_select;
sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_2_SDCLK;
sdram_command_init_struct.mode_register_content = 0;
timeout = SDRAM_TIMEOUT;
while ((exmc_flag_get(exmc_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0))
{
timeout--;
}
if (timeout == 0)
{
return RET_TIMEOUT;
}
exmc_sdram_command_config(&sdram_command_init_struct);
/* 步骤6:配置自动刷新命令 */
sdram_command_init_struct.command = EXMC_SDRAM_AUTO_REFRESH;
sdram_command_init_struct.bank_select = bank_select;
sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_9_SDCLK;
sdram_command_init_struct.mode_register_content = 0;
timeout = SDRAM_TIMEOUT;
while ((exmc_flag_get(exmc_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0))
{
timeout--;
}
if (timeout == 0)
{
return RET_TIMEOUT;
}
exmc_sdram_command_config(&sdram_command_init_struct);
/* 步骤7:配置加载模式寄存器命令 */
/* 编程模式寄存器 */
command_content = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
sdram_command_init_struct.command = EXMC_SDRAM_LOAD_MODE_REGISTER;
sdram_command_init_struct.bank_select = bank_select;
sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_2_SDCLK;
sdram_command_init_struct.mode_register_content = command_content;
timeout = SDRAM_TIMEOUT;
while ((exmc_flag_get(exmc_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0))
{
timeout--;
}
if (timeout == 0)
{
return RET_TIMEOUT;
}
exmc_sdram_command_config(&sdram_command_init_struct);
/* 步骤8:设置自动刷新速率计数器 */
/* 64ms, 8192-cycle refresh, 64ms/8192=7.81us */
/* SDCLK_Freq = HCLK/3 = 168MHz/3 = 56MHz */
/* (7.81 us * 56MHz) - 20 ≈ 418 */
exmc_sdram_refresh_count_set(418);
/* 等待SDRAM控制器就绪 */
timeout = SDRAM_TIMEOUT;
while ((exmc_flag_get(exmc_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0))
{
timeout--;
}
if (timeout == 0)
{
return RET_TIMEOUT;
}
/* 步骤9:配置读采样(解决读取数据为0的问题) */
/* 读采样延迟链补偿 PCB 走线延迟,确保 EXMC 在正确的时钟边沿采样数据 */
exmc_sdram_readsample_enable(ENABLE);
exmc_sdram_readsample_config(EXMC_SDRAM_4_DELAY_CELL, EXMC_SDRAM_READSAMPLE_0_EXTRAHCLK);
return RET_OK;
}
/* 公共函数实现 */
ret_code_t sdram_init(sdram_handle_t *handle)
{
if (handle == NULL || handle->device >= SDRAM_DEVICE_MAX)
{
printf("[SDRAM] 初始化失败: 无效参数\r\n");
return RET_INVALID_PARAM;
}
printf("[SDRAM] 开始初始化设备 %d\r\n", handle->device);
/* 初始化私有数据 */
sdram_private_t *priv = &sdram_private[handle->device];
/* 获取SDRAM基地址 */
switch (handle->device)
{
case SDRAM_DEVICE_0:
priv->base_address = SDRAM_DEVICE0_BASE_ADDR;
printf("[SDRAM] 使用设备0,基地址: 0x%08lX\r\n", priv->base_address);
break;
case SDRAM_DEVICE_1:
priv->base_address = SDRAM_DEVICE1_BASE_ADDR;
printf("[SDRAM] 使用设备1,基地址: 0x%08lX\r\n", priv->base_address);
break;
default:
printf("[SDRAM] 初始化失败: 无效设备 %d\r\n", handle->device);
return RET_INVALID_PARAM;
}
/* 显示配置信息 */
printf("[SDRAM] 配置信息:\r\n");
printf(" 列地址宽度: %d\r\n", handle->config.column_address_width == EXMC_SDRAM_COW_ADDRESS_9 ? 9 : 8);
printf(" 行地址宽度: %d\r\n", handle->config.row_address_width == EXMC_SDRAM_ROW_ADDRESS_13 ? 13 : 12);
printf(" 数据宽度: %d位\r\n", handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_16B ? 16 : (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_8B ? 8 : 32));
printf(" 内部Bank数: %d\r\n", handle->config.internal_bank_number == EXMC_SDRAM_4_INTER_BANK ? 4 : 2);
printf(" CAS延迟: %d个时钟\r\n", handle->config.cas_latency == EXMC_CAS_LATENCY_3_SDCLK ? 3 : 2);
printf(" 写保护: %s\r\n", handle->config.write_protection ? "启用" : "禁用");
printf(" SDCLK配置: HCLK/%d\r\n", handle->config.sdclock_config == EXMC_SDCLK_PERIODS_3_HCLK ? 3 : 2);
/* 初始化EXMC总线(时钟 + 共享数据引脚 + SDRAM专用引脚) */
ExmcBus &exmc_bus = ExmcBus::instance();
exmc_bus.init();
ExmcBus::sdram_pin_init();
printf("[SDRAM] EXMC总线初始化完成\r\n");
/* 获取EXMC设备参数 */
uint32_t exmc_device = get_exmc_sdram_device(handle->device);
uint32_t bank_select = get_exmc_sdram_bank_select(handle->device);
printf("[SDRAM] EXMC设备: 0x%08lX, Bank选择: 0x%08lX\r\n", exmc_device, bank_select);
/* 执行SDRAM初始化序列 */
printf("[SDRAM] 开始执行初始化序列...\r\n");
ret_code_t ret = execute_sdram_init_sequence(exmc_device, bank_select, &handle->config);
if (ret != RET_OK)
{
printf("[SDRAM] 初始化序列失败: 错误码=%d\r\n", ret);
return ret;
}
/* 标记为已初始化 */
priv->initialized = true;
handle->private_data = (void *)priv;
printf("[SDRAM] 初始化成功完成\r\n");
return RET_OK;
}
ret_code_t sdram_deinit(sdram_handle_t *handle)
{
if (handle == NULL || handle->device >= SDRAM_DEVICE_MAX)
{
return RET_INVALID_PARAM;
}
sdram_private_t *priv = (sdram_private_t *)handle->private_data;
if (priv == NULL || !priv->initialized)
{
return RET_NOT_INITIALIZED;
}
/* 禁用SDRAM控制器(通过禁用EXMC时钟) */
/* 注意:这会影响其他EXMC外设,实际项目中可能需要更精细的控制 */
rcu_periph_clock_disable(RCU_EXMC);
/* 标记为未初始化 */
priv->initialized = false;
handle->private_data = NULL;
return RET_OK;
}
ret_code_t sdram_write(sdram_handle_t *handle, uint32_t address, const void *data, uint32_t length)
{
if (handle == NULL || handle->device >= SDRAM_DEVICE_MAX || data == NULL)
{
return RET_INVALID_PARAM;
}
sdram_private_t *priv = (sdram_private_t *)handle->private_data;
if (priv == NULL || !priv->initialized)
{
return RET_NOT_INITIALIZED;
}
if (length == 0)
{
return RET_OK;
}
/* 计算实际内存地址 */
uint32_t mem_addr = priv->base_address + address;
/* 调试输出:显示写入信息 */
if (length > 1)
{
printf("[SDRAM] 写入: 地址=0x%08lX, 长度=%lu, 数据宽度=%d位\r\n",
mem_addr, length,
(handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_8B) ? 8 : (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_16B) ? 16
: 32);
if (length <= 16)
{
printf("[SDRAM] 数据: ");
const uint8_t *dbg_data = (const uint8_t *)data;
for (uint32_t i = 0; i < length && i < 16; i++)
{
printf("%02X ", dbg_data[i]);
}
printf("\r\n");
}
}
/* 根据数据宽度进行写入 */
if (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_8B)
{
uint8_t *dst = (uint8_t *)mem_addr;
const uint8_t *src = (const uint8_t *)data;
for (uint32_t i = 0; i < length; i++)
{
dst[i] = src[i];
}
}
else if (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_16B)
{
volatile uint16_t *dst = (volatile uint16_t *)mem_addr;
const uint8_t *src = (const uint8_t *)data;
uint32_t halfword_len = length / 2;
for (uint32_t i = 0; i < halfword_len; i++)
{
dst[i] = (uint16_t)(src[i * 2] | ((uint16_t)src[i * 2 + 1] << 8));
}
if (length & 1)
{
uint16_t last_word = dst[halfword_len];
last_word = (last_word & 0xFF00) | src[length - 1];
dst[halfword_len] = last_word;
}
__DSB();
}
else if (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_32B)
{
volatile uint32_t *dst = (volatile uint32_t *)mem_addr;
const uint32_t *src = (const uint32_t *)data;
uint32_t dword_len = length / 4;
for (uint32_t i = 0; i < dword_len; i++)
{
dst[i] = src[i];
}
uint32_t remain = length % 4;
if (remain)
{
volatile uint8_t *dst8 = (volatile uint8_t *)&dst[dword_len];
const uint8_t *src8 = (const uint8_t *)&src[dword_len];
for (uint32_t i = 0; i < remain; i++)
{
dst8[i] = src8[i];
}
}
}
else
{
return RET_NOT_SUPPORTED;
}
/* 数据同步屏障,确保所有写入完成 */
__DSB();
return RET_OK;
}
ret_code_t sdram_read(sdram_handle_t *handle, uint32_t address, void *buffer, uint32_t length)
{
if (handle == NULL || handle->device >= SDRAM_DEVICE_MAX || buffer == NULL)
{
return RET_INVALID_PARAM;
}
sdram_private_t *priv = (sdram_private_t *)handle->private_data;
if (priv == NULL || !priv->initialized)
{
return RET_NOT_INITIALIZED;
}
if (length == 0)
{
return RET_OK;
}
/* 计算实际内存地址 */
uint32_t mem_addr = priv->base_address + address;
/* 根据数据宽度进行读取 */
if (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_8B)
{
uint8_t *src = (uint8_t *)mem_addr;
uint8_t *dst = (uint8_t *)buffer;
for (uint32_t i = 0; i < length; i++)
{
dst[i] = src[i];
}
}
else if (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_16B)
{
__DSB();
volatile uint16_t *src = (volatile uint16_t *)mem_addr;
uint8_t *dst = (uint8_t *)buffer;
uint32_t halfword_len = length / 2;
for (uint32_t i = 0; i < halfword_len; i++)
{
uint32_t val = src[i];
dst[i * 2] = (uint8_t)(val & 0xFF);
dst[i * 2 + 1] = (uint8_t)((val >> 8) & 0xFF);
}
if (length & 1)
{
uint16_t val = src[halfword_len];
dst[length - 1] = (uint8_t)(val & 0xFF);
}
__DSB();
}
else if (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_32B)
{
volatile uint32_t *src = (volatile uint32_t *)mem_addr;
uint32_t *dst = (uint32_t *)buffer;
uint32_t dword_len = length / 4;
for (uint32_t i = 0; i < dword_len; i++)
{
dst[i] = src[i];
}
uint32_t remain = length % 4;
if (remain)
{
volatile uint8_t *src8 = (volatile uint8_t *)&src[dword_len];
uint8_t *dst8 = (uint8_t *)&dst[dword_len];
for (uint32_t i = 0; i < remain; i++)
{
dst8[i] = src8[i];
}
}
}
else
{
return RET_NOT_SUPPORTED;
}
/* 数据内存屏障,确保所有读取完成并按顺序执行 */
__DMB();
return RET_OK;
}
ret_code_t sdram_fill(sdram_handle_t *handle, uint32_t address, uint8_t value, uint32_t length)
{
if (handle == NULL || handle->device >= SDRAM_DEVICE_MAX)
{
return RET_INVALID_PARAM;
}
sdram_private_t *priv = (sdram_private_t *)handle->private_data;
if (priv == NULL || !priv->initialized)
{
return RET_NOT_INITIALIZED;
}
if (length == 0)
{
return RET_OK;
}
/* 计算实际内存地址 */
uint32_t mem_addr = priv->base_address + address;
/* 根据数据宽度进行填充 */
if (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_8B)
{
/* 8位填充 */
uint8_t *dst = (uint8_t *)mem_addr;
for (uint32_t i = 0; i < length; i++)
{
dst[i] = value;
}
}
else if (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_16B)
{
/* 16位填充,需要处理地址对齐 */
uint16_t word_value = (value << 8) | value;
uint8_t *dst8 = (uint8_t *)mem_addr;
uint16_t *dst16;
/* 检查地址对齐 */
if ((address & 0x1) != 0)
{
/* 地址未对齐,先填充第一个字节 */
dst8[0] = value;
dst8++;
length--;
}
/* 填充完整的16位字 */
dst16 = (uint16_t *)dst8;
uint32_t word_count = length / 2;
for (uint32_t i = 0; i < word_count; i++)
{
dst16[i] = word_value;
}
/* 处理剩余的单个字节(如果长度是奇数) */
if (length & 0x1)
{
dst8 = (uint8_t *)&dst16[word_count];
dst8[0] = value;
}
}
else if (handle->config.data_width == EXMC_SDRAM_DATABUS_WIDTH_32B)
{
/* 32位填充,需要地址对齐 */
uint32_t dword_value = (value << 24) | (value << 16) | (value << 8) | value;
uint32_t *dst = (uint32_t *)mem_addr;
uint32_t dword_count = (length + 3) / 4;
for (uint32_t i = 0; i < dword_count; i++)
{
dst[i] = dword_value;
}
}
else
{
return RET_NOT_SUPPORTED;
}
return RET_OK;
}
ret_code_t sdram_self_test(sdram_handle_t *handle, uint32_t test_size)
{
if (handle == NULL || handle->device >= SDRAM_DEVICE_MAX)
{
return RET_INVALID_PARAM;
}
sdram_private_t *priv = (sdram_private_t *)handle->private_data;
if (priv == NULL || !priv->initialized)
{
return RET_NOT_INITIALIZED;
}
/* 限制测试大小,避免超出SDRAM容量 */
if (test_size > 1024 * 1024)
{
test_size = 1024 * 1024;
}
/* 使用固定块大小进行测试,通过驱动API读写SDRAM */
#define SELF_TEST_BLOCK_SIZE 256
ret_code_t ret;
uint8_t write_buf[SELF_TEST_BLOCK_SIZE];
uint8_t read_buf[SELF_TEST_BLOCK_SIZE];
for (uint32_t offset = 0; offset < test_size; offset += SELF_TEST_BLOCK_SIZE)
{
uint32_t block_size = (test_size - offset) > SELF_TEST_BLOCK_SIZE ? SELF_TEST_BLOCK_SIZE : (test_size - offset);
for (uint32_t i = 0; i < block_size; i++)
{
write_buf[i] = (uint8_t)((offset + i) & 0xFF);
}
ret = sdram_write(handle, offset, write_buf, block_size);
if (ret != RET_OK)
{
return ret;
}
ret = sdram_read(handle, offset, read_buf, block_size);
if (ret != RET_OK)
{
return ret;
}
for (uint32_t i = 0; i < block_size; i++)
{
if (read_buf[i] != write_buf[i])
{
return RET_ERROR;
}
}
}
return RET_OK;
}
uint32_t sdram_get_base_address(sdram_device_t device)
{
switch (device)
{
case SDRAM_DEVICE_0:
return SDRAM_DEVICE0_BASE_ADDR;
case SDRAM_DEVICE_1:
return SDRAM_DEVICE1_BASE_ADDR;
default:
return 0;
}
}
ret_code_t sdram_default_init(void)
{
/* 使用默认句柄进行初始化 */
return sdram_init(&default_sdram_handle);
}