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
main.cpp
- Committer:
- Altronics
- Date:
- 2020-03-30
- Revision:
- 3:5ceff0955fb1
- Parent:
- 2:a19deff061e8
File content as of revision 3:5ceff0955fb1:
/*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 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; const uint32_t SDRAM_BANK2_ADDR=SDRAM_BANK1_ADDR+SDRAM_BANK_SIZE; const uint32_t SDRAM_BANK3_ADDR=SDRAM_BANK2_ADDR+SDRAM_BANK_SIZE; const uint32_t SDRAM_BANK4_ADDR=SDRAM_BANK3_ADDR+SDRAM_BANK_SIZE; const uint16_t LCD_WIDTH =480; const uint16_t LCD_HEIGHT=272; const uint16_t LCD_HSYNC =41; const uint16_t LCD_HBP =13; const uint16_t LCD_HFP =32; const uint16_t LCD_VSYNC =10; const uint16_t LCD_VBP =2; const uint16_t LCD_VFP =2; const PinName PIN_LCD_DISP=PI_12; const PinName PIN_LCD_BL =PK_3; uint32_t frontBuffer=SDRAM_BANK1_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); EventQueue* queue=mbed_event_queue(); CircularBuffer<uint16_t,10> buffer; void flip(void); bool draw(void); void transferCompleteHandler(void); void lineHandler(void); void reloadHandler(void); //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, 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 extern "C" void DMA2D_IRQHandler() { uint32_t reg=DMA2D->ISR; DMA2D->IFCR=0x3F; if(reg&0x01) queue->call(printf,"TE\n"); if(reg&0x02) transferCompleteHandler(); if(reg&0x04) queue->call(printf,"WM\n"); if(reg&0x08) queue->call(printf,"CLUTAE\n"); if(reg&0x10) queue->call(printf,"CLUTTC\n"); if(reg&0x20) queue->call(printf,"CFGE\n"); } extern "C" void LTDC_IRQHandler() { uint32_t reg=LTDC->ISR; LTDC->ICR=9; if(reg&0x01) lineHandler(); if(reg&0x08) reloadHandler(); } extern "C" void LTDC_ER_IRQHandler() { uint32_t reg=LTDC->ISR; LTDC->ICR=6; if(reg&0x02) queue->call(printf,"FIFO\n"); if(reg&0x04) queue->call(printf,"TERR\n"); } void initLCD() { __HAL_RCC_LTDC_CLK_ENABLE(); __HAL_RCC_DMA2D_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOI_CLK_ENABLE(); __HAL_RCC_GPIOJ_CLK_ENABLE(); __HAL_RCC_GPIOK_CLK_ENABLE(); RCC_PeriphCLKInitTypeDef PeriphClkInitStruct={0}; PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; PeriphClkInitStruct.PLLSAI.PLLSAIN = 192; PeriphClkInitStruct.PLLSAI.PLLSAIR = 5; PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_4; HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); GPIO_InitTypeDef GPIO_InitStruct={0}; GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FAST; GPIO_InitStruct.Alternate = GPIO_AF14_LTDC; HAL_GPIO_Init(GPIOE,&GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; HAL_GPIO_Init(GPIOI,&GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; HAL_GPIO_Init(GPIOJ,&GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7; HAL_GPIO_Init(GPIOK,&GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Alternate = GPIO_AF9_LTDC; HAL_GPIO_Init(GPIOG,&GPIO_InitStruct); LTDC_HandleTypeDef hLtdcHandler={0}; hLtdcHandler.Init.HorizontalSync=(LCD_HSYNC-1); hLtdcHandler.Init.VerticalSync=(LCD_VSYNC-1); hLtdcHandler.Init.AccumulatedHBP=(LCD_HSYNC+LCD_HBP-1); hLtdcHandler.Init.AccumulatedVBP=(LCD_VSYNC+LCD_VBP-1); hLtdcHandler.Init.AccumulatedActiveH=(LCD_HEIGHT+LCD_VSYNC+LCD_VBP-1); hLtdcHandler.Init.AccumulatedActiveW=(LCD_WIDTH+LCD_HSYNC+LCD_HBP-1); hLtdcHandler.Init.TotalHeigh=(LCD_HEIGHT+LCD_VSYNC+LCD_VBP+LCD_VFP-1); hLtdcHandler.Init.TotalWidth=(LCD_WIDTH+LCD_HSYNC+LCD_HBP+LCD_HFP-1); hLtdcHandler.LayerCfg->ImageWidth = LCD_WIDTH; hLtdcHandler.LayerCfg->ImageHeight = LCD_HEIGHT; hLtdcHandler.Init.Backcolor.Blue = 0; hLtdcHandler.Init.Backcolor.Green= 0; hLtdcHandler.Init.Backcolor.Red = 0; hLtdcHandler.Init.HSPolarity = LTDC_HSPOLARITY_AL; hLtdcHandler.Init.VSPolarity = LTDC_VSPOLARITY_AL; hLtdcHandler.Init.DEPolarity = LTDC_DEPOLARITY_AL; hLtdcHandler.Init.PCPolarity = LTDC_PCPOLARITY_IPC; hLtdcHandler.Instance = LTDC; HAL_LTDC_Init(&hLtdcHandler); LTDC_LayerCfgTypeDef layer_cfg={0}; layer_cfg.WindowX0 = 0; layer_cfg.WindowX1 = LCD_WIDTH; layer_cfg.WindowY0 = 0; layer_cfg.WindowY1 = LCD_HEIGHT; layer_cfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; layer_cfg.FBStartAdress = frontBuffer; layer_cfg.Alpha = 255; layer_cfg.Alpha0 = 0; layer_cfg.Backcolor.Blue = 0; layer_cfg.Backcolor.Green = 0; layer_cfg.Backcolor.Red = 0; layer_cfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; layer_cfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; layer_cfg.ImageWidth = LCD_WIDTH; layer_cfg.ImageHeight = LCD_HEIGHT; HAL_LTDC_ConfigLayer(&hLtdcHandler,&layer_cfg,1); DMA2D->OPFCCR=2; DMA2D->OCOLR=0; DMA2D->OMAR=frontBuffer; DMA2D->OOR=0; DMA2D->NLR=(((uint32_t)LCD_WIDTH)<<16)|((uint32_t)LCD_HEIGHT); DMA2D->CR=0x30001; while((DMA2D->CR)&0x01); 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; HAL_NVIC_SetPriority(LTDC_IRQn,5,0U); HAL_NVIC_EnableIRQ(LTDC_IRQn); HAL_NVIC_SetPriority(LTDC_ER_IRQn,5,0U); HAL_NVIC_EnableIRQ(LTDC_ER_IRQn); HAL_NVIC_SetPriority(DMA2D_IRQn,5,0U); HAL_NVIC_EnableIRQ(DMA2D_IRQn); disp=1; bl=1; } void transferCompleteHandler() { queue->call(printf,"TC\n"); #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(); #elif BUFFER_COUNT==1 draw(); #endif } void lineHandler() { queue->call(printf,"LN\n"); #if BUFFER_COUNT>=2 if(running==true) line=true; else if(updated>0) flip(); else draw(); #elif BUFFER_COUNT==1 draw(); #endif } void flip() { 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; frontBuffer=backBuffer; backBuffer=tmpBuffer; } void reloadHandler() { queue->call(printf,"RST\n"); running=true; updated=2; //Restore back buffer ASAP DMA2D->FGMAR=frontBuffer; 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; } bool draw() { running=true; if(DMA2D->CR&0x01) return false; if(buffer.empty()) { running=false; #if BUFFER_COUNT==1 cont=false; #endif return false; } 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 BUFFER_COUNT==3 DMA2D->OMAR=propBuffer; #elif BUFFER_COUNT==2 DMA2D->OMAR=backBuffer; #elif BUFFER_COUNT==1 DMA2D->OMAR=frontBuffer; #endif DMA2D->OOR=0; DMA2D->NLR=(((uint32_t)LCD_WIDTH)<<16)|((uint32_t)(LCD_HEIGHT)); DMA2D->IFCR=0x3F; DMA2D->CR=0x33F01; return true; } int main() { DeepSleepLock lock; {RawSerial pc(USBTX,USBRX,250000);} printf("Hello World!\n"); BSP_SDRAM_Init(); initLCD(); Timer t;t.start(); while(1) { if(cont) continue; 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 BUFFER_COUNT==1 ThisThread::sleep_for(100); #endif } } #ifdef sdfklasdhalefn #error "This code won't match pinouts for any available dev board" /*Initalisation code for IS42S16400 SDRAM*/ void initSDRAM() { __HAL_RCC_FMC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct={0}; GPIO_InitStruct.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_FMC; HAL_GPIO_Init(GPIOF,&GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_7; HAL_GPIO_Init(GPIOA,&GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5; HAL_GPIO_Init(GPIOC,&GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_15; HAL_GPIO_Init(GPIOG,&GPIO_InitStruct); GPIO_InitStruct.Pin=GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1; HAL_GPIO_Init(GPIOE,&GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1; HAL_GPIO_Init(GPIOD,&GPIO_InitStruct); FMC_SDRAM_TimingTypeDef Timing={0}; Timing.LoadToActiveDelay = 2; Timing.ExitSelfRefreshDelay = 7; Timing.SelfRefreshTime = 4; Timing.RowCycleDelay = 7; Timing.WriteRecoveryTime = 1; Timing.RPDelay = 2; Timing.RCDDelay = 2; SDRAM_HandleTypeDef sdramHandle={0}; sdramHandle.Instance = FMC_SDRAM_DEVICE; sdramHandle.Init.SDBank = FMC_SDRAM_BANK1; sdramHandle.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; sdramHandle.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; sdramHandle.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16; sdramHandle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; sdramHandle.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2; sdramHandle.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; sdramHandle.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; sdramHandle.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE; sdramHandle.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_2; HAL_SDRAM_Init(&sdramHandle,&Timing); FMC_SDRAM_CommandTypeDef Command={0}; Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; Command.AutoRefreshNumber = 1; Command.ModeRegisterDefinition = 0; HAL_SDRAM_SendCommand(&sdramHandle,&Command,0xFFFF); ThisThread::sleep_for(100); Command.CommandMode = FMC_SDRAM_CMD_PALL; Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; Command.AutoRefreshNumber = 1; Command.ModeRegisterDefinition = 0; HAL_SDRAM_SendCommand(&sdramHandle,&Command,0xFFFF); Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; Command.AutoRefreshNumber = 4; Command.ModeRegisterDefinition = 0; HAL_SDRAM_SendCommand(&sdramHandle,&Command,0xFFFF); Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; Command.AutoRefreshNumber = 1; Command.ModeRegisterDefinition = 0x0220; HAL_SDRAM_SendCommand(&sdramHandle,&Command,0xFFFF); HAL_SDRAM_ProgramRefreshRate(&sdramHandle,0x0606); } #endif