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