Framebuffer Strategies
This section shows how to configure the TouchGFX Generator to generate a TouchGFX HAL that uses one of the following Framebuffer strategies:
- Single
- Double
- Partial
Read more about framebuffers here.
Single Framebuffer
Choosing Single Buffer as the buffering strategy developers are able to let the compiler allocate memory for the framebuffer in internal RAM but can also choose a specific location for the buffer.
By Allocation
When choosing By Allocation TouchGFX Generator will allocate an array based on the dimensions and bit depth of the application.
Code is generated to configure the HAL to use this array as the framebuffer.
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);
}
By Address
When choosing By Address for the location of the framebuffer TouchGFX Generator will use the specified Start Addresses during HAL initialization.
TouchGFXGeneratedHAL.cpp
void TouchGFXGeneratedHAL::initialize()
{
HAL::initialize();
setFrameBufferStartAddresses((void*)0xC0000000, (void*)0, (void*)0);
}
Double Framebuffer
In a double framebuffer configuration, code to swap framebuffers will be generated in the HAL by TouchGFX Generator depending on the selected Framebuffer strategy and display interface. This memory interface to framebuffer location is used by the TouchGFX Engine during the main event loop.
By Address
When choosing By Address TouchGFX Generator will use the two specified Start Addresses during HAL initialization.
TouchGFXGeneratedHAL.cpp
void TouchGFXGeneratedHAL::initialize()
{
HAL::initialize();
setFrameBufferStartAddresses((void*)0xC0000000, (void*)0xC003FC00, (void*)0);
}
Tip
Tip
By Allocation
When choosing By Allocation TouchGFX Generator will allocate an array based on the dimensions and bit depth of the application, exactly as with a Single Framebuffer, only twice the size.
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);
}
Partial Framebuffer
With the partial framebuffer strategy, TouchGFX does not use a framebuffer in the same size as the display. Instead the user is allowed to choose a number of blocks (of a given size) to be used as framebuffers. TouchGFX uses a Frame Buffer Allocator object to control the use of these block.
With this strategy you don't supply a pointer to external memory (where the framebuffer would be located), nor allocate a framebuffer array in internal memory.
See the article on Framebuffer for a general overview of the concept of framebuffers.
Tip
Since a partial buffering strategy is typically only used with low cost MCU with no TFT controller and little internal RAM the Partial Buffer Strategy expects the developer to implement the transfer of the contents of the framebuffer to the display. See FMC/SPI Scenario for how to transmit pixels to e.g. a serial display on MCUs with no TFT Controller.
In order to link the display with TouchGFX when using the Partial Framebuffer strategy, developers are required to provide implementations for the following two functions. The code displayed below is generated by CubeMX inside TouchGFX/target/generated/TouchGFXGeneratedHAL.cpp
and defines the interface between the TouchGFX Engine and the display driver.
TouchGFXGeneratedHAL.cpp
/* ******************************************************
* Functions required by Partial Frame Buffer Strategy
* ******************************************************
*
* int touchgfxDisplayDriverTransmitActive() must return whether or not data is currently being transmitted, over e.g. SPI.
* void touchgfxDisplayDriverTransmitBlock(const 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.
*/
extern "C" int touchgfxDisplayDriverTransmitActive();
extern "C" int touchgfxDisplayDriverShouldTransferBlock(uint16_t bottom);
extern "C" void touchgfxDisplayDriverTransmitBlock(const uint8_t* pixels, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
extern "C" void touchgfxSignalVSync(void);
For the STM32G071 TouchGFX Board Setup available in the TouchGFX Designer these functions are implemented in Core/Src/MB1642BDisplayDriver.c
(only showing one here):
Core/Src/MB1642BDisplayDriver.c
int touchgfxDisplayDriverTransmitActive(void)
{
return IsTransmittingBlock_;
}
With this strategy CubeMX also generates the TouchGFXGeneratedHAL::flushFrameBuffer(Rect&)
inside the read-only TouchGFXGeneratedHAL
class in TouchGFX/target/generated/TouchGFXGeneratedHAL.cpp
.
Note
TouchGFXGeneratedHAL.cpp
void TouchGFXGeneratedHAL::flushFrameBuffer(const touchgfx::Rect& rect)
{
HAL::flushFrameBuffer(rect);
// Try transmitting a block
PartialFrameBufferManager::tryTransmitBlock();
}