Skip to main content

帧缓存策略

This section shows how to configure the TouchGFX Generator to generate a TouchGFX HAL that uses one of the following Frame Buffer strategies:

  • 单帧缓存
  • 双帧缓存
  • 部分帧缓存

单帧缓存

通过选择单帧缓存作为缓冲策略,开发人员既可以由编译器在内部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
将并行RGB (LTDC)作为显示接口时,起始地址将从LTDC层设置中继承。

按分配

选择按分配时,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
通常,STM32G0没有足够的内部RAM来承担整幅图形的帧缓存。 “部分帧缓存”与该MCU的低成本解决方案完美匹配。

部分帧缓冲器

由于部分帧缓存通常仅用于无TFT控制器且内部RAM很小的低成本MCU,因此部分帧缓存策略期望开发人员实现将帧缓存内容传输到显示器的操作。 参见FMC/SPI方案,以了解如何将像素通过无TFT控制器的MCU的串口传输到显示器等。

为了在TouchGFX里使用部分帧缓存策略,开发人员需要提供用于以下两个功能的实现。 下面显示的代码由CubeMx生成,在TouchGFX/target/generated/TouchGFXGeneratedHAL.cpp里定义了开发人员要用到的TouchGFX Engine的接口。

TouchGFXGeneratedHAL.cpp
/* ******************************************************
* Functions required by Partial Frame Buffer Strategy
* ******************************************************
*
* * uint8_t isTransmittingData() must return whether or not data is currently being transmitted, over e.g. SPI.
* * void transmitFrameBufferBlock(uint8_t* pixels, uint16_t x, uint16_t y, uint16_t w, uint16_t h) will be called
* when the framework wants to send a block. The user must then transfer
* the data represented by the arguments.
*
* A user must call touchgfx::startNewTransfer(); once transmitFrameBufferBlock() has succesfully sent a block.
* E.g. if using DMA to transfer the block, this could be called in the "Transfer Completed" interrupt handler.
*
*/
extern "C" void transmitFrameBufferBlock(uint8_t* pixels, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
extern "C" uint8_t isTransmittingData();

The following function is also generated by CubeMX inside the read-only TouchGFXGeneratedHAL class inside TouchGFX/target/generated/TouchGFXGeneratedHAL.cpp.

Note
此flushFrameBuffer()函数通常用于无TFT控制器的MCU。 对于部分帧缓存应用,TouchGFX Generator可以基于此方法生成专门用于该缓存策略的定义。
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);
}
}