Code to replicate double-draw glitch on ST dev board. Program draws full-screen Red->Green->Blue into back-buffer, then swaps the LTDC layer source buffer before repeating. This should result in a solid blue screen, but produces a visible glitch with parts of the screen flashing red and green.

Dependencies:   BSP_DISCO_F746NG

Files at this revision

API Documentation at this revision

Comitter:
Altronics
Date:
Mon Mar 30 02:00:31 2020 +0000
Parent:
2:a19deff061e8
Commit message:
Added 3rd buffer for prop assembly.; Appears to fix issue.

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r a19deff061e8 -r 5ceff0955fb1 main.cpp
--- a/main.cpp	Fri Mar 27 07:39:08 2020 +0000
+++ b/main.cpp	Mon Mar 30 02:00:31 2020 +0000
@@ -1,9 +1,21 @@
+/*Example code to replicate double-draw glitch on DISCO-F746NG
+ *
+ *The code rapidly draws to the screen, always ending on the same solid color
+ *box. When using single buffering there is a (as expected) glitch on the 
+ *screen. The unexpected bit is that this glitch persists when double buffering.
+ *
+ *A known-good workaround is to "tripple buffer" the system, with props
+ *assembled in a 3rd buffer, and copied to the back buffer in 1 go, before
+ *screen refresh. This isn't an idea solution, but at least it's something...
+ */
+
 #include "mbed.h"
 #include "stm32746g_discovery_sdram.h"
 
-//If 0 then always draw to front buffer
-//else always draw to back buffer
-#define DOUBLE_BUFFER 0
+//If 0 draw to front buffer
+//If 2 draw to back buffer
+//If 3 draw to prop buffer (and move to back before swap)
+#define BUFFER_COUNT 3
 
 const uint32_t SDRAM_BANK1_ADDR=0xC0000000;
 const uint32_t SDRAM_BANK_SIZE =0x200000;
@@ -24,7 +36,10 @@
 const PinName PIN_LCD_BL  =PK_3;
 
 uint32_t frontBuffer=SDRAM_BANK1_ADDR;
-uint32_t backBuffer=SDRAM_BANK2_ADDR;
+uint32_t backBuffer=SDRAM_BANK1_ADDR+LCD_WIDTH*LCD_HEIGHT*2;
+//uint32_t backBuffer=SDRAM_BANK2_ADDR;
+uint32_t propBuffer=SDRAM_BANK2_ADDR;
+//uint32_t propBuffer=SDRAM_BANK3_ADDR;
 
 DigitalOut disp(PIN_LCD_DISP);
 DigitalOut bl(PIN_LCD_BL);
@@ -41,8 +56,8 @@
 //Some of these may be redundant... There have been some modifications made to
 //try different things which haven't been fully stripped out.
 volatile bool line=false;    //Line handler went off while DMA2D active
-volatile bool running=false; //DMA2D transfer ongoing or imminent
-volatile uint8_t updated=0;  //0 BB not updated, 1 Updated, 2 Restoring from front
+volatile bool running=false; //DMA2D transfer ongoing, imminent or in ISR controlled section
+volatile uint8_t updated=0;  //0 BB not updated (also prop restore), 1 Updated, 2 Restoring from front, 3 3rd buffer to back transfer
 volatile bool swapping=false;//Do-Once since both LN and TC can trigger buffer swap
 volatile bool cont=false;    //Wait untill buffer swap completes before repeating
 
@@ -155,6 +170,9 @@
     DMA2D->OMAR=backBuffer;
     DMA2D->CR=0x30001;
     while((DMA2D->CR)&0x01);
+    DMA2D->OMAR=propBuffer;
+    DMA2D->CR=0x30001;
+    while((DMA2D->CR)&0x01);
     
     LTDC->LIPCR=LCD_HEIGHT+LCD_VSYNC+LCD_VBP;
     LTDC->IER=0x0F;
@@ -167,22 +185,39 @@
     HAL_NVIC_EnableIRQ(DMA2D_IRQn);
     
     disp=1;
