Skip to main content
Jon Enz
Associate III
November 5, 2020
Question

TouchGFX Double Framebuffer Swapping Logic

  • November 5, 2020
  • 3 replies
  • 6655 views

I'm a bit confused about the strategy used to determine when to swap buffers when TouchGFX is configured for double frame buffers. As illustrated here, the intent of the double frame buffer is to allow the old frame buffer to be presented if there is a long render time for the next frame.0693W000005AWzkQAG.png The issue is that I don't see how the TouchGFX implementation enables this. My understanding is that the function HAL::swapFrameBuffers is responsible for switching the pointer to the current frame buffer for the LTDC. Looking at calls to this function, the only one I can find is within the HAL_LTDC_LineEventCallback within TouchGFXGeneratedHAL.cpp.

extern "C"
{
 void HAL_LTDC_LineEventCallback(LTDC_HandleTypeDef *hltdc)
 {
 if (LTDC->LIPCR == lcd_int_active_line)
 {
 //entering active area
 HAL_LTDC_ProgramLineEvent(hltdc, lcd_int_porch_line);
 HAL::getInstance()->vSync();
 OSWrappers::signalVSync();
 // Swap frame buffers immediately instead of waiting for the task to be scheduled in.
 // Note: task will also swap when it wakes up, but that operation is guarded and will not have
 // any effect if already swapped.
 HAL::getInstance()->swapFrameBuffers();
 GPIO::set(GPIO::VSYNC_FREQ);
 }
 else
 {
 //exiting active area
 HAL_LTDC_ProgramLineEvent(hltdc, lcd_int_active_line);
 GPIO::clear(GPIO::VSYNC_FREQ);
 HAL::getInstance()->frontPorchEntered();
 }
 }
}

My understanding is that this callback function, specifically the condition that contains the call to swapFrameBuffers, will be executed every time the LTDC is ready to start drawing a new frame, what if the TouchGFX engine hasn't completed rendering the new frame? Why call that function from the ISR, and not from the TouchGFX engine when the frame is done rendering? What am I missing about how this works?

To give some more context, I'm implementing manual 180 deg rotation using the method stated here, so I am anticipating some long render times and lost frames. I am seeing artifacts and shifts on some of the frames currently that I would expect to be removed by a double frame buffer.

This topic has been closed for replies.

3 replies

Martin KJELDSEN
Principal III
November 18, 2020

There must be something else going on, because TouchGFX won't render to/mess with the framebuffer that is being transferred. Are you having memory bandwidth issues?

You can always try hal.LockDMAToFrontPorch(true); in your TouchGFXHAL.cpp initialize() function. This means that DMA operations won't happen until the LTDC has left the active area and reduces strain on memory.

Suffice it to say that TouchGFX is driven by syncronization signals from displays, display controllers or timers. No swapping should occur unless a transfer is complete, and that's how it is for the LTDC/DSI drivers in our application templates or what we can generate from the TouchGFX generator (LTDC only atm).

If you want you can always upload a video of the issue here. I'd quickly be able to tell you what it is i think.

/Martin

Jon Enz
Jon EnzAuthor
Associate III
November 18, 2020

I'm not sure what the cause of this issue is/was, but it seems to have been cleared up and is now working as expected. A colleague was working on some low level DMA/SPI code that may have been causing some bandwidth issues. If it starts happening again I will include a video in the thread.

I was more interested in why the call to swap inside the ISR for the vSync does not check that the task is done rendering the frame, or if it does, how? I'm not worried about the transfer to the hardware being complete. I'm worried that the application task didn't complete drawing the next frame, and the ISR switched it anyways. After seeing it work properly now, I think there is just something I'm missing about the logic.

Martin KJELDSEN
Principal III
November 19, 2020

Can you tell me what's supposed to be there where the artifcats are? Something tells me they're images and you haven't programmet those images to flash. This does not really seem like a buffering-run-time-gitch-kind-of-issue. It's a pretty quiet application.

/Martin

Jon Enz
Jon EnzAuthor
Associate III
November 19, 2020

I'm sorry, the issue that I'm chasing in this post does not have to do with those images. They are supposed to be small icons generated from .png files, but I'm not sure why they're not working. I should have just removed them before taking the video. I haven't started troubleshooting that yet.

The artifacts I'm referring to for this issue are the flashing and shifts of the frame. Here is a screenshot of the video around 29s:

0693W000005C1RqQAK.png

Jon Enz
Jon EnzAuthor
Associate III
November 20, 2020

I was able to (hopefully) resolve the issue today. After some messing with the LTDC and enabling the error interrupts I found that the FIFO buffer in the LTDC is experiencing buffer underruns. In my application (STMH753) the frame buffers are held in a 8MB external SRAM. All of my program RAM is currently configured in the 512KB SRAM. Both of these peripherals are on the 64-bit AXI bus. Looking at my linker script, my .bss and .data sections were not properly aligned to 64 bit. Taking out the . = ALIGN(4); or . = ALIGN(8); statements and replacing them with . = ALIGN(64); statements seems to have cleared up the issue for now.

I don't have the deepest understanding of why this helps. I know it's not efficient to access smaller addressed variables on the 64 bit bus, but this just adjusts the location of the entire data block, not necessarily the variables within the block. I would think the push/pop operations on the various stacks for the tasks would be causing the bandwidth issues, and they are happening somewhere randomly in the middle of the section of RAM.

If anyone has a deeper insight into this please let me know.