![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
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
Revision 3:5ceff0955fb1, committed 2020-03-30
- 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 |
--- 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 }