-    ThisThread::sleep_for(100);
     bl=1;
 }
 
 void transferCompleteHandler() {
 
     queue->call(printf,"TC\n");
-    #if DOUBLE_BUFFER
-    if(updated==2) {
+    #if BUFFER_COUNT>=2
+    if(updated==3) {
+        swapping=false;
+        flip();
+        return;
+    } else if(updated==2) {
+        #if BUFFER_COUNT==3
+        //Restore prop buffer
+        queue->call(printf,"PROP\n");
+        DMA2D->FGMAR=backBuffer;
+        DMA2D->FGOR=0;
+        DMA2D->FGPFCCR=2;
+        DMA2D->OPFCCR=2;
+        DMA2D->OMAR=propBuffer;
+        DMA2D->OOR=0;
+        DMA2D->NLR=(((uint32_t)LCD_WIDTH)<<16)|((uint32_t)(LCD_HEIGHT));
+        DMA2D->IFCR=0x3F;
+        DMA2D->CR=0x3F01;
+        updated=0;
+        #endif
         swapping=false;
         updated=0;
         line=false;
         cont=false;
     }
     if(line||(buffer.empty()&&(updated>0))) flip(); else draw();
-    #else
+    #elif BUFFER_COUNT==1
     draw();
     #endif
 }
@@ -190,9 +225,9 @@
 void lineHandler() {
     
     queue->call(printf,"LN\n");
-    #if DOUBLE_BUFFER
+    #if BUFFER_COUNT>=2
     if(running==true) line=true; else if(updated>0) flip(); else draw();
-    #else
+    #elif BUFFER_COUNT==1
     draw();
     #endif
 }
@@ -202,6 +237,24 @@
     if(swapping) return;
     swapping=true;
     queue->call(printf,"SW\n");
+    #if BUFFER_COUNT==3
+    if(updated!=3) {
+        queue->call(printf,"3UP\n");
+        //Move prop buffer to backBuffer
+        updated=3;
+        DMA2D->FGMAR=propBuffer;
+        DMA2D->FGOR=0;
+        DMA2D->FGPFCCR=2;
+        DMA2D->OPFCCR=2;
+        DMA2D->OMAR=backBuffer;
+        DMA2D->OOR=0;
+        DMA2D->NLR=(((uint32_t)LCD_WIDTH)<<16)|((uint32_t)(LCD_HEIGHT));
+        DMA2D->IFCR=0x3F;
+        DMA2D->CR=0x3F01;
+        return;
+    }
+    #endif
+    //Swap front and back buffers
     LTDC_Layer1->CFBAR=backBuffer;
     LTDC->SRCR=0x02;
     uint32_t tmpBuffer=frontBuffer;
@@ -214,6 +267,7 @@
     queue->call(printf,"RST\n");
     running=true;
     updated=2;
+    //Restore back buffer ASAP
     DMA2D->FGMAR=frontBuffer;
     DMA2D->FGOR=0;
     DMA2D->FGPFCCR=2;
@@ -231,20 +285,22 @@
     if(DMA2D->CR&0x01) return false;
     if(buffer.empty()) {
         running=false;
-        #if !DOUBLE_BUFFER
+        #if BUFFER_COUNT==1
         cont=false;
         #endif
         return false;
     }
-    queue->call(printf,"DRAW\n");
     if(updated==0) updated=1;
     uint16_t color=0;
     buffer.pop(color);
+    queue->call(printf,"DRAW: 0x%04X\n",color);
     DMA2D->OPFCCR=2;
     DMA2D->OCOLR=(uint32_t)color;
-    #if DOUBLE_BUFFER
+    #if BUFFER_COUNT==3
+    DMA2D->OMAR=propBuffer;
+    #elif BUFFER_COUNT==2
     DMA2D->OMAR=backBuffer;
-    #else
+    #elif BUFFER_COUNT==1
     DMA2D->OMAR=frontBuffer;
     #endif
     DMA2D->OOR=0;
@@ -261,17 +317,37 @@
     printf("Hello World!\n");
     BSP_SDRAM_Init();
     initLCD();
+    Timer t;t.start();
     
     while(1) {
         if(cont) continue;
-        uint16_t color=0xF800;
-        buffer.push(color);
-        color=0x07E0;
-        buffer.push(color);
-        color=0x001F;
-        buffer.push(color);
+        uint16_t col1;
+        uint16_t col2;
+        uint16_t col3;
+        //Cycle colors so we know there's activity (I'm prone to making stupid errors...)
+        if(t.read_ms()>15000) {
+            t.reset();
+            col1=0xF800;//R
+            col2=0x07E0;//G
+            col3=0x001F;//B
+        } else if(t.read_ms()>10000) {
+            col1=0x001F;//B
+            col2=0xF800;//R
+            col3=0x07E0;//G
+        } else if(t.read_ms()>5000) {
+            col1=0x07E0;//G
+            col2=0x001F;//B
+            col3=0xF800;//R
+        } else {
+            col1=0xF800;//R
+            col2=0x07E0;//G
+            col3=0x001F;//B
+        }            
+        buffer.push(col1);
+        buffer.push(col2);
+        buffer.push(col3);
         cont=true;
-        #if !DOUBLE_BUFFER
+        #if BUFFER_COUNT==1
         ThisThread::sleep_for(100);
         #endif
     }