LTDC显示接口
本场景描述在使用LCD-TFT并行显示接口时,如何配置STM32 LTDC显示控制器和TouchGFX Generator。
TouchGFX Generator可生成完整的TouchGFX AL,配置LTDC从帧缓存向显示屏传输像素,并使显示屏与TouchGFX引擎同步。
配置
从STM32CubeMX类别列表的Multimedia组中启用LTDC。
启用LTDC后,并行RGB (LTDC) 选项将在TouchGFX Generator的显示部分变得可用。
通过STM32CubeMX启用LTDC后,必须配置以下参数:
- 配置LTDC(GPIO与相关时序参数),以便与连接的显示屏规格相匹配
- 配置LTDC,以便与所需的TouchGFX应用程序需求相匹配。
TouchGFX Generator可从STM32CubeMX读取各种配置,并在依赖项部分中提供警告、建议或错误的列表。 下图显示了在STM32CubeMX中最初启用LTDC时的依赖项列表:
Note
参数和层配置
必须在LTDC块中配置以下参数:
依赖关系 | 说明 |
---|---|
层数 | TouchGFX只能利用单层。 |
窗口位置 | 默认情况下,LTDC层的水平和垂直窗口位置为0。 窗口的水平和垂直停止位置必须设置为与显示屏尺寸相等。 |
Alpha常数为0 | 默认情况下,LTDC层的alpha常数为0。 除非始终在应用程序中具有全局alpha,否则该常数应大于> 0,最好为255。 |
下图显示了满足警告条件的LTDC配置,该配置会使依赖关系组从TouchGFX Generator界面中消失。
Note
TouchGFX驱动程序/VSYNC信号
当选择并行RGB (LTDC) 作为显示接口时,开发者可访问LTDC应用滴答计时驱动程序,该驱动程序使用LTDC中断来驱动TouchGFX引擎主循环。 这是使用LTDC时驱动TouchGFX引擎主循环的推荐方式。
Note
以下代码是生成的LTDC中断处理程序(适用于单或双帧缓存策略),当显示屏准备就绪时,它会自动发出信号并解除TouchGFX引擎主循环的阻塞。
TouchGFXGeneratedHAL.cpp
extern "C"
{
void HAL_LTDC_LineEventCallback(LTDC_HandleTypeDef* hltdc)
{
if (!HAL::getInstance())
{
return;
}
if (LTDC->LIPCR == lcd_int_active_line)
{
//entering active area
HAL_LTDC_ProgramLineEvent(hltdc, lcd_int_porch_line);
HAL::getInstance()->vSync();
OSWrappers::signalVSync();
// 立即交换帧缓冲区,而不是等待任务被调度。
//注意:任务在唤醒时也会交换,但该操作是受保护的,并且如果已经完成交换,
// 那么此操作将不会产生任何效果。
HAL::getInstance()->swapFrameBuffers();
GPIO::set(GPIO::VSYNC_FREQ);
}
else
{
//退出活动区域
HAL_LTDC_ProgramLineEvent(hltdc, lcd_int_active_line);
// 向框架发送信号,表示显示更新已完成。
HAL::getInstance()->frontPorchEntered();
GPIO::clear(GPIO::VSYNC_FREQ);
}
}
}
LTDC帧缓存地址配置
生成的TouchGFX HAL将在运行时自动配置LTDC层色彩帧缓存起始地址,因此不应在LTDC配置中设置数值。
GFXMMU配置
当使用部分缓存 - LTDC驱动显示屏帧缓存策略时,必须启用并配置GFXMMU。 GFXMMU用于将LTDC读取的帧缓存地址映射到物理内存中部分帧缓存块的地址。
首先在STM32CubeMX的多媒体部分下启用GFXMMU,然后启用地址转换。 对于16位和32位帧缓存像素格式,建议使用16字节的块大小。 对于24位帧缓存像素格式,需要使用12字节的块大小。
Note
Caution
TouchGFX Generator将自动生成地址查找表 (LUT),该表根据GFXMMU配置和LTDC层设置进行地址映射。
启用GFXMMU后,可在TouchGFX Generator中配置所用部分区块的数量(即部分帧缓存块在显示屏中的适配次数)。
该参数将直接影响帧缓存块的RAM使用量。 块的数量必须是2的幂次,例如2、4和8,这将导致帧缓存块的大小分别为显示屏总大小的1/2、1/4和1/8。
帧缓存分配
在使用部分缓存 - LTDC驱动显示屏帧缓存策略时,帧缓存分配策略的语义与通常不同。
如果选择按分配,TouchGFX引擎将直接绘制到物理部分帧缓存块中,而LTDC则通过GFXMMU地址LUT进行读取。
如果选择按地址,则只能指定GFXMMU虚拟缓存之一的地址,TouchGFX引擎在渲染时将通过GFXMMU的虚拟缓存绘制,而不是直接绘制到物理帧缓存块中。
缓存位置 - 按分配
建议的帧缓存分配策略是按分配。 这样,当LTDC通过GFXMMU地址LUT读取数据时,TouchGFX引擎可以直接绘制到物理部分帧缓存块中。
缓存位置 - 按地址
This option is only recommended on some specific platforms with limitations using RGB888 framebuffer format and GPU2D (NeoChrom) to accelerate rendering.
Some MCU's using GPU2D (NeoChrom) to accelerate rendering do not support writing to a 24-bit RGB888 framebuffer. 在这种情况下,GFXMMU用于将从32位ARGB8888格式读/写的数据打包为物理帧缓存块的RGB888格式。
Further reading
要启用此功能,必须将LTDC像素格式设置为使用ARGB8888帧缓存格式,并使用GFXMMU的某个虚拟缓存GFXMMU_VIRTUAL_BUFFERX_BASE
作为帧缓存地址。 需与GFXMMU配置的虚拟缓存地址一致。 如下图所示,将GFXMMU配置为使用12字节的块大小,并为缓存启用打包功能:
这些选项将反映在TouchGFX Generator UI中:
必须在链接器脚本中以正确大小(即每个像素3字节)定义物理24位帧缓存区域,并使用该区域的起始地址来配置GFXMMU的物理缓存地址。
Note
支持的帧缓存策略
- 单帧缓存
- 双帧缓存
- 部分缓存 - LTDC驱动显示
Further reading
单帧缓存
使用单帧缓存策略的LTDC驱动显示屏时,会在HAL中生成以下代码,允许TouchGFX引擎按照显示屏的刷新周期来优化渲染过程:
TouchGFXGeneratedHAL.cpp
uint16_t TouchGFXGeneratedHAL::getTFTCurrentLine()
{
// CPSR寄存器(位 15:0)指定TFT控制器的当前行。
uint16_t curr = (uint16_t)(LTDC->CPSR & LTDC_CPSR_CYPOS_Msk);
uint16_t backPorchY = (uint16_t)(LTDC->BPCR & LTDC_BPCR_AVBP_Msk) + 1;
// getTFTCurrentLine() 函数的语义是返回
// 0-totalheight范围内的值。 如果仍处于后沿区,则返回0。
return (curr < backPorchY) ? 0 : (curr - backPorchY);
}
在LTDC中断处理程序中,不会交换LTDC帧缓存地址,当显示屏刷新周期离开活动区域时(即显示屏读取帧缓存最后一行后),TouchGFX引擎可完成当前帧的渲染。
参考实现
TouchGFX板设置STM32U5G9J探索套件2包含一个双帧缓存策略的参考实现。 在TouchGFX Generator中将帧缓存策略更改为单帧缓存策略并生成代码,可查看使用单帧缓存策略的示例:
双帧缓存
使用双帧缓存策略的LTDC驱动显示屏时,LTDC帧缓存地址将在中断处理程序中交换到另一个帧缓存。 这使得LTDC从另一个帧缓存读取当前帧时,TouchGFX引擎可在交换帧缓存地址后立即渲染下一帧。
参考实现
TouchGFX板设置STM32U5G9J探索套件2包含一个参考实现:
部分缓存 - LTDC驱动显示
采用部分帧缓存策略的LTDC驱动显示屏与单帧缓存策略类似,但TouchGFX引擎仅会渲染到部分帧缓存块。 由于是重复使用相同的帧缓存块来渲染显示屏的所有部分,因此高效管理渲染过程以避免撕裂和错过硬性截止时间就显得至关重要。 要启用此功能,TouchGFX Generator将在HAL中生成以下代码,允许TouchGFX引擎配置LTDC行中断,从而向TouchGFX引擎发出何时渲染显示屏下一部分的信号:
TouchGFXGeneratedHAL.cpp
void TouchGFXGeneratedHAL::waitForLTDCLines(uint16_t numberOfLines)
{
// CPSR寄存器(位 15:0)指定TFT控制器的当前行。
uint16_t curr = LTDC->CPSR & LTDC_CPSR_CYPOS_Msk;
// AWCR寄存器 (10:0) 指定累计有效高度。
uint16_t max = (LTDC->AWCR & LTDC_AWCR_AAH_Msk) - 1;
// 计算需要配置中断的行号。
curr += numberOfLines;
if (curr > max)
{
curr -= max;
}
// 配置行中断
HAL_LTDC_ProgramLineEvent(&hltdc, curr);
// 等待VSync信号,该信号会在我们刚刚配置的行中断时触发。
OSWrappers::waitForVSync();
}
函数TouchGFXGeneratedHAL::waitForLTDCLines(uint16_t)
由TouchGFX引擎绘制循环调用。 请求的具体行号取决于一组参数。 根据TouchGFX Generator中配置的部分区块数量,将为这些参数分配一组适当的默认值。
由于帧缓存块被重复用于渲染显示屏的所有部分,通常用于指示LTDC扫描行已离开有效区域的VSYNC信号,现被用于通知TouchGFX引擎开始渲染显示屏的下一部分:
TouchGFXGeneratedHAL.cpp
extern "C"
{
void HAL_LTDC_LineEventCallback(LTDC_HandleTypeDef* hltdc)
{
OSWrappers::signalVSync();
}
}
参考实现
The TouchGFX Board Setup STM32H7S78 DK Emulated Framebuffer includes a reference implementation: