帧缓存策略
本节介绍了如何配置TouchGFX Generator,以生成基于以下帧缓存策略之一的TouchGFX HAL:
- 单帧缓存
- 双帧缓存
- 部分帧缓存
单帧缓存
通过选择单帧缓存作为缓冲策略,开发人员既可以由编译器在内部RAM中分配帧缓存区域,也可以自行在RAM中指定帧缓存存储位置。
按分配来
选择按分配时,TouchGFX Generator将根据图形的大小和像素位深来分配帧缓存数组大小。
生成用于配置HAL的代码,并将该数组用作帧缓存。
TouchGFXGeneratedHAL.cpp
namespace {
// Use the section "TouchGFX_Framebuffer" in the linker script
// to specify the placement of the buffer
LOCATION_PRAGMA("TouchGFX_Framebuffer")
uint32_t frameBuf[(480 * 272 * 2 + 3) / 4] LOCATION_ATTRIBUTE("TouchGFX_Framebuffer");
}
void TouchGFXGeneratedHAL::initialize()
{
HAL::initialize();
setFrameBufferStartAddresses((void*)frameBuf, (void*)0, (void*)0);
}
按地址
当为帧缓存的位置选择按地址时,TouchGFX Generator将在HAL初始化期间使用指定其起始地址。
TouchGFXGeneratedHAL.cpp
void TouchGFXGeneratedHAL::initialize()
{
HAL::initialize();
setFrameBufferStartAddresses((void*)0xC0000000, (void*)0, (void*)0);
}
双帧缓存
在双帧缓存配置中,TouchGFX Generator将根据所选帧缓存策略和显示接口在HAL中生成用于帧缓存切换的代码。 在主事件循环期间,TouchGFX Engine将会用到与帧缓存相连的存储器接口。
按地址
选择按地址时,TouchGFX Generator将在HAL初始化期间使用两个指定的起始地址。
TouchGFXGeneratedHAL.cpp
void TouchGFXGeneratedHAL::initialize()
{
HAL::initialize();
setFrameBufferStartAddresses((void*)0xC0000000, (void*)0xC003FC00, (void*)0);
}
Tip
按分配来
选择按分配时,TouchGFX Generator将根据图形的大小和像素位深来分配数组大小,这与使用单帧缓存完全一样,只是开辟了两个相同大小的数组。
TouchGFXGeneratedHAL.cpp
namespace {
// Use the section "TouchGFX_Framebuffer" in the linker to specify the placement of the buffer
LOCATION_PRAGMA("TouchGFX_Framebuffer")
uint32_t frameBuf[(480 * 272 * 2 + 3) / 4 * 2] LOCATION_ATTRIBUTE("TouchGFX_Framebuffer");
}
void TouchGFXGeneratedHAL::initialize()
{
HAL::initialize();
setFrameBufferStartAddresses((void*)frameBuf, (void*)(frameBuf + sizeof(frameBuf)/(sizeof(uint32_t)*2)), (void*)0);
}
部分帧缓存
通过选择部分缓存策略,开发人员可以选择许多内存块,以及这些用作帧缓存的诸多不同块大小。 该策略使用TouchGFX所谓的帧缓存分配器,与向外部存储器提供帧缓存所处位置的指针不同,也与在内部存储器中分配固定大小的数组不同。
有关帧缓存概念的一般概述,请参见有关帧缓存的文章。
Tip
由于部分帧缓存通常仅用于无TFT控制器且内部RAM很小的低成本MCU,因此部分帧缓存策略期望开发人员实现将帧缓存内容传输到显示屏的操作。 参见FMC/SPI方案,以了解如何将像素通过无TFT控制器的MCU的串口传输到显示屏等。
为了在TouchGFX里使用部分帧缓存策略,开发人员需要提供用于以下两个功能的实现。 下面显示的代码由CubeMx生成,在TouchGFX/target/generated/TouchGFXGeneratedHAL.cpp
里定义了开发人员要用到的TouchGFX Engine的接口。
TouchGFXGeneratedHAL.cpp
/* ******************************************************
* 部分帧缓冲策略需要用到的函数
* ******************************************************
*
* * uint8_t isTransmittingData(),不管当前传输是否完成,此函数必须返回,比如通过SPI传输.
* * void transmitFrameBufferBlock(uint8_t* pixels, uint16_t x,uint16_t y,uint16_t w,uint16_t h),框架调用此函数发送数据块, 然后用户必须提供正确参数来传输像素数据
* * 一旦transmitFrameBufferBlock() 已经成功发送数据块,用户必须调用touchgfx::startNewTransfer()。
* 例如, 如果使用DMA传输数据块,可以在“传输完成”中断处理函数中调用此函数。
*
*/
extern "C" void transmitFrameBufferBlock(uint8_t* pixels, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
extern "C" uint8_t isTransmittingData();
以下函数也由CubeMX生成在TouchGFXGeneratedHAL
只读类之中,存放在TouchGFX/target/generated/TouchGFXGeneratedHAL.cpp
文件里。
Note
TouchGFXGeneratedHAL.cpp
void TouchGFXGeneratedHAL::flushFrameBuffer(const touchgfx::Rect& rect)
{
HAL::flushFrameBuffer(rect);
// Once flushFrameBuffer() is called by the framework a block is ready for transfer
// Mark it ready for transfer and transmit it if user defined method
// isTransmittingData() does not return false
// If data is not being transmitted, transfer the data with user defined method
// transmitFrameBufferBlock().
frameBufferAllocator->markBlockReadyForTransfer();
if (!isTransmittingData())
{
touchgfx::Rect r;
const uint8_t* pixels = frameBufferAllocator->getBlockForTransfer(r);
transmitFrameBufferBlock((uint8_t*)pixels, r.x, r.y, r.width, r.height);
}
}