cancel
Showing results for 
Search instead for 
Did you mean: 

Problems with triple buffer page flipping

Hansel
Senior

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).

6 REPLIES 6
MM..1
Chief III

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
Senior

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.

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
Senior

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.

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
Senior

@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.