2021-06-29 01:43 PM
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).
2021-06-29 02:07 PM
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.
2021-06-29 02:14 PM
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.
2021-06-29 11:31 PM
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.
2021-06-30 11:23 AM
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.
2021-06-30 11:48 PM
2021-07-07 11:28 AM
@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.