The following scenario shows, generally, the steps involved in writing a TouchGFX driver when selecting Custom display interface in the TouchGFX generator using an LCD connected to either an FMC or through SPI.
The process of writing a TouchGFX display driver for MCUs without embedded display controllers over FMC or SPI is identical. The scenario described in this section uses an ST7789H2 LCD Controller to exemplify.
Once FMC or SPI is configured according to board specifications in CubeMX the TouchGFX Generator can be used to generate a HAL, selecting the Custom display interface, which allows developers to write custom code to transfer the updated parts of the application framebuffer to a connected display.
The figure below shows a TouchGFX Generator configuration with Custom Display Interface selected. This instructs the TouchGFX Generator that the developer would like to configure and transfer pixels from the framebuffer memory to the display manually and generates the handles to accomplish this.
The driver must be able to transfer pixels to the display, and to control the memory writing position of the display. Check its datasheet to find appropriate commands, outlined below, and further details.
Generally, for displays with embedded GRAM such as 8080 or SPI displays, the driver works as follows:
- Based on the area of the framebuffer to be redrawn, move the "display cursor" and "active window" to a place in GRAM that matches this area.
- Prepare to write incoming pixel data to GRAM.
- Send pixel data.
When an area of the framebuffer has been updated, the TouchGFX Engine calls
HAL::flushFrameBuffer(Rect r). This function can be overridden when developers must implement a driver for a "Custom" display interface.
The following function
__ST7789H2_SetDisplayWindow sets the
y coordinates for the virtual "cursor" in GRAM by writing to specific registers, which is usual for displays using GRAM.
The following function
TouchGFXHAL::copyFrameBufferBlockToLCD is a private function that sends one line of the updated area (
Rect) at a time, ensuring to progress the framebuffer pointer accordingly.
Instead of advancing
ptr manually, the TouchGFX Generator will generate a function
advanceFrameBufferToRect that advances
ptr according to the position of
Rect in the framebuffer.
Once the function returns TouchGFX Engine continues to draw the rest of the frame. If developers wish to use DMA to transfer pixels to the display, they must ensure that
HAL::flushFrameBuffer(Rect& rect) does not return immediately by e.g. waiting on a semaphore signaled by a DMA Completed interrupt.
The following pseudo-code example shows an example of how
HAL::flushFrameBuffer() could be structured in case DMA is used. The code uses a FreeRTOS semaphore
As can be seen in TouchGFX Generator configuration above, the "Application Tick Source" is also set to "Custom", which is general for MCUs without embedded TFT Controllers.
As described in the Abstraction Layer Architecture section, the TouchGFX Engine main loop is unblocked by calling
OSWrappers::signalVSync(), usually at the time when a display signals.
For displays with a serial or 8080 display interface, the embedded display controller typically raises a periodic Tearing Effect (TE) signal that can be connected to a GPIO on the MCU. In this case, the MCU is usually configured to raise an interrupt when the GPIO is signalled. This "Tearing Effect" interrupt will then unblock the TouchGFX Engine Main loop to render the next frame. Remember to configure the GPIO to input and enable the external interrupt for the pin in CubeMX.
Selecting Custom Display Interface through the TouchGFX Generator is an expression of a developer's intent to write code to transfer pixels from an application frame buffer to a display, manually.
The TouchGFX Generator will generate a function
TouchGFXHAL::flushFrameBuffer(Rect& rect) that is called automatically by TouchGFX after rendering an area of the framebuffer that developers can use to transfer affected pixels to a display, SPI, FMC or otherwise.
Selecting a custom display interface also requires developers to implement a custom TouchGFX Application Tick driver that signals
OSWrappers::signalVSync() to unblock the TouchGFX Engine Main loop. Usually, displays used along with MCUs that have no TFT Controllers can provide a Tearing Effect signal that is connected to the MCU.