Files
motor_ili9341/SystemDrivers/ILI9341.h
T
zhy200308 fd6c18c4c7 ILI9341: 增加 DMA/纯阻塞 两种传输 + 每次 flush 日志,便于定位错位/残留
- ILI9341_USE_DMA 开关:1=DMA+同步等待,0=纯阻塞SPI(不用DMA),同一入口
- ILI9341_LOG_EN/LOG_EVERY:每次(或每N次)flush 打印 方式/区域/字节/耗时/
  错误码/累计错误/超时/缓冲地址(判断是否落在AXI SRAM)
- DWT 微秒计时;纯阻塞路径无 D-Cache/DMA 一致性问题,用于对照
- README 增加两种模式对照判读表
2026-07-08 11:40:20 +08:00

133 lines
5.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifndef __ILI9341_H__
#define __ILI9341_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "spi.h"
#include <stdint.h>
#include <stddef.h>
/* ============================================================
* ILI9341 TFT-LCD 驱动 (STM32H750 + SPI1 + DMA1_Stream2)
*
* 设计要点(详见 SystemDrivers/README_ILI9341.md):
* 1. 硬件旋转:方向完全由 MADCTL 决定,软件不做转置,
* LVGL 坐标与面板坐标 1:1 对应,从根本上消除移动物体
* 残留/拖影问题。
* 2. 全异步 DMAILI9341_FlushArea_DMA() 启动 DMA 后立刻返回,
* 传输完成由 SPI 中断回调收尾并触发用户回调(=lv_disp_flush_ready)。
* 刷新任务不再阻塞,SPI/DMA 时序自同步,不依赖任何 RTOS 信号量。
* 3. DMA 源缓冲必须位于 DMA 可访问内存(AXI SRAM 0x24000000)
* 绝不能放在 DTCM(0x20000000)——DMA1 无法访问 DTCM。
* LVGL 绘制缓冲用 LCD_RAM_ATTR 强制放入 .lcd_ram 段。
* 4. 看门狗 + 出错自恢复:任何一次传输异常都会被恢复,
* 不会级联导致长时间白屏。
* ============================================================ */
/* ============================================================
* 诊断/调试开关
* ILI9341_USE_DMA : 1 = 用 DMA 搬运像素(+任务内同步等待)
* 0 = 纯阻塞 SPI(完全不用 DMA,CPU 直推)
* 两种方式共用同一入口 ILI9341_FlushArea_DMA()
* 切换后对比日志即可判断“错位/残留”是否与 DMA 相关。
* ILI9341_LOG_EN : 1 = 每次 flush 打印一行日志(走 UART4 Debug_Printf
* ILI9341_LOG_EVERY: 每多少次 flush 打印一次(1=每次;调大可减轻串口负担)
* ============================================================ */
#ifndef ILI9341_USE_DMA
#define ILI9341_USE_DMA 1
#endif
#ifndef ILI9341_LOG_EN
#define ILI9341_LOG_EN 1
#endif
#ifndef ILI9341_LOG_EVERY
#define ILI9341_LOG_EVERY 1U
#endif
/* 面板原生(未旋转)分辨率 */
#define ILI9341_NATIVE_WIDTH 240U
#define ILI9341_NATIVE_HEIGHT 320U
/* 当前工作方向下的分辨率(默认横屏 320x240,见 ILI9341_SetRotation */
#define ILI9341_WIDTH 320U
#define ILI9341_HEIGHT 240U
/* ------------------------------------------------------------
* LCD 控制引脚(与 main.h / gpio.c 保持一致,PB12=CS 已被配置为输出)
* ------------------------------------------------------------ */
#define LCD_CS_PORT GPIOB
#define LCD_CS_PIN GPIO_PIN_12
#define LCD_DC_PORT GPIOB
#define LCD_DC_PIN GPIO_PIN_7
#define LCD_RST_PORT GPIOB
#define LCD_RST_PIN GPIO_PIN_8
#define LCD_BL_PORT GPIOB
#define LCD_BL_PIN GPIO_PIN_9
/* RGB565 常用颜色(大端字节序由发送时处理) */
#define ILI9341_BLACK 0x0000
#define ILI9341_WHITE 0xFFFF
#define ILI9341_RED 0xF800
#define ILI9341_GREEN 0x07E0
#define ILI9341_BLUE 0x001F
#define ILI9341_YELLOW 0xFFE0
#define ILI9341_CYAN 0x07FF
#define ILI9341_MAGENTA 0xF81F
#define ILI9341_GRAY 0x8410
/* ------------------------------------------------------------
* DMA 可访问内存属性。
* 所有交给 ILI9341_FlushArea_DMA() 的缓冲区都必须用它修饰,
* 链接脚本(motor_ili9341_lcd.sct)会把 .lcd_ram 段放到 AXI SRAM。
* 32 字节对齐是为了配合 D-Cache 的 clean-by-address 粒度。
* ------------------------------------------------------------ */
#if defined(__GNUC__) || defined(__clang__)
#define LCD_RAM_ATTR __attribute__((section(".lcd_ram"), aligned(32)))
#else
#define LCD_RAM_ATTR
#warning "未识别的工具链:请自行确保 LCD DMA 缓冲位于 DMA 可访问内存并 32 字节对齐"
#endif
/* 传输完成回调(在 SPI 中断上下文里被调用,务必只做极短的事) */
typedef void (*ILI9341_FlushDoneCb)(void *user_data);
/* ---- 初始化 / 方向 ---- */
void ILI9341_Init(void);
void ILI9341_SetRotation(uint8_t rotation); /* 0/1/2/3,默认 1=横屏 */
/* ---- 阻塞式基础绘图(仅用于初始化清屏/自检,非 LVGL 热路径) ---- */
void ILI9341_FillScreen(uint16_t color);
void ILI9341_FillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color);
uint16_t ILI9341_Color565(uint8_t r, uint8_t g, uint8_t b);
/* ---- LVGL 异步刷新入口 ----
* data 必须已按面板发送顺序排列(配合 lv_conf.h 的 LV_COLOR_16_SWAP=1
* LVGL 直接产出正确字节序,无需再拷贝/交换)。
* 函数启动 DMA 后立即返回;传输完成后在中断里调用 done_cb(user_data)。
* 若参数非法或启动失败,会同步调用 done_cb 以避免 LVGL 卡死。 */
void ILI9341_FlushArea_DMA(uint16_t x, uint16_t y,
uint16_t w, uint16_t h,
const uint16_t *data,
ILI9341_FlushDoneCb done_cb,
void *user_data);
/* ---- 传输是否进行中(供上层判断) ---- */
uint8_t ILI9341_IsBusy(void);
/* ---- 看门狗:从任务上下文周期性调用(例如 lv_timer_handler 之后)。
* 绝不能从中断里调用。若一次 DMA 传输超过 timeout_ms 仍未完成,
* 强制中止、重建 SPI、恢复 CS 并触发完成回调,避免永久白屏。
* timeout_ms 建议 150~200ms。 */
void ILI9341_ServiceWatchdog(uint32_t timeout_ms);
#ifdef __cplusplus
}
#endif
#endif /* __ILI9341_H__ */