guiTask blocks in touchgfx::HAL::lockFrameBuffer and freezes UI completely
Hi Folks,
I'm using the STM32L4R9 DISCO Board where some additional hardware is attached to (via I2C bus). My TouchGFX version is 4.14.0 and I'm using the ChromArtDMA class instead of the class generated by CubeMX to have fast L8 bitmap painting which enables smooth scrolling of such L8 bitmaps (found here: https://community.st.com/s/question/0D50X0000BdgJZkSQM/is-the-l8argb8888-image-format-supported-for-shapes-widget-if-not-will-it-be-in-the-future).
As long as I have no file transfers active, TouchGFX works perfectly well.
But when a background task writes data (read from the additional hardware via I2C) to a file on the SD card (some 10s of KBs per second), the guiTask of TouchGFX blocks in a call to touchgfx::HAL::lockFrameBuffer. This problem can be reproduced at 100% of my test-cases. Only the time, until it happens, varies (from 0.x to 5s).
From what I can see in the debugger, one call to unlockFrameBuffer was missing and thus lockFrameBuffer cannot continue and block the guiTask.
Without the complete source code of TouchGFX I'm not able to fix this problem because I can't see where the missing call to unlockFrameBuffer could be.
When this block happens, the LCD content freezes. But the rest of my tasks continue without any problems. The background task still records the data to the file on the SD card without any problems!
Additional hint: I'm using the FATFS on the SD Card with "dma template" enabled. The generated file FATFS sources contain a bug: Whenever one tries to read to or write from a memory address that is not word-aligned, the read / written contents are corrupted because "DMABASE0[31:0]: Buffer 0 memory base address bits [31:2], shall be word aligned (bit [1:0] are always 0 and read only)". So I fixed this problem directly in ff.c in the methods f_write / and f_read. The file operations work well, the application can read files without any problems and the written files contain the correct contents.
And no, I'm not using stack pointers for DMA transfers!
And all my stack and heap configurations are now insanely huge to avoid stack / heap overflows...
And I've already tried to set the RTOS heap management to heap_3 and back to heap_4. But that did not solve the problem...
UPDATE 1:
I've spent some more hours debugging into this problem:
The generated class TouchGFXHAL contains the method HAL_DSI_TearingEffectCallback which uses refreshRequested in calls to lockDMAToFrontPorch. As long as the original code is active, the blocks can be reproduced.
As soon as I change the calls from
HAL::getInstance()->lockDMAToFrontPorch(refreshRequested);
to
HAL::getInstance()->lockDMAToFrontPorch(false);
I'm NOT able to reproduce the blocking. But I see visual artifacts on the display. (Which I understand as the DMA2D writes to the framebuffer while it's contents are transferred to the display.)
What I do NOT understand: In https://support.touchgfx.com/docs/api/classes/classtouchgfx_1_1_h_a_l#function-lockdmatofrontporch a note says "This setting only has effect when using double buffering.". But I do NOT use double buffering.
As soon as I change the calls from
HAL::getInstance()->lockDMAToFrontPorch(refreshRequested);
to
HAL::getInstance()->lockDMAToFrontPorch(true);
the application hangs immediately.
So it seems to me that setting refreshRequested to true at the wrong moment causes the UI to freeze. Apparently does my file transfer only increase the load of the system (or only the load of the DMA transfers?) in a way that this happens with higher probability.
Was something like this witnessed before?
How can I solve the freezing UI withOUT having visual artifacts on the display?
UPDATE 2:
After further digging into the HAL class, I'm able to avoid the blocking of the guiTask as well as to avoid the visual artifacts on the display. In the generated file TouchGFXHAL.cpp I just tweaked the method HAL_DSI_TearingEffectCallback a littel bit:
void HAL_DSI_TearingEffectCallback(DSI_HandleTypeDef* hdsi)
{
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
GPIO::set(GPIO::VSYNC_FREQ);
HAL::getInstance()->vSync();
OSWrappers::signalVSync();
HAL::getInstance()->lockDMAToFrontPorch(refreshRequested);
HAL::getInstance()->vSync();
OSWrappers::signalVSync();
// In single buffering, only require that the system waits for display update to be finished if we
// actually intend to update the display in this frame.
HAL::getInstance()->lockDMAToFrontPorch(refreshRequested);
// These two lines help to avoid freezing the UI as it was described in
// https://community.st.com/s/question/0D53W00000Jik6iSAB/guitasks-blocks-in-touchgfxhallockframebuffer-and-freezes-ui-completely
if (!refreshRequested)
HAL::getInstance()->allowDMATransfers();
}
if (refreshRequested && !displayRefreshing)
{
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
displayRefreshing = true;
}
//Set update whole display region.
LCD_SetUpdateRegion(0);
// Transfer a quarter screen of pixel data.
HAL_DSI_Refresh(hdsi);
}
else
{
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
GPIO::clear(GPIO::VSYNC_FREQ);
}
}
}Is that a valid fix?
If not, could you gide me in fixing my problem in the correct way?
Any help would be highly appreciated!
Thanks & kind regards,
Klemens Pleiner
