fc10ef2e10
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
793 lines
24 KiB
C++
793 lines
24 KiB
C++
#include "gd32f4xx.h"
|
|
#include "systick.h"
|
|
#include "lcd.h"
|
|
#include "../bsp/device/led/led_driver.h"
|
|
#include "../drv/uart/uart_driver.h"
|
|
#include "../bsp/device/sdram/sdram_driver.h"
|
|
#include "../bsp/device/flash/flash_driver.h"
|
|
#include "../bsp/hardware_init.h"
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
extern _lcd_dev lcddev;
|
|
|
|
__attribute__((section(".sdram"))) uint8_t sdram_framebuffer[800 * 480 * 3];
|
|
|
|
__attribute__((section(".sdram"))) uint16_t sdram_audio_buffer[65536];
|
|
|
|
__attribute__((section(".sdram"))) uint8_t sdram_big_buffer[1024 * 1024];
|
|
|
|
__attribute__((section(".sdram"))) struct
|
|
{
|
|
uint32_t header;
|
|
uint8_t data[1024 * 64];
|
|
} sdram_packet_pool;
|
|
|
|
static void uart_send_string(const char *str)
|
|
{
|
|
while (*str)
|
|
{
|
|
fputc(*str, stdout);
|
|
str++;
|
|
}
|
|
}
|
|
|
|
static void software_delay_ms(uint32_t ms)
|
|
{
|
|
for (volatile uint32_t i = 0; i < ms * 8000; i++)
|
|
;
|
|
}
|
|
|
|
static void demo_sdram_variable_usage(void)
|
|
{
|
|
printf("\r\n");
|
|
printf("========================================\r\n");
|
|
printf(" SDRAM 变量直接访问演示 (像内置RAM一样)\r\n");
|
|
printf("========================================\r\n");
|
|
|
|
printf("[演示1] 像普通数组一样直接赋值和读取:\r\n");
|
|
sdram_big_buffer[0] = 0x12;
|
|
sdram_big_buffer[1] = 0x34;
|
|
sdram_big_buffer[2] = 0x56;
|
|
sdram_big_buffer[3] = 0x78;
|
|
printf(" sdram_big_buffer[0..3] = 0x%02X 0x%02X 0x%02X 0x%02X\r\n",
|
|
sdram_big_buffer[0], sdram_big_buffer[1],
|
|
sdram_big_buffer[2], sdram_big_buffer[3]);
|
|
|
|
printf("[演示2] 使用memset/memcpy标准库函数:\r\n");
|
|
memset(sdram_framebuffer, 0x00, sizeof(sdram_framebuffer));
|
|
sdram_framebuffer[0] = 0xFF;
|
|
sdram_framebuffer[799] = 0xAA;
|
|
printf(" 帧缓冲首字节=0x%02X 末字节=0x%02X (总大小=%lu 字节)\r\n",
|
|
sdram_framebuffer[0], sdram_framebuffer[799],
|
|
(unsigned long)sizeof(sdram_framebuffer));
|
|
|
|
printf("[演示3] 结构体操作:\r\n");
|
|
sdram_packet_pool.header = 0xA5A5A5A5;
|
|
for (int i = 0; i < 5; i++)
|
|
sdram_packet_pool.data[i] = 0x10 + i;
|
|
printf(" header=0x%08lX data[0..4]=0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\r\n",
|
|
sdram_packet_pool.header,
|
|
sdram_packet_pool.data[0], sdram_packet_pool.data[1],
|
|
sdram_packet_pool.data[2], sdram_packet_pool.data[3],
|
|
sdram_packet_pool.data[4]);
|
|
|
|
printf("[演示4] 通过不同类型指针读写:\r\n");
|
|
uint32_t *ptr32 = (uint32_t *)&sdram_big_buffer[0];
|
|
ptr32[0] = 0xDEADBEEF;
|
|
ptr32[1] = 0xCAFEBABE;
|
|
printf(" 以 uint32_t 指针写入后: [0]=0x%08lX [1]=0x%08lX\r\n",
|
|
ptr32[0], ptr32[1]);
|
|
|
|
printf("[演示5] 地址验证 (变量是否在SDRAM地址范围 0xC0000000+):\r\n");
|
|
printf(" sdram_framebuffer = 0x%08lX\r\n", (unsigned long)sdram_framebuffer);
|
|
printf(" sdram_audio_buffer = 0x%08lX\r\n", (unsigned long)sdram_audio_buffer);
|
|
printf(" sdram_big_buffer = 0x%08lX\r\n", (unsigned long)sdram_big_buffer);
|
|
printf(" sdram_packet_pool = 0x%08lX\r\n", (unsigned long)&sdram_packet_pool);
|
|
printf(" 所有变量地址均在 SDRAM 范围内 √\r\n");
|
|
|
|
printf("[演示6] 与驱动API读写同一地址,数据一致:\r\n");
|
|
sdram_big_buffer[100] = 0x7F;
|
|
printf(" 直接赋值: sdram_big_buffer[100] = 0x%02X\r\n", sdram_big_buffer[100]);
|
|
|
|
printf("========================================\r\n");
|
|
printf(" 总结: 像内置RAM一样声明和使用SDRAM变量√\r\n");
|
|
printf(" 用法: __attribute__((section(\".sdram\"))) 类型 变量名;\r\n");
|
|
printf("========================================\r\n");
|
|
printf("\r\n");
|
|
}
|
|
|
|
static void test_sdram_driver(void)
|
|
{
|
|
printf("SDRAM驱动测试开始...\r\n");
|
|
printf("SDRAM型号: W9825G6KH-6I (32Mx16位, 64MB, CAS延迟6)\r\n");
|
|
printf("注意: GD32 EXMC控制器支持CAS延迟2或3,使用CAS延迟3进行测试\r\n");
|
|
|
|
sdram_handle_t sdram_handle = {
|
|
.device = SDRAM_DEVICE_0,
|
|
.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 = false,
|
|
.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,
|
|
}},
|
|
.private_data = NULL};
|
|
|
|
ret_code_t ret = sdram_init(&sdram_handle);
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" SDRAM初始化失败: 错误码=%d\r\n", ret);
|
|
if (ret == RET_TIMEOUT)
|
|
{
|
|
printf(" 错误类型: 初始化超时\r\n");
|
|
}
|
|
return;
|
|
}
|
|
printf(" SDRAM初始化成功\r\n");
|
|
printf(" SDRAM配置: 数据宽度=%d位, CAS延迟=%d, 时钟分频=HCLK/%d\r\n",
|
|
(sdram_handle.config.data_width == EXMC_SDRAM_DATABUS_WIDTH_16B) ? 16 : (sdram_handle.config.data_width == EXMC_SDRAM_DATABUS_WIDTH_32B) ? 32
|
|
: 8,
|
|
(sdram_handle.config.cas_latency == EXMC_CAS_LATENCY_3_SDCLK) ? 3 : (sdram_handle.config.cas_latency == EXMC_CAS_LATENCY_2_SDCLK) ? 2
|
|
: 1,
|
|
(sdram_handle.config.sdclock_config == EXMC_SDCLK_PERIODS_3_HCLK) ? 3 : 2);
|
|
|
|
printf(" 开始SDRAM读写测试...\r\n");
|
|
|
|
uint8_t write_buffer[256];
|
|
uint8_t read_buffer[256];
|
|
uint8_t zero_buffer[256];
|
|
uint8_t ff_buffer[256];
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
write_buffer[i] = (uint8_t)(i & 0xFF);
|
|
}
|
|
|
|
memset(zero_buffer, 0x00, sizeof(zero_buffer));
|
|
memset(ff_buffer, 0xFF, sizeof(ff_buffer));
|
|
|
|
printf(" 测试数据生成完成,前16字节: ");
|
|
for (int i = 0; i < 16 && i < sizeof(write_buffer); i++)
|
|
{
|
|
printf("%02X ", write_buffer[i]);
|
|
}
|
|
printf("\r\n");
|
|
|
|
printf(" 步骤1: 测试地址0x00000000的单字节访问...\r\n");
|
|
uint8_t test_byte = 0x55;
|
|
uint8_t verify_byte;
|
|
ret = sdram_write(&sdram_handle, 0, &test_byte, 1);
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" 地址0x00000000单字节写入失败: 错误码=%d\r\n", ret);
|
|
}
|
|
else
|
|
{
|
|
ret = sdram_read(&sdram_handle, 0, &verify_byte, 1);
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" 地址0x00000000单字节读取失败: 错误码=%d\r\n", ret);
|
|
}
|
|
else
|
|
{
|
|
printf(" 地址0x00000000单字节测试: 写入=0x%02X, 读取=0x%02X %s\r\n",
|
|
test_byte, verify_byte, (verify_byte == test_byte) ? "(成功)" : "(失败)");
|
|
}
|
|
}
|
|
|
|
printf(" 步骤2: 写入256字节到SDRAM地址 0x1000...\r\n");
|
|
ret = sdram_write(&sdram_handle, 0x1000, write_buffer, sizeof(write_buffer));
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" SDRAM写入失败: 错误码=%d\r\n", ret);
|
|
if (ret == RET_NOT_INITIALIZED)
|
|
printf(" 错误类型: SDRAM未初始化\r\n");
|
|
else if (ret == RET_INVALID_PARAM)
|
|
printf(" 错误类型: 无效参数\r\n");
|
|
else if (ret == RET_TIMEOUT)
|
|
printf(" 错误类型: 操作超时\r\n");
|
|
sdram_deinit(&sdram_handle);
|
|
return;
|
|
}
|
|
printf(" SDRAM写入成功\r\n");
|
|
|
|
printf(" 步骤3: 从SDRAM地址 0x1000 读取256字节...\r\n");
|
|
ret = sdram_read(&sdram_handle, 0x1000, read_buffer, sizeof(read_buffer));
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" SDRAM读取失败: 错误码=%d\r\n", ret);
|
|
sdram_deinit(&sdram_handle);
|
|
return;
|
|
}
|
|
printf(" SDRAM读取成功\r\n");
|
|
|
|
printf(" 读取到的前16字节: ");
|
|
for (int i = 0; i < 16 && i < sizeof(read_buffer); i++)
|
|
{
|
|
printf("%02X ", read_buffer[i]);
|
|
}
|
|
printf("\r\n");
|
|
|
|
printf(" 步骤4: 数据验证...\r\n");
|
|
bool verify_ok = true;
|
|
int first_error_index = -1;
|
|
uint8_t expected_value = 0, actual_value = 0;
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
if (read_buffer[i] != write_buffer[i])
|
|
{
|
|
verify_ok = false;
|
|
first_error_index = i;
|
|
expected_value = write_buffer[i];
|
|
actual_value = read_buffer[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!verify_ok)
|
|
{
|
|
printf(" 数据验证失败 @ 索引 %d: 期望=0x%02X, 实际=0x%02X\r\n",
|
|
first_error_index, expected_value, actual_value);
|
|
|
|
bool all_zero = true;
|
|
bool all_ff = true;
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
if (read_buffer[i] != 0x00)
|
|
all_zero = false;
|
|
if (read_buffer[i] != 0xFF)
|
|
all_ff = false;
|
|
if (!all_zero && !all_ff)
|
|
break;
|
|
}
|
|
|
|
if (all_zero)
|
|
{
|
|
printf(" 警告: 读取到的数据全为0x00 (可能写入未生效)\r\n");
|
|
}
|
|
else if (all_ff)
|
|
{
|
|
printf(" 警告: 读取到的数据全为0xFF (可能SDRAM未初始化或访问失败)\r\n");
|
|
}
|
|
|
|
printf(" 错误位置附近数据 (索引 %d-%d):\r\n",
|
|
(first_error_index > 8) ? first_error_index - 8 : 0,
|
|
(first_error_index < 248) ? first_error_index + 8 : 255);
|
|
printf(" 索引: ");
|
|
for (int i = (first_error_index > 8) ? first_error_index - 8 : 0;
|
|
i <= ((first_error_index < 248) ? first_error_index + 8 : 255); i++)
|
|
{
|
|
printf("%3d ", i);
|
|
}
|
|
printf("\r\n");
|
|
printf(" 期望: ");
|
|
for (int i = (first_error_index > 8) ? first_error_index - 8 : 0;
|
|
i <= ((first_error_index < 248) ? first_error_index + 8 : 255); i++)
|
|
{
|
|
printf("%02X ", write_buffer[i]);
|
|
}
|
|
printf("\r\n");
|
|
printf(" 实际: ");
|
|
for (int i = (first_error_index > 8) ? first_error_index - 8 : 0;
|
|
i <= ((first_error_index < 248) ? first_error_index + 8 : 255); i++)
|
|
{
|
|
printf("%02X ", read_buffer[i]);
|
|
}
|
|
printf("\r\n");
|
|
}
|
|
else
|
|
{
|
|
printf(" SDRAM数据验证成功 (所有256字节匹配)\r\n");
|
|
}
|
|
|
|
printf(" 步骤5: 执行SDRAM自测试 (1KB范围)...\r\n");
|
|
ret = sdram_self_test(&sdram_handle, 1024);
|
|
if (ret == RET_OK)
|
|
{
|
|
printf(" SDRAM自测试通过\r\n");
|
|
}
|
|
else
|
|
{
|
|
printf(" SDRAM自测试失败: 错误码=%d\r\n", ret);
|
|
}
|
|
|
|
printf(" 步骤6: 测试不同地址 (0x2000)...\r\n");
|
|
uint8_t test_value = 0xAA;
|
|
uint8_t verify_value;
|
|
ret = sdram_write(&sdram_handle, 0x2000, &test_value, 1);
|
|
if (ret == RET_OK)
|
|
{
|
|
ret = sdram_read(&sdram_handle, 0x2000, &verify_value, 1);
|
|
if (ret == RET_OK)
|
|
{
|
|
if (verify_value == test_value)
|
|
{
|
|
printf(" 地址0x2000测试通过: 写入=0x%02X, 读取=0x%02X\r\n", test_value, verify_value);
|
|
}
|
|
else
|
|
{
|
|
printf(" 地址0x2000测试失败: 写入=0x%02X, 读取=0x%02X\r\n", test_value, verify_value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf(" 地址0x2000读取失败: %d\r\n", ret);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf(" 地址0x2000写入失败: %d\r\n", ret);
|
|
}
|
|
|
|
demo_sdram_variable_usage();
|
|
|
|
printf(" 反初始化SDRAM...\r\n");
|
|
sdram_deinit(&sdram_handle);
|
|
printf("SDRAM驱动测试完成\r\n");
|
|
}
|
|
|
|
static void test_flash_driver(void)
|
|
{
|
|
printf("Flash驱动测试开始...\r\n");
|
|
|
|
flash_handle_t flash_handle = {
|
|
.type = FLASH_TYPE_INTERNAL,
|
|
.config = {
|
|
.type = FLASH_TYPE_INTERNAL,
|
|
.base_address = flash_get_internal_base_address(),
|
|
.clock_freq = 0,
|
|
.cs_pin = 0,
|
|
.spi_port = 0,
|
|
.exmc_bank = 0},
|
|
.info = {.total_size = flash_get_internal_total_size(), .sector_size = flash_get_internal_sector_size(), .page_size = 256, .block_size = 64 * 1024, .manufacturer_id = 0x20, .device_id = 0x470},
|
|
.initialized = false,
|
|
.private_data = NULL};
|
|
|
|
ret_code_t ret = flash_init(&flash_handle);
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" Flash初始化失败: %d\r\n", ret);
|
|
return;
|
|
}
|
|
printf(" Flash初始化成功\r\n");
|
|
|
|
flash_info_t flash_info;
|
|
ret = flash_get_info(&flash_handle, &flash_info);
|
|
if (ret == RET_OK)
|
|
{
|
|
printf(" Flash信息: 总大小=%lu KB, 扇区大小=%lu KB\r\n",
|
|
flash_info.total_size / 1024, flash_info.sector_size / 1024);
|
|
}
|
|
|
|
uint32_t test_address = flash_get_internal_base_address() +
|
|
flash_get_internal_total_size() -
|
|
flash_get_internal_sector_size();
|
|
|
|
printf(" 测试地址: 0x%08lX\r\n", test_address);
|
|
|
|
uint8_t write_buffer[256];
|
|
uint8_t read_buffer[256];
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
write_buffer[i] = (uint8_t)((i + 0x80) & 0xFF);
|
|
}
|
|
|
|
printf(" 擦除Flash扇区...\r\n");
|
|
printf(" 扇区地址: 0x%08lX, 扇区大小: %lu 字节\r\n",
|
|
test_address, flash_get_internal_sector_size());
|
|
ret = flash_erase(&flash_handle, test_address, flash_get_internal_sector_size());
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" Flash擦除失败: 错误码=%d\r\n", ret);
|
|
if (ret == RET_TIMEOUT)
|
|
{
|
|
printf(" 错误类型: 操作超时\r\n");
|
|
}
|
|
else if (ret == RET_ERROR)
|
|
{
|
|
printf(" 错误类型: Flash操作错误\r\n");
|
|
}
|
|
flash_deinit(&flash_handle);
|
|
return;
|
|
}
|
|
printf(" Flash擦除成功\r\n");
|
|
|
|
printf(" 写入Flash数据...\r\n");
|
|
ret = flash_write(&flash_handle, test_address, write_buffer, sizeof(write_buffer));
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" Flash写入失败: %d\r\n", ret);
|
|
flash_deinit(&flash_handle);
|
|
return;
|
|
}
|
|
printf(" Flash写入成功\r\n");
|
|
|
|
printf(" 读取Flash数据...\r\n");
|
|
ret = flash_read(&flash_handle, test_address, read_buffer, sizeof(read_buffer));
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" Flash读取失败: %d\r\n", ret);
|
|
flash_deinit(&flash_handle);
|
|
return;
|
|
}
|
|
printf(" Flash读取成功\r\n");
|
|
|
|
bool verify_ok = true;
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
if (read_buffer[i] != write_buffer[i])
|
|
{
|
|
verify_ok = false;
|
|
printf(" 数据验证失败 @ %d: 写入=%02X, 读取=%02X\r\n",
|
|
i, write_buffer[i], read_buffer[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (verify_ok)
|
|
{
|
|
printf(" Flash数据验证成功\r\n");
|
|
}
|
|
|
|
ret = flash_self_test(&flash_handle, 256);
|
|
if (ret == RET_OK)
|
|
{
|
|
printf(" Flash自测试通过\r\n");
|
|
}
|
|
else
|
|
{
|
|
printf(" Flash自测试失败: %d\r\n", ret);
|
|
}
|
|
|
|
flash_deinit(&flash_handle);
|
|
printf("Flash驱动测试完成\r\n");
|
|
}
|
|
|
|
static void test_external_spi_flash(void)
|
|
{
|
|
printf("外部SPI Flash驱动测试开始...\r\n");
|
|
|
|
ret_code_t ret = flash_external_spi_default_init();
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" 外部SPI Flash初始化失败: %d\r\n", ret);
|
|
return;
|
|
}
|
|
printf(" 外部SPI Flash初始化成功\r\n");
|
|
|
|
flash_handle_t *flash_handle = flash_get_external_spi_handle();
|
|
if (flash_handle == NULL)
|
|
{
|
|
printf(" 获取外部SPI Flash句柄失败\r\n");
|
|
return;
|
|
}
|
|
|
|
printf(" 制造商ID: 0x%02lX\r\n", flash_handle->info.manufacturer_id);
|
|
printf(" 设备ID: 0x%04lX\r\n", flash_handle->info.device_id);
|
|
printf(" 总容量: %lu KB\r\n", flash_handle->info.total_size / 1024);
|
|
printf(" 扇区大小: %lu KB\r\n", flash_handle->info.sector_size / 1024);
|
|
printf(" 页大小: %lu 字节\r\n", flash_handle->info.page_size);
|
|
|
|
uint8_t read_buffer[256];
|
|
ret = flash_read(flash_handle, 0, read_buffer, sizeof(read_buffer));
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" 读取测试失败: %d\r\n", ret);
|
|
}
|
|
else
|
|
{
|
|
printf(" 读取测试成功(读取前256字节)\r\n");
|
|
printf(" 前16字节内容: ");
|
|
for (int i = 0; i < 16 && i < sizeof(read_buffer); i++)
|
|
{
|
|
printf("%02X ", read_buffer[i]);
|
|
}
|
|
printf("\r\n");
|
|
}
|
|
|
|
printf("\r\n");
|
|
printf(" 开始完整功能测试(写入/擦除/验证)...\r\n");
|
|
|
|
uint32_t status;
|
|
ret = flash_read_status(flash_handle, &status);
|
|
if (ret == RET_OK)
|
|
{
|
|
printf(" 当前状态寄存器: 0x%02lX\r\n", status);
|
|
printf(" 状态位: BUSY=%d, WEL=%d, BP0=%d, BP1=%d, BP2=%d, BP3=%d, SRWD=%d\r\n",
|
|
(int)((status >> 0) & 1), (int)((status >> 1) & 1), (int)((status >> 2) & 1),
|
|
(int)((status >> 3) & 1), (int)((status >> 4) & 1), (int)((status >> 5) & 1),
|
|
(int)((status >> 7) & 1));
|
|
}
|
|
|
|
printf(" 选择测试扇区: 最后一个4KB扇区 (避免破坏现有数据)\r\n");
|
|
uint32_t test_sector = flash_handle->info.total_size - flash_handle->info.sector_size;
|
|
printf(" 测试地址: 0x%08lX\r\n", test_sector);
|
|
|
|
uint8_t sector_buffer[256];
|
|
ret = flash_read(flash_handle, test_sector, sector_buffer, sizeof(sector_buffer));
|
|
if (ret == RET_OK)
|
|
{
|
|
printf(" 测试扇区前16字节: ");
|
|
for (int i = 0; i < 16; i++)
|
|
printf("%02X ", sector_buffer[i]);
|
|
printf("\r\n");
|
|
}
|
|
|
|
printf(" 擦除测试扇区...\r\n");
|
|
ret = flash_erase(flash_handle, test_sector, flash_handle->info.sector_size);
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" 擦除失败: %d\r\n", ret);
|
|
flash_deinit(flash_handle);
|
|
return;
|
|
}
|
|
printf(" 擦除成功\r\n");
|
|
|
|
bool erase_ok = false;
|
|
uint8_t verify_erase_buf[16];
|
|
ret = flash_read(flash_handle, test_sector, verify_erase_buf, sizeof(verify_erase_buf));
|
|
if (ret == RET_OK)
|
|
{
|
|
erase_ok = true;
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
if (verify_erase_buf[i] != 0xFF)
|
|
{
|
|
erase_ok = false;
|
|
break;
|
|
}
|
|
}
|
|
printf(" 擦除验证: %s\r\n", erase_ok ? "通过" : "失败");
|
|
}
|
|
|
|
uint8_t test_data[256];
|
|
for (int i = 0; i < 256; i++)
|
|
test_data[i] = (uint8_t)(i ^ 0x55);
|
|
|
|
printf(" 写入测试数据 (256字节, 模式: i ^ 0x55)...\r\n");
|
|
ret = flash_write(flash_handle, test_sector, test_data, sizeof(test_data));
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" 写入失败: %d\r\n", ret);
|
|
flash_deinit(flash_handle);
|
|
return;
|
|
}
|
|
printf(" 写入成功\r\n");
|
|
|
|
uint8_t verify_buf[256];
|
|
ret = flash_read(flash_handle, test_sector, verify_buf, sizeof(verify_buf));
|
|
if (ret != RET_OK)
|
|
{
|
|
printf(" 读取验证失败: %d\r\n", ret);
|
|
flash_deinit(flash_handle);
|
|
return;
|
|
}
|
|
|
|
bool write_verified = true;
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
if (verify_buf[i] != test_data[i])
|
|
{
|
|
write_verified = false;
|
|
printf(" 数据不匹配 @ 字节 %d: 期望=0x%02X, 实际=0x%02X\r\n", i, test_data[i], verify_buf[i]);
|
|
if (i >= 10)
|
|
{
|
|
printf(" (显示前10个错误后停止)\r\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (write_verified)
|
|
{
|
|
printf(" 写入验证: 通过 (所有256字节匹配)\r\n");
|
|
}
|
|
|
|
printf(" 测试跨页写入 (256+128=384字节)...\r\n");
|
|
uint8_t cross_page_data[384];
|
|
for (int i = 0; i < 384; i++)
|
|
cross_page_data[i] = (uint8_t)(i & 0xFF);
|
|
|
|
ret = flash_write(flash_handle, test_sector + 256, cross_page_data, sizeof(cross_page_data));
|
|
if (ret == RET_OK)
|
|
{
|
|
printf(" 跨页写入成功\r\n");
|
|
}
|
|
else
|
|
{
|
|
printf(" 跨页写入失败: %d (此错误在某些Flash型号中可能正常)\r\n", ret);
|
|
}
|
|
|
|
printf("\r\n");
|
|
if (erase_ok && write_verified)
|
|
{
|
|
printf(" ? 外部SPI Flash完整功能测试通过!\r\n");
|
|
printf(" 擦除、写入、读取、验证所有功能正常。\r\n");
|
|
}
|
|
else
|
|
{
|
|
printf(" ?? 外部SPI Flash测试部分通过。\r\n");
|
|
printf(" 需要进一步检查问题。\r\n");
|
|
}
|
|
|
|
flash_deinit(flash_handle);
|
|
printf("外部SPI Flash驱动测试完成\r\n");
|
|
}
|
|
|
|
static const char *get_clock_source_str(void)
|
|
{
|
|
uint32_t scs = RCU_CFG0 & RCU_CFG0_SCS;
|
|
if (scs == RCU_SCSS_IRC16M)
|
|
{
|
|
return "IRC16M (内部16MHz)";
|
|
}
|
|
else if (scs == RCU_SCSS_HXTAL)
|
|
{
|
|
return "HXTAL (外部25MHz晶体)";
|
|
}
|
|
else if (scs == RCU_SCSS_PLLP)
|
|
{
|
|
return "PLL (168MHz)";
|
|
}
|
|
else
|
|
{
|
|
return "未知";
|
|
}
|
|
}
|
|
|
|
static const char *get_system_clock_str(void)
|
|
{
|
|
uint32_t scs = RCU_CFG0 & RCU_CFG0_SCS;
|
|
if (scs == RCU_SCSS_IRC16M)
|
|
{
|
|
return "16MHz";
|
|
}
|
|
else if (scs == RCU_SCSS_HXTAL)
|
|
{
|
|
return "25MHz";
|
|
}
|
|
else if (scs == RCU_SCSS_PLLP)
|
|
{
|
|
return "168MHz";
|
|
}
|
|
else
|
|
{
|
|
return "未知频率";
|
|
}
|
|
}
|
|
|
|
static void lcd_display_demo(void)
|
|
{
|
|
printf("LCD初始化...\r\n");
|
|
LCD_Init();
|
|
printf(" LCD ID: %s\r\n", lcd_id);
|
|
printf(" LCD分辨率: %dx%d\r\n", lcddev.width, lcddev.height);
|
|
|
|
printf(" Step 1: 逐步骤诊断测试 (含寄存器读回验证)...\r\n");
|
|
LCD_DiagnosticPattern();
|
|
printf(" [诊断完成, 等待 5 秒观察屏幕]...\r\n");
|
|
delay_1ms(5000);
|
|
|
|
printf(" Step 2: 全屏纯色测试开始\r\n");
|
|
printf(" 全屏 RED...\r\n");
|
|
LCD_Clear(RED);
|
|
delay_1ms(2000);
|
|
|
|
printf(" 全屏 GREEN...\r\n");
|
|
LCD_Clear(GREEN);
|
|
delay_1ms(2000);
|
|
|
|
printf(" 全屏 BLUE...\r\n");
|
|
LCD_Clear(BLUE);
|
|
delay_1ms(2000);
|
|
|
|
printf(" 全屏 WHITE...\r\n");
|
|
LCD_Clear(WHITE);
|
|
delay_1ms(2000);
|
|
|
|
POINT_COLOR = RED;
|
|
BACK_COLOR = WHITE;
|
|
LCD_ShowString(30, 40, 400, 32, 16, 0, (uint8_t *)"LiangShanPi GD32F470");
|
|
LCD_ShowString(30, 70, 400, 32, 16, 0, (uint8_t *)"LCD: NT35510 480x800");
|
|
|
|
POINT_COLOR = BLUE;
|
|
LCD_ShowString(30, 110, 400, 32, 16, 0, lcd_id);
|
|
LCD_ShowString(30, 150, 400, 32, 16, 0, (uint8_t *)"SDRAM + LCD Coexistence OK");
|
|
|
|
POINT_COLOR = BLACK;
|
|
LCD_ShowString(30, 200, 400, 32, 16, 0, (uint8_t *)"System: 168MHz");
|
|
LCD_ShowString(30, 240, 400, 32, 16, 0, (uint8_t *)"Hello World!");
|
|
|
|
POINT_COLOR = RED;
|
|
LCD_DrawRectangle(20, 300, 220, 500);
|
|
POINT_COLOR = GREEN;
|
|
LCD_FillRectangle(30, 310, 210, 490);
|
|
POINT_COLOR = BLUE;
|
|
LCD_DrawCircle(400, 400, 80);
|
|
|
|
printf(" LCD显示演示完成\r\n");
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
hardware_init();
|
|
|
|
LedManager::instance().init_all();
|
|
|
|
{
|
|
UartConfig uart_cfg;
|
|
uart_cfg.baudrate = 9600;
|
|
UartBus::default_instance().init(uart_cfg);
|
|
}
|
|
|
|
systick_config();
|
|
|
|
software_delay_ms(100);
|
|
|
|
printf("系统时钟调试信息:\r\n");
|
|
printf(" 时钟源: %s\r\n", get_clock_source_str());
|
|
printf(" 系统频率: %s\r\n", get_system_clock_str());
|
|
printf(" SystemCoreClock变量: %lu Hz\r\n", SystemCoreClock);
|
|
|
|
uart_send_string("Direct UART test: Hello World!\r\n");
|
|
|
|
printf("printf test: Hello World!\r\n");
|
|
|
|
printf("SysTick测试: 开始1秒延时...\r\n");
|
|
delay_1ms(1000);
|
|
printf("SysTick测试: 1秒延时完成\r\n");
|
|
|
|
printf("SysTick精确延时测试: 开始100ms x 10次延时...\r\n");
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
delay_1ms(100);
|
|
printf(" Tick %d\r\n", i + 1);
|
|
}
|
|
printf("SysTick精确延时测试: 完成\r\n");
|
|
|
|
printf("\r\n");
|
|
// 暂时注释掉 SDRAM 和 SPI Flash,只测试 LCD
|
|
// printf("开始SDRAM驱动测试 (型号: W9825G6KH-6I)...\r\n");
|
|
// printf("\r\n");
|
|
// test_sdram_driver();
|
|
// printf("\r\n");
|
|
// printf("开始外部SPI Flash测试...\r\n");
|
|
// printf("\r\n");
|
|
// test_external_spi_flash();
|
|
// printf("\r\n");
|
|
|
|
printf("开始LCD显示测试...\r\n");
|
|
printf(" 注意:LCD和SDRAM共享EXMC数据总线D0-D15\r\n");
|
|
printf(" LCD使用NOR/PSRAM控制器(NE3/PG12, 地址0x6C000000)\r\n");
|
|
printf(" SDRAM使用SDRAM控制器(SDNE0/PC2, 地址0xC0000000)\r\n");
|
|
printf(" 两个控制器独立工作,互不干扰\r\n");
|
|
printf("\r\n");
|
|
lcd_display_demo();
|
|
printf("LCD显示测试完成\r\n");
|
|
printf("\r\n");
|
|
|
|
printf("进入主循环: LED闪烁\r\n");
|
|
while (1)
|
|
{
|
|
LedManager::instance().led(1).on();
|
|
delay_1ms(500);
|
|
LedManager::instance().led(1).off();
|
|
delay_1ms(500);
|
|
}
|
|
}
|