ILI9341: 修复每帧多耗~5ms的空等 + SPI 10MHz->20MHz,解决移动错位
日志实测定位:单块 flush 耗时~9.7ms,远超面板扫描周期(~16ms)导致扫描 在写入途中'套圈',方块被撕成多个错位副本。两处根因: - LCD_SPI_WaitShiftEmpty 轮询 TXC,但 HAL 在 EOT 后关闭 SPI,TXC 恒0, 每帧白等满 5ms 超时。HAL 的 EOT/阻塞传输已保证数据移出,直接删除。 - SPI 仅 10MHz(pll1_q40M/4),0.8us/byte。改 prescaler 4->2 = 20MHz。 合计单块 flush ~9.7ms -> ~2.3ms,远小于扫描周期,错位应显著消除。 spi.c 与 .ioc(本就=_2) 对齐。
This commit is contained in:
+4
-1
@@ -45,7 +45,10 @@ void MX_SPI1_Init(void)
|
|||||||
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
|
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||||
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
|
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||||
hspi1.Init.NSS = SPI_NSS_SOFT;
|
hspi1.Init.NSS = SPI_NSS_SOFT;
|
||||||
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
|
/* pll1_q=40MHz / 2 = 20MHz SPI(原来 /4=10MHz 太慢,单块刷新耗时逼近
|
||||||
|
* 面板扫描周期导致移动错位)。ILI9341 写周期实测可稳定跑 20~40MHz;
|
||||||
|
* 若接线长/花屏,退回 SPI_BAUDRATEPRESCALER_4。 */
|
||||||
|
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
|
||||||
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||||
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
|
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||||
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||||
|
|||||||
+5
-26
@@ -242,29 +242,6 @@ static void LCD_CleanDCache(const void *addr, uint32_t size)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================= 等待 SPI 移位彻底完成 ================= */
|
|
||||||
|
|
||||||
static void LCD_SPI_WaitShiftEmpty(void)
|
|
||||||
{
|
|
||||||
/* HAL 在传输完成中断里已经把数据全部交给 SPI,但最后几个 bit 可能
|
|
||||||
* 还在移位。拉高 CS 前确认 TXC/EOT,避免尾部像素被 CS 截断——尾部
|
|
||||||
* 截断在快速移动时会表现为“擦除不干净/残留一条边”。 */
|
|
||||||
uint32_t t0 = HAL_GetTick();
|
|
||||||
|
|
||||||
#if defined(SPI_FLAG_TXC)
|
|
||||||
while (__HAL_SPI_GET_FLAG(&hspi1, SPI_FLAG_TXC) == RESET)
|
|
||||||
{
|
|
||||||
if ((HAL_GetTick() - t0) > 5U) break;
|
|
||||||
}
|
|
||||||
#elif defined(SPI_FLAG_EOT)
|
|
||||||
while (__HAL_SPI_GET_FLAG(&hspi1, SPI_FLAG_EOT) == RESET)
|
|
||||||
{
|
|
||||||
if ((HAL_GetTick() - t0) > 5U) break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
__DSB();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================= 两种传输实现 =================
|
/* ================= 两种传输实现 =================
|
||||||
* 均为“同步返回”:函数返回时该块像素一定已完整写入面板。
|
* 均为“同步返回”:函数返回时该块像素一定已完整写入面板。
|
||||||
* 返回值:0=成功,1=超时/出错(已尽力恢复)。 */
|
* 返回值:0=成功,1=超时/出错(已尽力恢复)。 */
|
||||||
@@ -310,7 +287,9 @@ static uint8_t LCD_Xfer_DMA(const uint16_t *data, uint32_t byte_len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LCD_SPI_WaitShiftEmpty();
|
/* HAL 的 TxCplt 由 SPI EOT 触发,此刻数据已全部移出,直接拉高 CS。
|
||||||
|
* 不再自旋等待 TXC——EOT 之后 HAL 会关闭 SPI,TXC 恒为 0,等待会白等
|
||||||
|
* 满超时(实测每帧多耗约 5ms,正是移动错位的元凶之一)。 */
|
||||||
LCD_CS_HIGH();
|
LCD_CS_HIGH();
|
||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
@@ -328,10 +307,10 @@ static uint8_t LCD_Xfer_Poll(const uint16_t *data, uint32_t byte_len)
|
|||||||
LCD_CS_LOW();
|
LCD_CS_LOW();
|
||||||
LCD_DC_DATA();
|
LCD_DC_DATA();
|
||||||
|
|
||||||
/* byte_len 上限 = 单块缓冲字节数 < 65535,可一次发完 */
|
/* byte_len 上限 = 单块缓冲字节数 < 65535,可一次发完。
|
||||||
|
* HAL_SPI_Transmit 在 H7 上返回时数据已移出,直接拉高 CS。 */
|
||||||
st = HAL_SPI_Transmit(&hspi1, (uint8_t *)data, (uint16_t)byte_len, 100);
|
st = HAL_SPI_Transmit(&hspi1, (uint8_t *)data, (uint16_t)byte_len, 100);
|
||||||
|
|
||||||
LCD_SPI_WaitShiftEmpty();
|
|
||||||
LCD_CS_HIGH();
|
LCD_CS_HIGH();
|
||||||
|
|
||||||
return (st == HAL_OK) ? 0U : 1U;
|
return (st == HAL_OK) ? 0U : 1U;
|
||||||
|
|||||||
Reference in New Issue
Block a user