GD5F 驱动增设 DMA 可达性运行时守卫,非 SRAM 缓冲拒走 DMA 回落轮询

This commit is contained in:
2026-09-21 02:56:54 +08:00
parent bad5ceac0d
commit 45a3d0d06b
+70 -2
View File
@@ -53,6 +53,15 @@ volatile uint8_t g_spi1_dma_done;
* 页级大块传输(2048)仍走 DMA,源/目的全部为文件作用域静态缓冲。 */
#define GD5F_DMA_THRESHOLD 1024
/* DMA 可达内存区间:必须与分散加载文件 RW_IRAM1(0x20000000,128KB,
* SRAM1+SRAM2)一致。CCM(0x10000000,64KB)DMA1/DMA2 物理不可达,
* RW_CCM 区任何缓冲都不得进 DMA。阈值只能挡住"当前已知的小栈缓冲",
* 挡不住"将来新加的 >1024B 栈缓冲";gd5f_dma_buf_ok() 把这条约定
* 升级为运行时强制检查(2026-09-21 加固)。若将来新增其它 DMA 可达
* 内存(如外部 SDRAM),此处区间必须同步扩展。 */
#define GD5F_DMA_RAM_BASE 0x20000000UL
#define GD5F_DMA_RAM_END 0x20020000UL
/*
* 函数功能:SPI1 TX DMA 完成回调(PROGRAM_LOAD 数据发送用)
* 入口参数:hspi - 触发回调的 SPI 句柄 SPI_HandleTypeDef*
@@ -91,6 +100,42 @@ static int gd5f_private_bbt_find_best(void);
static int gd5f_bbt_load(void);
static int gd5f_bbt_save(void);
/* DMA 可达性守卫(见下方实现) */
static int gd5f_dma_buf_ok(const void *p_buf, size_t size);
/* ======================== DMA 可达性守卫 ======================== */
/*
* 函数功能:判定缓冲是否位于 DMA 可达内存(SRAM1+SRAM2)
* 入口参数:p_buf - 传输缓冲首地址 const void*
* size - 传输字节数 size_t
* 返回值:1 - 整段缓冲 DMA 可达;0 - 不可达(调用方须回落 CPU 轮询)
* 限定条件:无
* 函数说明:DMA1/DMA2 物理不可达 CCM(0x10000000)——以 CCM 缓冲做 DMA
* 源/目的会静默不落地(2026-09-20 首轮 CCM 扩容实验实证根因)。
* 本函数把"栈/堆缓冲禁入 DMA"的约定升级为运行时强制约束:
* 起止地址任一越出 SRAM 区间即判不可达。
*/
static int gd5f_dma_buf_ok(const void *p_buf, size_t size) {
uint32_t start = (uint32_t)(uintptr_t)p_buf;
uint32_t end;
if (size == 0U) {
return 0;
}
end = start + (uint32_t)size;
if (end < start) { /* 地址回绕:不可能落在同一区间内 */
return 0;
}
if ((start < GD5F_DMA_RAM_BASE) || (end > GD5F_DMA_RAM_END)) {
return 0;
}
return 1;
}
/* ======================== SPI 原语定义 ======================== */
/*
@@ -223,6 +268,17 @@ int gd5f_page_read(uint32_t page_addr) {
int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf,
size_t size) {
uint8_t cmd[4] = {0};
uint8_t use_dma = 0U;
/* 守卫判定须在 CS 拉低之前完成:DBG_ERROR 走串口,不能占着 CS 窗口 */
if (size > GD5F_DMA_THRESHOLD) {
use_dma = (uint8_t)gd5f_dma_buf_ok(p_buf, size);
if (use_dma == 0U) {
DBG_ERROR("RX DMA buffer not DMA-reachable "
"(p=0x%08lX size=%lu), fallback poll",
(unsigned long)(uintptr_t)p_buf, (unsigned long)size);
}
}
cmd[0] = GD5F_CMD_READ_FROM_CACHE;
cmd[1] = (column >> 8) & 0xFF;
@@ -232,7 +288,7 @@ int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf,
GD5F_CS_LOW();
HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT);
if (size > GD5F_DMA_THRESHOLD) {
if (use_dma != 0U) {
uint32_t tick_start = HAL_GetTick();
g_spi1_dma_done = 0U;
if (HAL_SPI_Receive_DMA(&hspi1, p_buf, (uint16_t)size) != HAL_OK) {
@@ -294,6 +350,18 @@ static int gd5f_page_program(uint32_t page_addr, uint16_t column,
*/
int gd5f_program_load(uint16_t column, const uint8_t *p_buf, size_t size) {
uint8_t cmd[3];
uint8_t use_dma = 0U;
/* 守卫判定须在 CS 拉低之前完成:DBG_ERROR 走串口,不能占着 CS 窗口 */
if (size > GD5F_DMA_THRESHOLD) {
use_dma = (uint8_t)gd5f_dma_buf_ok(p_buf, size);
if (use_dma == 0U) {
DBG_ERROR("TX DMA buffer not DMA-reachable "
"(p=0x%08lX size=%lu), fallback poll",
(unsigned long)(uintptr_t)p_buf, (unsigned long)size);
}
}
cmd[0] = GD5F_CMD_PROGRAM_LOAD;
cmd[1] = (uint8_t)(column >> 8);
cmd[2] = (uint8_t)(column);
@@ -301,7 +369,7 @@ int gd5f_program_load(uint16_t column, const uint8_t *p_buf, size_t size) {
GD5F_CS_LOW();
HAL_SPI_Transmit(&hspi1, cmd, 3, GD5F_SPI_TIMEOUT);
if (size > GD5F_DMA_THRESHOLD) {
if (use_dma != 0U) {
uint32_t tick_start = HAL_GetTick();
g_spi1_dma_done = 0U;
if (HAL_SPI_Transmit_DMA(&hspi1, (uint8_t *)p_buf, (uint16_t)size)