refactor: 完整C++面向对象重构(LedManager/SdramManager)
This commit is contained in:
+147
-118
@@ -12,62 +12,27 @@
|
|||||||
|
|
||||||
__attribute__((section(".sdram"))) uint8_t sdram_big_buffer[1024 * 1024];
|
__attribute__((section(".sdram"))) uint8_t sdram_big_buffer[1024 * 1024];
|
||||||
|
|
||||||
#define LED1_PORT GPIOE
|
|
||||||
#define LED1_PIN GPIO_PIN_3
|
|
||||||
#define LED2_PORT GPIOD
|
|
||||||
#define LED2_PIN GPIO_PIN_7
|
|
||||||
#define LED3_PORT GPIOG
|
|
||||||
#define LED3_PIN GPIO_PIN_3
|
|
||||||
#define LED4_PORT GPIOA
|
|
||||||
#define LED4_PIN GPIO_PIN_5
|
|
||||||
|
|
||||||
static void delay_16m(uint32_t ms)
|
static void delay_16m(uint32_t ms)
|
||||||
{
|
{
|
||||||
for (volatile uint32_t i = 0; i < ms * 4000U; i++);
|
for (volatile uint32_t i = 0; i < ms * 4000U; i++)
|
||||||
}
|
;
|
||||||
|
|
||||||
static void led_on(uint32_t port, uint32_t pin)
|
|
||||||
{
|
|
||||||
gpio_bit_set(port, pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void led_off(uint32_t port, uint32_t pin)
|
|
||||||
{
|
|
||||||
gpio_bit_reset(port, pin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void led_pattern(uint8_t p)
|
static void led_pattern(uint8_t p)
|
||||||
{
|
{
|
||||||
led_off(LED1_PORT, LED1_PIN);
|
LedManager &lm = LedManager::instance();
|
||||||
led_off(LED2_PORT, LED2_PIN);
|
lm.led(0).off();
|
||||||
led_off(LED3_PORT, LED3_PIN);
|
lm.led(1).off();
|
||||||
led_off(LED4_PORT, LED4_PIN);
|
lm.led(2).off();
|
||||||
if (p & 0x01) led_on(LED1_PORT, LED1_PIN);
|
lm.led(3).off();
|
||||||
if (p & 0x02) led_on(LED2_PORT, LED2_PIN);
|
if (p & 0x01)
|
||||||
if (p & 0x04) led_on(LED3_PORT, LED3_PIN);
|
lm.led(0).on();
|
||||||
if (p & 0x08) led_on(LED4_PORT, LED4_PIN);
|
if (p & 0x02)
|
||||||
}
|
lm.led(1).on();
|
||||||
|
if (p & 0x04)
|
||||||
static void init_leds(void)
|
lm.led(2).on();
|
||||||
{
|
if (p & 0x08)
|
||||||
rcu_periph_clock_enable(RCU_GPIOA);
|
lm.led(3).on();
|
||||||
rcu_periph_clock_enable(RCU_GPIOE);
|
|
||||||
rcu_periph_clock_enable(RCU_GPIOG);
|
|
||||||
rcu_periph_clock_enable(RCU_GPIOD);
|
|
||||||
|
|
||||||
gpio_mode_set(LED1_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED1_PIN);
|
|
||||||
gpio_output_options_set(LED1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED1_PIN);
|
|
||||||
gpio_mode_set(LED2_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED2_PIN);
|
|
||||||
gpio_output_options_set(LED2_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED2_PIN);
|
|
||||||
gpio_mode_set(LED3_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED3_PIN);
|
|
||||||
gpio_output_options_set(LED3_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED3_PIN);
|
|
||||||
gpio_mode_set(LED4_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED4_PIN);
|
|
||||||
gpio_output_options_set(LED4_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED4_PIN);
|
|
||||||
|
|
||||||
led_off(LED1_PORT, LED1_PIN);
|
|
||||||
led_off(LED2_PORT, LED2_PIN);
|
|
||||||
led_off(LED3_PORT, LED3_PIN);
|
|
||||||
led_off(LED4_PORT, LED4_PIN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_usart0(void)
|
static void init_usart0(void)
|
||||||
@@ -89,21 +54,32 @@ static void init_usart0(void)
|
|||||||
static void uart_putchar(char c)
|
static void uart_putchar(char c)
|
||||||
{
|
{
|
||||||
usart_data_transmit(USART0, (uint8_t)c);
|
usart_data_transmit(USART0, (uint8_t)c);
|
||||||
while (RESET == usart_flag_get(USART0, USART_FLAG_TBE));
|
while (RESET == usart_flag_get(USART0, USART_FLAG_TBE))
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uart_puts(const char *s)
|
static void uart_puts(const char *s)
|
||||||
{
|
{
|
||||||
while (*s) uart_putchar(*s++);
|
while (*s)
|
||||||
|
uart_putchar(*s++);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uart_putdec(uint32_t val)
|
static void uart_putdec(uint32_t val)
|
||||||
{
|
{
|
||||||
char buf[16];
|
char buf[16];
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
if (val == 0) { uart_puts("0"); return; }
|
if (val == 0)
|
||||||
while (val > 0) { buf[idx++] = '0' + (val % 10); val /= 10; }
|
{
|
||||||
while (idx > 0) uart_putchar(buf[--idx]);
|
uart_puts("0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (val > 0)
|
||||||
|
{
|
||||||
|
buf[idx++] = '0' + (val % 10);
|
||||||
|
val /= 10;
|
||||||
|
}
|
||||||
|
while (idx > 0)
|
||||||
|
uart_putchar(buf[--idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reinit_usart0_168m(void)
|
static void reinit_usart0_168m(void)
|
||||||
@@ -121,7 +97,8 @@ static void test_sdram_driver(void)
|
|||||||
|
|
||||||
SdramManager &sdram = SdramManager::instance();
|
SdramManager &sdram = SdramManager::instance();
|
||||||
RetCode ret = sdram.init();
|
RetCode ret = sdram.init();
|
||||||
if (ret != RET_OK) {
|
if (ret != RET_OK)
|
||||||
|
{
|
||||||
printf(" SDRAM 初始化失败: 错误码=%d\r\n", ret);
|
printf(" SDRAM 初始化失败: 错误码=%d\r\n", ret);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -134,10 +111,12 @@ static void test_sdram_driver(void)
|
|||||||
delay_1ms(1);
|
delay_1ms(1);
|
||||||
|
|
||||||
bool diag1_ok = true;
|
bool diag1_ok = true;
|
||||||
for (uint32_t i = 0; i < 8; i++) {
|
for (uint32_t i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
uint16_t val = sram16[i];
|
uint16_t val = sram16[i];
|
||||||
uint16_t expected = (uint16_t)(0xAA00 + i);
|
uint16_t expected = (uint16_t)(0xAA00 + i);
|
||||||
if (val != expected) {
|
if (val != expected)
|
||||||
|
{
|
||||||
printf(" 16位错误 @ [%lu]: 期望=0x%04X, 读取=0x%04X\r\n", i, expected, val);
|
printf(" 16位错误 @ [%lu]: 期望=0x%04X, 读取=0x%04X\r\n", i, expected, val);
|
||||||
diag1_ok = false;
|
diag1_ok = false;
|
||||||
}
|
}
|
||||||
@@ -154,11 +133,14 @@ static void test_sdram_driver(void)
|
|||||||
delay_1ms(1);
|
delay_1ms(1);
|
||||||
|
|
||||||
bool diag2_ok = true;
|
bool diag2_ok = true;
|
||||||
for (uint32_t i = 0; i < 4; i++) {
|
for (uint32_t i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
uint32_t val = sram32[i];
|
uint32_t val = sram32[i];
|
||||||
uint32_t expected = (i == 0) ? 0xDEADBEEF : (i == 1) ? 0xCAFEBABE
|
uint32_t expected = (i == 0) ? 0xDEADBEEF : (i == 1) ? 0xCAFEBABE
|
||||||
: (i == 2) ? 0x12345678 : 0x87654321;
|
: (i == 2) ? 0x12345678
|
||||||
if (val != expected) {
|
: 0x87654321;
|
||||||
|
if (val != expected)
|
||||||
|
{
|
||||||
printf(" 32位错误 @ [%lu]: 期望=0x%08lX, 读取=0x%08lX\r\n", i, expected, val);
|
printf(" 32位错误 @ [%lu]: 期望=0x%08lX, 读取=0x%08lX\r\n", i, expected, val);
|
||||||
diag2_ok = false;
|
diag2_ok = false;
|
||||||
}
|
}
|
||||||
@@ -169,9 +151,12 @@ static void test_sdram_driver(void)
|
|||||||
uint32_t write_val = 0xA5A55A5A;
|
uint32_t write_val = 0xA5A55A5A;
|
||||||
uint32_t read_val = 0;
|
uint32_t read_val = 0;
|
||||||
ret = sdram.write(64, &write_val, sizeof(write_val));
|
ret = sdram.write(64, &write_val, sizeof(write_val));
|
||||||
if (ret != RET_OK) {
|
if (ret != RET_OK)
|
||||||
|
{
|
||||||
printf(" 驱动写入失败: %d\r\n", ret);
|
printf(" 驱动写入失败: %d\r\n", ret);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
__DSB();
|
__DSB();
|
||||||
ret = sdram.read(64, &read_val, sizeof(read_val));
|
ret = sdram.read(64, &read_val, sizeof(read_val));
|
||||||
if (ret != RET_OK)
|
if (ret != RET_OK)
|
||||||
@@ -190,7 +175,8 @@ static void test_flash_driver(void)
|
|||||||
|
|
||||||
FlashManager &flash = FlashManager::instance();
|
FlashManager &flash = FlashManager::instance();
|
||||||
RetCode ret = flash.init();
|
RetCode ret = flash.init();
|
||||||
if (ret != RET_OK) {
|
if (ret != RET_OK)
|
||||||
|
{
|
||||||
printf(" Flash 初始化失败: %d\r\n", ret);
|
printf(" Flash 初始化失败: %d\r\n", ret);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -208,32 +194,49 @@ static void test_flash_driver(void)
|
|||||||
|
|
||||||
printf(" 擦除 Flash 扇区...\r\n");
|
printf(" 擦除 Flash 扇区...\r\n");
|
||||||
ret = flash.erase(test_address, flash.sector_size());
|
ret = flash.erase(test_address, flash.sector_size());
|
||||||
if (ret != RET_OK) { printf(" Flash 擦除失败: 错误码=%d\r\n", ret); return; }
|
if (ret != RET_OK)
|
||||||
|
{
|
||||||
|
printf(" Flash 擦除失败: 错误码=%d\r\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
printf(" Flash 擦除成功\r\n");
|
printf(" Flash 擦除成功\r\n");
|
||||||
|
|
||||||
printf(" 写入 Flash 数据...\r\n");
|
printf(" 写入 Flash 数据...\r\n");
|
||||||
ret = flash.write(test_address, write_buffer, sizeof(write_buffer));
|
ret = flash.write(test_address, write_buffer, sizeof(write_buffer));
|
||||||
if (ret != RET_OK) { printf(" Flash 写入失败: %d\r\n", ret); return; }
|
if (ret != RET_OK)
|
||||||
|
{
|
||||||
|
printf(" Flash 写入失败: %d\r\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
printf(" Flash 写入成功\r\n");
|
printf(" Flash 写入成功\r\n");
|
||||||
|
|
||||||
printf(" 读取 Flash 数据...\r\n");
|
printf(" 读取 Flash 数据...\r\n");
|
||||||
ret = flash.read(test_address, read_buffer, sizeof(read_buffer));
|
ret = flash.read(test_address, read_buffer, sizeof(read_buffer));
|
||||||
if (ret != RET_OK) { printf(" Flash 读取失败: %d\r\n", ret); return; }
|
if (ret != RET_OK)
|
||||||
|
{
|
||||||
|
printf(" Flash 读取失败: %d\r\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
printf(" Flash 读取成功\r\n");
|
printf(" Flash 读取成功\r\n");
|
||||||
|
|
||||||
bool verify_ok = true;
|
bool verify_ok = true;
|
||||||
for (int i = 0; i < 256; i++) {
|
for (int i = 0; i < 256; i++)
|
||||||
if (read_buffer[i] != write_buffer[i]) {
|
{
|
||||||
|
if (read_buffer[i] != write_buffer[i])
|
||||||
|
{
|
||||||
verify_ok = false;
|
verify_ok = false;
|
||||||
printf(" 数据错误 @ %d: 写入=%02X, 读取=%02X\r\n", i, write_buffer[i], read_buffer[i]);
|
printf(" 数据错误 @ %d: 写入=%02X, 读取=%02X\r\n", i, write_buffer[i], read_buffer[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (verify_ok) printf(" Flash 数据验证成功\r\n");
|
if (verify_ok)
|
||||||
|
printf(" Flash 数据验证成功\r\n");
|
||||||
|
|
||||||
ret = flash.self_test(256);
|
ret = flash.self_test(256);
|
||||||
if (ret == RET_OK) printf(" Flash 自测试通过\r\n");
|
if (ret == RET_OK)
|
||||||
else printf(" Flash 自测试失败: %d\r\n", ret);
|
printf(" Flash 自测试通过\r\n");
|
||||||
|
else
|
||||||
|
printf(" Flash 自测试失败: %d\r\n", ret);
|
||||||
printf("Flash 驱动测试完成\r\n");
|
printf("Flash 驱动测试完成\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +252,8 @@ static void test_lcd(void)
|
|||||||
delay_1ms(500);
|
delay_1ms(500);
|
||||||
|
|
||||||
uint16_t bands[4] = {Lcd::RED, Lcd::GREEN, Lcd::BLUE, Lcd::WHITE};
|
uint16_t bands[4] = {Lcd::RED, Lcd::GREEN, Lcd::BLUE, Lcd::WHITE};
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
int y0 = i * 200;
|
int y0 = i * 200;
|
||||||
int y1 = y0 + 199;
|
int y1 = y0 + 199;
|
||||||
lcd.blockWrite(0, 479, y0, y1);
|
lcd.blockWrite(0, 479, y0, y1);
|
||||||
@@ -279,10 +283,12 @@ static void test_sdram_after_lcd(void)
|
|||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
volatile uint16_t *sram16 = (volatile uint16_t *)0xC0000000;
|
volatile uint16_t *sram16 = (volatile uint16_t *)0xC0000000;
|
||||||
for (uint32_t i = 0; i < 8; i++) {
|
for (uint32_t i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
uint16_t val = sram16[i];
|
uint16_t val = sram16[i];
|
||||||
uint16_t expected = (uint16_t)(0xAA00 + i);
|
uint16_t expected = (uint16_t)(0xAA00 + i);
|
||||||
if (val != expected) {
|
if (val != expected)
|
||||||
|
{
|
||||||
printf(" 16位错误 @ [%lu]: 期望=0x%04X, 读取=0x%04X\r\n", i, expected, val);
|
printf(" 16位错误 @ [%lu]: 期望=0x%04X, 读取=0x%04X\r\n", i, expected, val);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
@@ -290,9 +296,11 @@ static void test_sdram_after_lcd(void)
|
|||||||
|
|
||||||
volatile uint32_t *sram32 = (volatile uint32_t *)0xC0000000;
|
volatile uint32_t *sram32 = (volatile uint32_t *)0xC0000000;
|
||||||
uint32_t expected_32[4] = {0xDEADBEEF, 0xCAFEBABE, 0x12345678, 0x87654321};
|
uint32_t expected_32[4] = {0xDEADBEEF, 0xCAFEBABE, 0x12345678, 0x87654321};
|
||||||
for (uint32_t i = 0; i < 4; i++) {
|
for (uint32_t i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
uint32_t val = sram32[i];
|
uint32_t val = sram32[i];
|
||||||
if (val != expected_32[i]) {
|
if (val != expected_32[i])
|
||||||
|
{
|
||||||
printf(" 32位错误 @ [%lu]: 期望=0x%08lX, 读取=0x%08lX\r\n", i, expected_32[i], val);
|
printf(" 32位错误 @ [%lu]: 期望=0x%08lX, 读取=0x%08lX\r\n", i, expected_32[i], val);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
@@ -312,17 +320,18 @@ static void concurrent_loop(void)
|
|||||||
uint32_t counter = 0;
|
uint32_t counter = 0;
|
||||||
volatile uint16_t *sram16 = (volatile uint16_t *)0xC0000000;
|
volatile uint16_t *sram16 = (volatile uint16_t *)0xC0000000;
|
||||||
|
|
||||||
for (int iter = 0; iter < 10; iter++) {
|
for (int iter = 0; iter < 10; iter++)
|
||||||
led_on(LED1_PORT, LED1_PIN);
|
{
|
||||||
led_off(LED2_PORT, LED2_PIN);
|
LedManager::instance().led(0).on();
|
||||||
|
LedManager::instance().led(1).off();
|
||||||
sram16[100 + iter] = (uint16_t)(iter * 0x1111);
|
sram16[100 + iter] = (uint16_t)(iter * 0x1111);
|
||||||
__DSB();
|
__DSB();
|
||||||
uint16_t val = sram16[100 + iter];
|
uint16_t val = sram16[100 + iter];
|
||||||
printf("[并发] iter=%d, SDRAM[%d]=0x%04X, LED1=ON\r\n", iter, 100 + iter, val);
|
printf("[并发] iter=%d, SDRAM[%d]=0x%04X, LED1=ON\r\n", iter, 100 + iter, val);
|
||||||
delay_1ms(500);
|
delay_1ms(500);
|
||||||
|
|
||||||
led_off(LED1_PORT, LED1_PIN);
|
LedManager::instance().led(0).off();
|
||||||
led_on(LED2_PORT, LED2_PIN);
|
LedManager::instance().led(1).on();
|
||||||
sram16[200 + iter] = (uint16_t)(iter * 0x2222);
|
sram16[200 + iter] = (uint16_t)(iter * 0x2222);
|
||||||
__DSB();
|
__DSB();
|
||||||
val = sram16[200 + iter];
|
val = sram16[200 + iter];
|
||||||
@@ -345,18 +354,19 @@ static void test_touch(void)
|
|||||||
printf("\r\n===== Touch 测试 (多点触控) =====\r\n");
|
printf("\r\n===== Touch 测试 (多点触控) =====\r\n");
|
||||||
|
|
||||||
RetCode ret = touch.init();
|
RetCode ret = touch.init();
|
||||||
if (ret != RET_OK) {
|
if (ret != RET_OK)
|
||||||
|
{
|
||||||
printf(" Touch 初始化失败 (ret=%d)\r\n", ret);
|
printf(" Touch 初始化失败 (ret=%d)\r\n", ret);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printf(" Touch 初始化成功,等待触摸中断...\r\n");
|
printf(" Touch 初始化成功,等待触摸中断...\r\n");
|
||||||
|
|
||||||
static const uint16_t TP_COLORS[5] = {
|
static const uint16_t TP_COLORS[5] = {
|
||||||
0xFFE0, // YELLOW - point 0
|
0xFFE0, // YELLOW - point 0
|
||||||
0x07FF, // CYAN - point 1
|
0x07FF, // CYAN - point 1
|
||||||
0xF81F, // MAGENTA - point 2
|
0xF81F, // MAGENTA - point 2
|
||||||
0x07E0, // GREEN - point 3
|
0x07E0, // GREEN - point 3
|
||||||
0xF800 // RED - point 4
|
0xF800 // RED - point 4
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint16_t BG_COLOR = 0x0841;
|
const uint16_t BG_COLOR = 0x0841;
|
||||||
@@ -367,7 +377,8 @@ static void test_touch(void)
|
|||||||
lcd.setForeground(Lcd::WHITE);
|
lcd.setForeground(Lcd::WHITE);
|
||||||
lcd.showString(10, 30, 460, 24, 16, 0, (uint8_t *)"Touch with up to 5 fingers");
|
lcd.showString(10, 30, 460, 24, 16, 0, (uint8_t *)"Touch with up to 5 fingers");
|
||||||
|
|
||||||
for (uint8_t i = 0; i < GT1151::kMaxTouch; i++) {
|
for (uint8_t i = 0; i < GT1151::kMaxTouch; i++)
|
||||||
|
{
|
||||||
lcd.setForeground(TP_COLORS[i]);
|
lcd.setForeground(TP_COLORS[i]);
|
||||||
char lbl[8];
|
char lbl[8];
|
||||||
sprintf(lbl, "P%d: --", i);
|
sprintf(lbl, "P%d: --", i);
|
||||||
@@ -377,7 +388,8 @@ static void test_touch(void)
|
|||||||
uint16_t last_x[5];
|
uint16_t last_x[5];
|
||||||
uint16_t last_y[5];
|
uint16_t last_y[5];
|
||||||
bool was_active[5];
|
bool was_active[5];
|
||||||
for (uint8_t i = 0; i < GT1151::kMaxTouch; i++) {
|
for (uint8_t i = 0; i < GT1151::kMaxTouch; i++)
|
||||||
|
{
|
||||||
last_x[i] = 0xFFFF;
|
last_x[i] = 0xFFFF;
|
||||||
last_y[i] = 0xFFFF;
|
last_y[i] = 0xFFFF;
|
||||||
was_active[i] = false;
|
was_active[i] = false;
|
||||||
@@ -386,8 +398,10 @@ static void test_touch(void)
|
|||||||
uint32_t idle_counter = 0;
|
uint32_t idle_counter = 0;
|
||||||
GT1151::irq_flag = 0;
|
GT1151::irq_flag = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1)
|
||||||
if (GT1151::irq_flag) {
|
{
|
||||||
|
if (GT1151::irq_flag)
|
||||||
|
{
|
||||||
GT1151::irq_flag = 0;
|
GT1151::irq_flag = 0;
|
||||||
delay_1ms(5);
|
delay_1ms(5);
|
||||||
|
|
||||||
@@ -399,21 +413,25 @@ static void test_touch(void)
|
|||||||
uint8_t active_cnt = touch.activeCount();
|
uint8_t active_cnt = touch.activeCount();
|
||||||
uint8_t mask = sta & 0x1F;
|
uint8_t mask = sta & 0x1F;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < GT1151::kMaxTouch; i++) {
|
for (uint8_t i = 0; i < GT1151::kMaxTouch; i++)
|
||||||
|
{
|
||||||
bool active = (mask & (1 << i)) != 0;
|
bool active = (mask & (1 << i)) != 0;
|
||||||
|
|
||||||
if (active) {
|
if (active)
|
||||||
|
{
|
||||||
uint16_t x = touch.x(i);
|
uint16_t x = touch.x(i);
|
||||||
uint16_t y = touch.y(i);
|
uint16_t y = touch.y(i);
|
||||||
|
|
||||||
if (x < lcd.width() && y < lcd.height()) {
|
if (x < lcd.width() && y < lcd.height())
|
||||||
|
{
|
||||||
lcd.setForeground(TP_COLORS[i]);
|
lcd.setForeground(TP_COLORS[i]);
|
||||||
char buf[20];
|
char buf[20];
|
||||||
sprintf(buf, "P%d: X:%-3d Y:%-3d", i, x, y);
|
sprintf(buf, "P%d: X:%-3d Y:%-3d", i, x, y);
|
||||||
lcd.fillRectangle(10, 52 + i * 18, 200, 52 + i * 18 + 17);
|
lcd.fillRectangle(10, 52 + i * 18, 200, 52 + i * 18 + 17);
|
||||||
lcd.showString(10, 52 + i * 18, 200, 18, 16, 0, (uint8_t *)buf);
|
lcd.showString(10, 52 + i * 18, 200, 18, 16, 0, (uint8_t *)buf);
|
||||||
|
|
||||||
if (was_active[i] && last_x[i] != 0xFFFF) {
|
if (was_active[i] && last_x[i] != 0xFFFF)
|
||||||
|
{
|
||||||
lcd.setForeground(TP_COLORS[i]);
|
lcd.setForeground(TP_COLORS[i]);
|
||||||
lcd.drawLine(last_x[i], last_y[i], x, y);
|
lcd.drawLine(last_x[i], last_y[i], x, y);
|
||||||
}
|
}
|
||||||
@@ -425,8 +443,11 @@ static void test_touch(void)
|
|||||||
last_y[i] = y;
|
last_y[i] = y;
|
||||||
was_active[i] = true;
|
was_active[i] = true;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (was_active[i]) {
|
else
|
||||||
|
{
|
||||||
|
if (was_active[i])
|
||||||
|
{
|
||||||
lcd.setForeground(BG_COLOR);
|
lcd.setForeground(BG_COLOR);
|
||||||
lcd.fillCircle(last_x[i], last_y[i], 6);
|
lcd.fillCircle(last_x[i], last_y[i], 6);
|
||||||
|
|
||||||
@@ -442,15 +463,19 @@ static void test_touch(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("[TOUCH] cnt=%d sta=0x%02X", active_cnt, sta);
|
printf("[TOUCH] cnt=%d sta=0x%02X", active_cnt, sta);
|
||||||
for (uint8_t i = 0; i < GT1151::kMaxTouch; i++) {
|
for (uint8_t i = 0; i < GT1151::kMaxTouch; i++)
|
||||||
|
{
|
||||||
if (mask & (1 << i))
|
if (mask & (1 << i))
|
||||||
printf(" P%d(%u,%u)", i, touch.x(i), touch.y(i));
|
printf(" P%d(%u,%u)", i, touch.x(i), touch.y(i));
|
||||||
}
|
}
|
||||||
printf("\r\n");
|
printf("\r\n");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
idle_counter++;
|
idle_counter++;
|
||||||
delay_1ms(10);
|
delay_1ms(10);
|
||||||
if (idle_counter > 500) {
|
if (idle_counter > 500)
|
||||||
|
{
|
||||||
printf(" 无触摸超过 5 秒,退出 Touch 测试\r\n");
|
printf(" 无触摸超过 5 秒,退出 Touch 测试\r\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -464,7 +489,7 @@ static void test_touch(void)
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
init_leds();
|
LedManager::instance().init_all();
|
||||||
led_pattern(0x01);
|
led_pattern(0x01);
|
||||||
|
|
||||||
init_usart0();
|
init_usart0();
|
||||||
@@ -475,18 +500,23 @@ int main(void)
|
|||||||
|
|
||||||
uint32_t cs = RCU_CFG0 & RCU_CFG0_SCS;
|
uint32_t cs = RCU_CFG0 & RCU_CFG0_SCS;
|
||||||
uart_puts("Clock source: ");
|
uart_puts("Clock source: ");
|
||||||
if (cs == RCU_SCSS_IRC16M) uart_puts("IRC16M (16MHz)\r\n");
|
if (cs == RCU_SCSS_IRC16M)
|
||||||
else if (cs == RCU_SCSS_HXTAL) uart_puts("HXTAL (25MHz)\r\n");
|
uart_puts("IRC16M (16MHz)\r\n");
|
||||||
else if (cs == RCU_SCSS_PLLP) uart_puts("PLL (168MHz)\r\n");
|
else if (cs == RCU_SCSS_HXTAL)
|
||||||
else uart_puts("UNKNOWN\r\n");
|
uart_puts("HXTAL (25MHz)\r\n");
|
||||||
|
else if (cs == RCU_SCSS_PLLP)
|
||||||
|
uart_puts("PLL (168MHz)\r\n");
|
||||||
|
else
|
||||||
|
uart_puts("UNKNOWN\r\n");
|
||||||
uart_puts("SystemCoreClock: ");
|
uart_puts("SystemCoreClock: ");
|
||||||
uart_putdec(SystemCoreClock);
|
uart_putdec(SystemCoreClock);
|
||||||
uart_puts(" Hz\r\n");
|
uart_puts(" Hz\r\n");
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++)
|
||||||
led_on(LED2_PORT, LED2_PIN);
|
{
|
||||||
|
LedManager::instance().led(1).on();
|
||||||
delay_16m(200);
|
delay_16m(200);
|
||||||
led_off(LED2_PORT, LED2_PIN);
|
LedManager::instance().led(1).off();
|
||||||
delay_16m(200);
|
delay_16m(200);
|
||||||
}
|
}
|
||||||
uart_puts("LED blink OK\r\n");
|
uart_puts("LED blink OK\r\n");
|
||||||
@@ -500,17 +530,15 @@ int main(void)
|
|||||||
|
|
||||||
cs = RCU_CFG0 & RCU_CFG0_SCS;
|
cs = RCU_CFG0 & RCU_CFG0_SCS;
|
||||||
uart_puts("Clock after init: ");
|
uart_puts("Clock after init: ");
|
||||||
if (cs == RCU_SCSS_PLLP) uart_puts("PLL (168MHz)\r\n");
|
if (cs == RCU_SCSS_PLLP)
|
||||||
else uart_puts("UNKNOWN\r\n");
|
uart_puts("PLL (168MHz)\r\n");
|
||||||
|
else
|
||||||
|
uart_puts("UNKNOWN\r\n");
|
||||||
uart_puts("SystemCoreClock: ");
|
uart_puts("SystemCoreClock: ");
|
||||||
uart_putdec(SystemCoreClock);
|
uart_putdec(SystemCoreClock);
|
||||||
uart_puts(" Hz\r\n");
|
uart_puts(" Hz\r\n");
|
||||||
|
|
||||||
led_pattern(0x07);
|
led_pattern(0x07);
|
||||||
LedManager::instance().init_all();
|
|
||||||
LedManager::instance().led(1).on();
|
|
||||||
delay_16m(100);
|
|
||||||
LedManager::instance().led(1).off();
|
|
||||||
uart_puts("LedManager OK\r\n");
|
uart_puts("LedManager OK\r\n");
|
||||||
|
|
||||||
led_pattern(0x09);
|
led_pattern(0x09);
|
||||||
@@ -554,10 +582,11 @@ int main(void)
|
|||||||
printf("系统运行于 168MHz, Flash/SDRAM/LCD/UART/LED 全部正常\r\n");
|
printf("系统运行于 168MHz, Flash/SDRAM/LCD/UART/LED 全部正常\r\n");
|
||||||
|
|
||||||
uint32_t tick = 0;
|
uint32_t tick = 0;
|
||||||
while (1) {
|
while (1)
|
||||||
led_on(LED4_PORT, LED4_PIN);
|
{
|
||||||
|
LedManager::instance().led(3).on();
|
||||||
delay_1ms(250);
|
delay_1ms(250);
|
||||||
led_off(LED4_PORT, LED4_PIN);
|
LedManager::instance().led(3).off();
|
||||||
delay_1ms(250);
|
delay_1ms(250);
|
||||||
|
|
||||||
tick++;
|
tick++;
|
||||||
|
|||||||
@@ -1,699 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
#ifndef __SDRAM_DRIVER_H__
|
|
||||||
#define __SDRAM_DRIVER_H__
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include "common_types.h"
|
|
||||||
#include "gd32f4xx.h"
|
|
||||||
|
|
||||||
/* SDRAM设备类型定义 */
|
|
||||||
typedef enum {
|
|
||||||
SDRAM_DEVICE_0 = 0, /* SDRAM设备0,基地址0xC0000000 */
|
|
||||||
SDRAM_DEVICE_1 = 1, /* SDRAM设备1,基地址0xD0000000 */
|
|
||||||
SDRAM_DEVICE_MAX
|
|
||||||
} sdram_device_t;
|
|
||||||
|
|
||||||
/* SDRAM配置结构体 */
|
|
||||||
typedef struct {
|
|
||||||
uint32_t column_address_width; /* 列地址宽度: 8, 9, 10, 11, 12位 */
|
|
||||||
uint32_t row_address_width; /* 行地址宽度: 11, 12, 13位 */
|
|
||||||
uint32_t data_width; /* 数据总线宽度: 8, 16, 32位 */
|
|
||||||
uint32_t internal_bank_number; /* 内部Bank数量: 2或4 */
|
|
||||||
uint32_t cas_latency; /* CAS延迟: 1, 2, 3个时钟周期 */
|
|
||||||
bool write_protection; /* 写保护使能 */
|
|
||||||
uint32_t sdclock_config; /* SDCLK配置: HCLK分频 */
|
|
||||||
bool burst_read_switch; /* 突发读取开关 */
|
|
||||||
uint32_t pipeline_read_delay; /* 流水线读取延迟: 0, 1, 2个HCLK */
|
|
||||||
|
|
||||||
/* 时序参数 */
|
|
||||||
struct {
|
|
||||||
uint32_t load_mode_register_delay; /* 加载模式寄存器延迟 (LMRD) */
|
|
||||||
uint32_t exit_selfrefresh_delay; /* 退出自刷新延迟 (XSRD) */
|
|
||||||
uint32_t row_address_select_delay; /* 行地址选择延迟 (RASD) */
|
|
||||||
uint32_t auto_refresh_delay; /* 自动刷新延迟 (ARFD) */
|
|
||||||
uint32_t write_recovery_delay; /* 写恢复延迟 (WRD) */
|
|
||||||
uint32_t row_precharge_delay; /* 行预充电延迟 (RPD) */
|
|
||||||
uint32_t row_to_column_delay; /* 行到列延迟 (RCD) */
|
|
||||||
} timing;
|
|
||||||
} sdram_config_t;
|
|
||||||
|
|
||||||
/* SDRAM句柄结构体 */
|
|
||||||
typedef struct {
|
|
||||||
sdram_device_t device; /* SDRAM设备 */
|
|
||||||
sdram_config_t config; /* SDRAM配置 */
|
|
||||||
void *private_data; /* 私有数据指针 */
|
|
||||||
} sdram_handle_t;
|
|
||||||
|
|
||||||
/* 函数声明 */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 初始化SDRAM
|
|
||||||
* @param handle SDRAM句柄指针
|
|
||||||
* @return 操作结果
|
|
||||||
*/
|
|
||||||
ret_code_t sdram_init(sdram_handle_t *handle);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 反初始化SDRAM
|
|
||||||
* @param handle SDRAM句柄指针
|
|
||||||
* @return 操作结果
|
|
||||||
*/
|
|
||||||
ret_code_t sdram_deinit(sdram_handle_t *handle);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 写入数据到SDRAM
|
|
||||||
* @param handle SDRAM句柄指针
|
|
||||||
* @param address 相对地址(从SDRAM基地址开始的偏移)
|
|
||||||
* @param data 数据指针
|
|
||||||
* @param length 数据长度(字节)
|
|
||||||
* @return 操作结果
|
|
||||||
*/
|
|
||||||
ret_code_t sdram_write(sdram_handle_t *handle, uint32_t address, const void *data, uint32_t length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 从SDRAM读取数据
|
|
||||||
* @param handle SDRAM句柄指针
|
|
||||||
* @param address 相对地址(从SDRAM基地址开始的偏移)
|
|
||||||
* @param buffer 缓冲区指针
|
|
||||||
* @param length 数据长度(字节)
|
|
||||||
* @return 操作结果
|
|
||||||
*/
|
|
||||||
ret_code_t sdram_read(sdram_handle_t *handle, uint32_t address, void *buffer, uint32_t length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 填充SDRAM区域
|
|
||||||
* @param handle SDRAM句柄指针
|
|
||||||
* @param address 起始地址
|
|
||||||
* @param value 填充值
|
|
||||||
* @param length 填充长度(字节)
|
|
||||||
* @return 操作结果
|
|
||||||
*/
|
|
||||||
ret_code_t sdram_fill(sdram_handle_t *handle, uint32_t address, uint8_t value, uint32_t length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 验证SDRAM读写功能
|
|
||||||
* @param handle SDRAM句柄指针
|
|
||||||
* @param test_size 测试数据大小(字节)
|
|
||||||
* @return 操作结果
|
|
||||||
*/
|
|
||||||
ret_code_t sdram_self_test(sdram_handle_t *handle, uint32_t test_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取SDRAM基地址
|
|
||||||
* @param device SDRAM设备
|
|
||||||
* @return SDRAM基地址,如果设备无效返回0
|
|
||||||
*/
|
|
||||||
uint32_t sdram_get_base_address(sdram_device_t device);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 默认SDRAM初始化(使用预定义配置)
|
|
||||||
* @return 操作结果
|
|
||||||
*/
|
|
||||||
ret_code_t sdram_default_init(void);
|
|
||||||
|
|
||||||
#endif /* __SDRAM_DRIVER_H__ */
|
|
||||||
@@ -1,6 +1,27 @@
|
|||||||
#include "sdram_manager.h"
|
#include "sdram_manager.h"
|
||||||
#include <cstdio>
|
#include "exmc_driver.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "systick.h"
|
||||||
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
#define SDRAM_DEVICE0_BASE_ADDR ((uint32_t)0xC0000000)
|
||||||
|
#define SDRAM_DEVICE1_BASE_ADDR ((uint32_t)0xD0000000)
|
||||||
|
|
||||||
|
#define SDRAM_TIMEOUT ((uint32_t)0x0000FFFF)
|
||||||
|
|
||||||
SdramManager &SdramManager::instance()
|
SdramManager &SdramManager::instance()
|
||||||
{
|
{
|
||||||
@@ -9,31 +30,200 @@ SdramManager &SdramManager::instance()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SdramManager::SdramManager()
|
SdramManager::SdramManager()
|
||||||
: handle_{
|
: config_{
|
||||||
.device = SDRAM_DEVICE_0,
|
.column_address_width = EXMC_SDRAM_COW_ADDRESS_9,
|
||||||
.config = {
|
.row_address_width = EXMC_SDRAM_ROW_ADDRESS_13,
|
||||||
.column_address_width = EXMC_SDRAM_COW_ADDRESS_9,
|
.data_width = EXMC_SDRAM_DATABUS_WIDTH_16B,
|
||||||
.row_address_width = EXMC_SDRAM_ROW_ADDRESS_13,
|
.internal_bank_number = EXMC_SDRAM_4_INTER_BANK,
|
||||||
.data_width = EXMC_SDRAM_DATABUS_WIDTH_16B,
|
.cas_latency = EXMC_CAS_LATENCY_3_SDCLK,
|
||||||
.internal_bank_number = EXMC_SDRAM_4_INTER_BANK,
|
.write_protection = false,
|
||||||
.cas_latency = EXMC_CAS_LATENCY_3_SDCLK,
|
.sdclock_config = EXMC_SDCLK_PERIODS_3_HCLK,
|
||||||
.write_protection = false,
|
.burst_read_switch = true,
|
||||||
.sdclock_config = EXMC_SDCLK_PERIODS_3_HCLK,
|
.pipeline_read_delay = EXMC_PIPELINE_DELAY_1_HCLK,
|
||||||
.burst_read_switch = true,
|
.timing = {
|
||||||
.pipeline_read_delay = EXMC_PIPELINE_DELAY_2_HCLK,
|
.load_mode_register_delay = 2,
|
||||||
.timing = {
|
.exit_selfrefresh_delay = 7,
|
||||||
.load_mode_register_delay = 2,
|
.row_address_select_delay = 5,
|
||||||
.exit_selfrefresh_delay = 7,
|
.auto_refresh_delay = 6,
|
||||||
.row_address_select_delay = 5,
|
.write_recovery_delay = 2,
|
||||||
.auto_refresh_delay = 6,
|
.row_precharge_delay = 2,
|
||||||
.write_recovery_delay = 2,
|
.row_to_column_delay = 2,
|
||||||
.row_precharge_delay = 2,
|
}},
|
||||||
.row_to_column_delay = 2,
|
base_addr_(SDRAM_DEVICE0_BASE_ADDR)
|
||||||
}},
|
|
||||||
.private_data = nullptr}
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t SdramManager::base_address() const
|
||||||
|
{
|
||||||
|
return base_addr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SdramManager::getExmcDevice() const
|
||||||
|
{
|
||||||
|
switch (device_)
|
||||||
|
{
|
||||||
|
case DEVICE_0:
|
||||||
|
return EXMC_SDRAM_DEVICE0;
|
||||||
|
case DEVICE_1:
|
||||||
|
return EXMC_SDRAM_DEVICE1;
|
||||||
|
default:
|
||||||
|
return EXMC_SDRAM_DEVICE0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SdramManager::getExmcBankSelect() const
|
||||||
|
{
|
||||||
|
switch (device_)
|
||||||
|
{
|
||||||
|
case DEVICE_0:
|
||||||
|
return EXMC_SDRAM_DEVICE0_SELECT;
|
||||||
|
case DEVICE_1:
|
||||||
|
return EXMC_SDRAM_DEVICE1_SELECT;
|
||||||
|
default:
|
||||||
|
return EXMC_SDRAM_DEVICE0_SELECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RetCode SdramManager::executeInitSequence(uint32_t exmc_device, uint32_t bank_select)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
printf("[SDRAM] 执行EXMC SDRAM初始化...\r\n");
|
||||||
|
exmc_sdram_init(&sdram_init_struct);
|
||||||
|
printf("[SDRAM] EXMC SDRAM初始化完成\r\n");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
delay_1ms(10);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
exmc_sdram_refresh_count_set(418);
|
||||||
|
|
||||||
|
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_readsample_enable(ENABLE);
|
||||||
|
exmc_sdram_readsample_config(EXMC_SDRAM_4_DELAY_CELL, EXMC_SDRAM_READSAMPLE_0_EXTRAHCLK);
|
||||||
|
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
RetCode SdramManager::init()
|
RetCode SdramManager::init()
|
||||||
{
|
{
|
||||||
if (initialized_)
|
if (initialized_)
|
||||||
@@ -42,49 +232,332 @@ RetCode SdramManager::init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("[SdramManager] Initializing...\r\n");
|
printf("[SdramManager] Initializing...\r\n");
|
||||||
RetCode ret = sdram_init(&handle_);
|
|
||||||
if (ret == RET_OK)
|
printf("[SDRAM] 开始初始化设备 %d\r\n", device_);
|
||||||
|
|
||||||
|
switch (device_)
|
||||||
{
|
{
|
||||||
initialized_ = true;
|
case DEVICE_0:
|
||||||
printf("[SdramManager] Init OK, base=0x%08lX\r\n", base_address());
|
base_addr_ = SDRAM_DEVICE0_BASE_ADDR;
|
||||||
|
printf("[SDRAM] 使用设备0,基地址: 0x%08lX\r\n", base_addr_);
|
||||||
|
break;
|
||||||
|
case DEVICE_1:
|
||||||
|
base_addr_ = SDRAM_DEVICE1_BASE_ADDR;
|
||||||
|
printf("[SDRAM] 使用设备1,基地址: 0x%08lX\r\n", base_addr_);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("[SDRAM] 初始化失败: 无效设备 %d\r\n", device_);
|
||||||
|
return RET_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
printf("[SDRAM] 配置信息:\r\n");
|
||||||
|
printf(" 列地址宽度: %d\r\n", config_.column_address_width == EXMC_SDRAM_COW_ADDRESS_9 ? 9 : 8);
|
||||||
|
printf(" 行地址宽度: %d\r\n", config_.row_address_width == EXMC_SDRAM_ROW_ADDRESS_13 ? 13 : 12);
|
||||||
|
printf(" 数据宽度: %d位\r\n", config_.data_width == EXMC_SDRAM_DATABUS_WIDTH_16B ? 16 : (config_.data_width == EXMC_SDRAM_DATABUS_WIDTH_8B ? 8 : 32));
|
||||||
|
printf(" 内部Bank数: %d\r\n", config_.internal_bank_number == EXMC_SDRAM_4_INTER_BANK ? 4 : 2);
|
||||||
|
printf(" CAS延迟: %d个时钟\r\n", config_.cas_latency == EXMC_CAS_LATENCY_3_SDCLK ? 3 : 2);
|
||||||
|
printf(" 写保护: %s\r\n", config_.write_protection ? "启用" : "禁用");
|
||||||
|
printf(" SDCLK配置: HCLK/%d\r\n", config_.sdclock_config == EXMC_SDCLK_PERIODS_3_HCLK ? 3 : 2);
|
||||||
|
|
||||||
|
ExmcBus &exmc_bus = ExmcBus::instance();
|
||||||
|
exmc_bus.init();
|
||||||
|
ExmcBus::sdram_pin_init();
|
||||||
|
printf("[SDRAM] EXMC总线初始化完成\r\n");
|
||||||
|
|
||||||
|
uint32_t exmc_device = getExmcDevice();
|
||||||
|
uint32_t bank_select = getExmcBankSelect();
|
||||||
|
printf("[SDRAM] EXMC设备: 0x%08lX, Bank选择: 0x%08lX\r\n", exmc_device, bank_select);
|
||||||
|
|
||||||
|
printf("[SDRAM] 开始执行初始化序列...\r\n");
|
||||||
|
RetCode ret = executeInitSequence(exmc_device, bank_select);
|
||||||
|
if (ret != RET_OK)
|
||||||
{
|
{
|
||||||
printf("[SdramManager] Init failed: %d\r\n", ret);
|
printf("[SDRAM] 初始化序列失败: 错误码=%d\r\n", ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
|
initialized_ = true;
|
||||||
|
|
||||||
|
printf("[SDRAM] 初始化成功完成\r\n");
|
||||||
|
printf("[SdramManager] Init OK, base=0x%08lX\r\n", base_addr_);
|
||||||
|
|
||||||
|
return RET_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
RetCode SdramManager::write(uint32_t offset, const void *data, uint32_t length)
|
RetCode SdramManager::write(uint32_t offset, const void *data, uint32_t length)
|
||||||
{
|
{
|
||||||
if (!initialized_)
|
if (!initialized_)
|
||||||
|
{
|
||||||
return RET_NOT_INITIALIZED;
|
return RET_NOT_INITIALIZED;
|
||||||
return sdram_write(&handle_, offset, data, length);
|
}
|
||||||
|
|
||||||
|
if (data == NULL || length == 0)
|
||||||
|
{
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mem_addr = base_addr_ + offset;
|
||||||
|
|
||||||
|
if (length > 1)
|
||||||
|
{
|
||||||
|
printf("[SDRAM] 写入: 地址=0x%08lX, 长度=%lu, 数据宽度=%d位\r\n",
|
||||||
|
mem_addr, length,
|
||||||
|
(config_.data_width == EXMC_SDRAM_DATABUS_WIDTH_8B) ? 8 : (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 (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 (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 (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;
|
||||||
}
|
}
|
||||||
|
|
||||||
RetCode SdramManager::read(uint32_t offset, void *buffer, uint32_t length)
|
RetCode SdramManager::read(uint32_t offset, void *buffer, uint32_t length)
|
||||||
{
|
{
|
||||||
if (!initialized_)
|
if (!initialized_)
|
||||||
|
{
|
||||||
return RET_NOT_INITIALIZED;
|
return RET_NOT_INITIALIZED;
|
||||||
return sdram_read(&handle_, offset, buffer, length);
|
}
|
||||||
|
|
||||||
|
if (buffer == NULL || length == 0)
|
||||||
|
{
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mem_addr = base_addr_ + offset;
|
||||||
|
|
||||||
|
if (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 (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 (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;
|
||||||
}
|
}
|
||||||
|
|
||||||
RetCode SdramManager::fill(uint32_t offset, uint8_t value, uint32_t length)
|
RetCode SdramManager::fill(uint32_t offset, uint8_t value, uint32_t length)
|
||||||
{
|
{
|
||||||
if (!initialized_)
|
if (!initialized_)
|
||||||
|
{
|
||||||
return RET_NOT_INITIALIZED;
|
return RET_NOT_INITIALIZED;
|
||||||
return sdram_fill(&handle_, offset, value, length);
|
}
|
||||||
|
|
||||||
|
if (length == 0)
|
||||||
|
{
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mem_addr = base_addr_ + offset;
|
||||||
|
|
||||||
|
if (config_.data_width == EXMC_SDRAM_DATABUS_WIDTH_8B)
|
||||||
|
{
|
||||||
|
uint8_t *dst = (uint8_t *)mem_addr;
|
||||||
|
for (uint32_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
dst[i] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (config_.data_width == EXMC_SDRAM_DATABUS_WIDTH_16B)
|
||||||
|
{
|
||||||
|
uint16_t word_value = (value << 8) | value;
|
||||||
|
uint8_t *dst8 = (uint8_t *)mem_addr;
|
||||||
|
uint16_t *dst16;
|
||||||
|
|
||||||
|
if ((offset & 0x1) != 0)
|
||||||
|
{
|
||||||
|
dst8[0] = value;
|
||||||
|
dst8++;
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (config_.data_width == EXMC_SDRAM_DATABUS_WIDTH_32B)
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
RetCode SdramManager::self_test(uint32_t test_size)
|
RetCode SdramManager::self_test(uint32_t test_size)
|
||||||
{
|
{
|
||||||
if (!initialized_)
|
if (!initialized_)
|
||||||
|
{
|
||||||
return RET_NOT_INITIALIZED;
|
return RET_NOT_INITIALIZED;
|
||||||
printf("[SdramManager] Running self-test (%lu bytes)...\r\n", test_size);
|
}
|
||||||
return sdram_self_test(&handle_, test_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t SdramManager::base_address() const
|
printf("[SdramManager] Running self-test (%lu bytes)...\r\n", test_size);
|
||||||
{
|
|
||||||
return sdram_get_base_address(handle_.device);
|
if (test_size > 1024 * 1024)
|
||||||
|
{
|
||||||
|
test_size = 1024 * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SELF_TEST_BLOCK_SIZE 256
|
||||||
|
|
||||||
|
RetCode 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 = write(offset, write_buf, block_size);
|
||||||
|
if (ret != RET_OK)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = read(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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "common_types.h"
|
#include "common_types.h"
|
||||||
#include "sdram_driver.h"
|
|
||||||
|
|
||||||
class SdramManager {
|
class SdramManager {
|
||||||
public:
|
public:
|
||||||
@@ -24,8 +23,39 @@ private:
|
|||||||
SdramManager(const SdramManager &) = delete;
|
SdramManager(const SdramManager &) = delete;
|
||||||
SdramManager &operator=(const SdramManager &) = delete;
|
SdramManager &operator=(const SdramManager &) = delete;
|
||||||
|
|
||||||
sdram_handle_t handle_;
|
enum Device : uint8_t { DEVICE_0 = 0, DEVICE_1 = 1 };
|
||||||
bool initialized_ = false;
|
|
||||||
|
struct Timing {
|
||||||
|
uint32_t load_mode_register_delay;
|
||||||
|
uint32_t exit_selfrefresh_delay;
|
||||||
|
uint32_t row_address_select_delay;
|
||||||
|
uint32_t auto_refresh_delay;
|
||||||
|
uint32_t write_recovery_delay;
|
||||||
|
uint32_t row_precharge_delay;
|
||||||
|
uint32_t row_to_column_delay;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Config {
|
||||||
|
uint32_t column_address_width;
|
||||||
|
uint32_t row_address_width;
|
||||||
|
uint32_t data_width;
|
||||||
|
uint32_t internal_bank_number;
|
||||||
|
uint32_t cas_latency;
|
||||||
|
bool write_protection;
|
||||||
|
uint32_t sdclock_config;
|
||||||
|
bool burst_read_switch;
|
||||||
|
uint32_t pipeline_read_delay;
|
||||||
|
Timing timing;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t getExmcDevice() const;
|
||||||
|
uint32_t getExmcBankSelect() const;
|
||||||
|
RetCode executeInitSequence(uint32_t exmc_device, uint32_t bank_select);
|
||||||
|
|
||||||
|
Device device_{DEVICE_0};
|
||||||
|
Config config_;
|
||||||
|
uint32_t base_addr_;
|
||||||
|
bool initialized_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user