Skip to main content
Hansel
Senior
June 29, 2021
Question

Problems with triple buffer page flipping

  • June 29, 2021
  • 6 replies
  • 1236 views

My page flipping via the LTDC works seamlessly if my drawing routine is faster than the frame rate, but as soon it is slower, I see flickering on my LCD. It's not the type of flickering you'd see if a page is overwritten out of sync with the display. I've been wrecking my brain over this during the last two days and can't see what's wrong.

I am using the STM32H745 Disco board.

Here's the code snippet:

while(1) {
 
 // my drawing routine here, storing data in
 // graphicsMemory[currentPage][LAYER1] and 
 // graphicsMemory[currentPage][LAYER2] 
  .
 .
 .
 
 // A reload event will signal that the LCD
 // is pointing at the new page. If that
 // hasn't occured yet, we are stalled.
 while(pageFlag);
 
 // Set frame buffer pointers to new addresses
 LTDC_Layer1->CFBAR = (uint32_t) graphicsMemory[currentPage][LAYER1];
 LTDC_Layer2->CFBAR = (uint32_t) graphicsMemory[currentPage][LAYER2];
 
 // Set flag that indicates that page is ready to be pointed at.
 pageFlag = 1;
 
 // Turn on interrupt on reload
 LTDC->IER = LTDC_IT_RR;
 
 // Enable reload on next vertical blanking
 LTDC->SRCR = LTDC_SRCR_VBR;
 
 // Switch to next available page.
 // Why three pages? Let's assume the first page has
 // been drawn and submitted for being taken over at
 // the next vertical blanking. It is unknown when that 
 // next vertical blanking will occur but waiting for it
 // is a waste of time. So while the first page is still 
 // showing and the second one hasn't been taken
 // over yet, the third page is updated instead.
 switch (currentPage) {
 case PAGE1: currentPage = PAGE2; break;
 case PAGE2: currentPage = PAGE3; break;
 case PAGE3: currentPage = PAGE1; break;
 }
 
} // while(1)
 
void HAL_LTDC_ReloadEventCallback(LTDC_HandleTypeDef *hltdc) {
 // Send signal that the page has been flipped
 pageFlag = 0;
}

What's wrong with this approach, causing the flickering if the drawing routine is too slow? I can't see how the displayed page is being overwritten while drawing a new page (if that's actually the cause of the problem).

This topic has been closed for replies.

6 replies

MM..1
Super User
June 29, 2021

Your idea seems be tripple buffering on every frame. This isnt best way, LTDC dont need change or refresh CFBAR on every frame, but only when you prepare new frame data ready. And double buffering is ok.

Hansel
HanselAuthor
Senior
June 29, 2021

Hi MM..1, I am not doing it on every frame. I do it on demand, namely when the page is done drawing. I understand that triple buffering isn't needed but if I don't want to waste my time waiting for the vertical blanking to occur and use that time for processing the next frame, I don't know how else to do it. In the case above, I will get tearing if I take out one of the three pages.

MM..1
Super User
June 30, 2021

Hi,

showed code wait only for interrupt and repeat on it, because pageFlag=0

then your pages is swapped continuosly on every vertical blanking for example when no graphics changed .

In normal double buffer this swap is in ISR and no while need. Inspire in TouchGFXGeneratedHAL.cpp for LTDC config.

Hansel
HanselAuthor
Senior
June 30, 2021

Hi @MM..1​ , I appreciate your time replying to my posts.

I've been thinking about your comments for a couple of hours but don't really see why the code as it is is leading to flickering when the drawing time is longer than the frame rate. Bear in mind that my graphics changes every time the while loop gets repeated. And even if it didn't, it wouldn't matter as far as page flipping goes because it would then just flip to a page with the same content. If I simplify the code to use double buffering as shown below, it still works perfectly fine if my graphics routine is faster than the frame rate and still flickers if the graphics routine is slower than the frame rate. The difference of the code below compared to the code above is that I am now waiting for the flip to occur right after I've prepared the page to be taken over at the next vertical blanking. That is a waste of time. That's time I can use to prepare another page, hence the code above uses three pages.

 while(1) {
 
 // my drawing routine here, storing data in
 // graphicsMemory[currentPage][LAYER1] and 
 // graphicsMemory[currentPage][LAYER2] 
 .
 .
 .
 
 // A reload event will signal that the LCD
 // is pointing at the new page. If that
 // hasn't occured yet, we are stalled.
 while(pageFlag);
 
 // Set frame buffer pointers to new addresses
 LTDC_Layer1->CFBAR = (uint32_t) graphicsMemory[currentPage][LAYER1];
 LTDC_Layer2->CFBAR = (uint32_t) graphicsMemory[currentPage][LAYER2];
 
 pageFlag = 1;
 LTDC->IER = LTDC_IT_RR;
 LTDC->SRCR = LTDC_SRCR_VBR;
 
 switch (currentPage) {
 case PAGE1: currentPage = PAGE2; break;
 case PAGE2: currentPage = PAGE1; break;
 }
 
 } // while(1)
 
 void HAL_LTDC_ReloadEventCallback(LTDC_HandleTypeDef *hltdc) {
 // Send signal that the page has been flipped
 pageFlag = 0;
 }

As far as using the line events goes, I've tried that as well in the past with the same flickering effect. The difference is that the line event is called every time vertical blanking occurs. But it may be called for nothing because a page may not be prepared to be taken over. So it is less efficient. My code just calls for the flipping only once a new page is ready.

But clearly, there's something wrong with my code. I just don't see what it is.

MM..1
Super User
July 1, 2021
I see you add to first ticket pageFlag = 1;
Im not expert to SRCR , but why you reenable IER on every iteration?
Why you set SRCR VBR without (uint32_t)
Try move IER before while, pageFlag=1 before CFBAR ...
Or better is other idea , create variable newpage rendered and in ISR check if true swap CFBAR with
/* Reload immediate */
LTDC->SRCR = (uint32_t)LTDC_SRCR_IMR;
And flickering maybe you have because you access memory (other page is irelevant) in same time as LTDC, and bus colision occur. Is your pages in internal or SDRAM ? Optimize...
Hansel
HanselAuthor
Senior
July 7, 2021

@MM..1​ I've spent quite some time investigating this further and I believe this has indeed to do with concurrent operations of DMA2D and LTDC. I make heavy use of the DMA2D and noticed that the flickering goes away if I use other operations to fill the screen with graphics. About your questions: The IER has to be re-enabled every time I need the reload event to signal that the page flip has finished. So moving it before updating CFBAR is of no consequence because of the VBR setting after CFBAR and the IER have been updated. In any case, thanks for your hints. They led me in the right direction.