2020-10-02 05:59 AM
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
2020-10-13 05:59 AM
Hi again!
Since posting UPDATE 2, TouchGFX runs without any problems (with the two additional lines in HAL_DSI_TearingEffectCallback). So the two additional lines obviously fixed my problem.
Are there no comments / suggestions / bug reports from the TouchGFX community / developer teams so far???
I think I've found a bug in the TouchGFX base (or the code that is generated by CubeMX directly on top of the TouchGFX base) and supplied the fix...
Kind regards,
Klemens Pleiner
2022-07-26 03:00 AM
Hello,
I'm facing this Freezing issue since few weeks now with no real clues on how to solve it.
I just found your forum and test your updates on the codes and got the same result.
Everything seems fine with what you added in the Tearing effect function.
I discussed about it with some of the ST Employees but didn't found any other solutions yet. That my forum : https://community.st.com/s/question/0D73W000001OxAWSA0/detail?s1oid=00Db0000000YtG6&s1nid=0DB0X000000DYbd&emkind=chatterCommentNotification&s1uid=0053W000002o6lz&emtm=1657706274681&fromEmail=1&s1ext=0
I was wondering if you could just explain a bit more about what made you choose to add a call to the allowDMATransfers() when refreshRequested is false. To solve your problem.
I know It's been 2 years now so my expectations are not really high, i might be lucky who knows.
Thank you for your time !
2024-07-02 07:45 AM