2024-02-18 11:28 PM - edited 2024-02-18 11:30 PM
Hi.
A custom board was built using the STM32H753XI. The board contains 16MB SDRAM and we want to use it with an LTDC to display a screen on a TFT-LCD.
I used the embedded wizard to create the UI and verified that it displays correctly on the LCD screen.
However, flickering occurs on the LCD when the screen is switched or parts of the screen change.
I rechecked the clock, SDRAM, LTDC settings, etc. but couldn't find the cause.
I've attached the datasheets for the parts I used as files.
1. TFT-LCD (JWS070NA-23A-1)
2. SDRAM (MT48LC8M16A)
3. Clock configuration
4. FMC
4.1. FMC configuration
/* FMC initialization function */
static void MX_FMC_Init(void) {
/* USER CODE BEGIN FMC_Init 0 */
/* USER CODE END FMC_Init 0 */
FMC_SDRAM_TimingTypeDef SdramTiming = {0};
/* USER CODE BEGIN FMC_Init 1 */
/* USER CODE END FMC_Init 1 */
/** Perform the SDRAM1 memory initialization sequence
*/
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK2;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;
/* SdramTiming */
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 7;
SdramTiming.SelfRefreshTime = 5;
SdramTiming.RowCycleDelay = 6;
SdramTiming.WriteRecoveryTime = 3;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN FMC_Init 2 */
// initialize sdram sequence
init_sdram_handle(&hsdram1, FMC_SDRAM_CMD_TARGET_BANK2);
/* USER CODE END FMC_Init 2 */
}
4.2. Initialize sequence for FMC
SDRAM.BANK = FMC_SDRAM_CMD_TARGET_BANK2
SDRAM.P = &hsdram1
static HAL_StatusTypeDef sdram_init_sequence(void) {
HAL_StatusTypeDef res = HAL_OK;
FMC_SDRAM_CommandTypeDef cmd = {0,};
uint32_t tmp = (uint32_t) SDRAM_MODEREG_BURST_LENGTH_1 | SDRAM_MODEREG_CAS_LATENCY_3 | SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
// configure a clock configuration enable command
cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
cmd.CommandTarget = SDRAM.BANK;
cmd.AutoRefreshNumber = 1;
cmd.ModeRegisterDefinition = 0;
// send command
res |= HAL_SDRAM_SendCommand(SDRAM.P, &cmd, SDRAM_TIMEOUT);
// insert 100 us minimum delay
HAL_Delay(1);
// configure a PALL (pre-charge all) command
cmd.CommandMode = FMC_SDRAM_CMD_PALL;
cmd.CommandTarget = SDRAM.BANK;
cmd.AutoRefreshNumber = 1;
cmd.ModeRegisterDefinition = 0;
// send command
res |= HAL_SDRAM_SendCommand(SDRAM.P, &cmd, SDRAM_TIMEOUT);
// configure a auto refresh command
cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
cmd.CommandTarget = SDRAM.BANK;
cmd.AutoRefreshNumber = 2;
cmd.ModeRegisterDefinition = 0;
// send command
res |= HAL_SDRAM_SendCommand(SDRAM.P, &cmd, SDRAM_TIMEOUT);
// program the external memory mode register
cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
cmd.CommandTarget = SDRAM.BANK;
cmd.AutoRefreshNumber = 1;
cmd.ModeRegisterDefinition = tmp;
// send command
res |= HAL_SDRAM_SendCommand(SDRAM.P, &cmd, SDRAM_TIMEOUT);
// set the refresh rate counter
res |= HAL_SDRAM_ProgramRefreshRate(SDRAM.P, SDRAM_REFRESH_COUNT);
// result
return res;
}
5. LTDC
5.1. defined setting
#define EW_USE_DOUBLE_BUFFER 1
#define EW_DISPLAY_WIDTH 1024
#define EW_DISPLAY_HEIGHT 600
#define EW_FRAME_BUFFER_WIDTH 1024
#define EW_FRAME_BUFFER_HEIGHT 600
/* calculated addresses for framebuffer(s) */
#define SDRAM_BASE_ADDR 0xD0000000
#define EW_FRAME_BUFFER_ADDR SDRAM_BASE_ADDR
#define EW_FRAME_BUFFER_SIZE (EW_FRAME_BUFFER_WIDTH * EW_FRAME_BUFFER_HEIGHT * EW_FRAME_BUFFER_DEPTH)
#if EW_USE_DOUBLE_BUFFER == 1
/* locate double-buffer at the end of the last SDRAM bank - this ensures
that front/back-buffer are located within different banks of the SDRAM */
#define EW_DOUBLE_BUFFER_ADDR (SDRAM_BASE_ADDR + SDRAM_SIZE_BYTES - EW_FRAME_BUFFER_SIZE)
#define EW_DOUBLE_BUFFER_SIZE EW_FRAME_BUFFER_SIZE
5.2. LTDC configuration
/*******************************************************************************
* FUNCTION:
* EwBspDisplayInit
*
* DESCRIPTION:
* The function EwBspDisplayInit initializes the display hardware and returns
* the display parameter.
*
* ARGUMENTS:
* aGuiWidth,
* aGuiHeight - Size of the GUI in pixel.
* aDisplayInfo - Display info data structure.
*
* RETURN VALUE:
* Returns 1 if successful, 0 otherwise.
*
*******************************************************************************/
int EwBspDisplayInit(int aGuiWidth, int aGuiHeight, XDisplayInfo *aDisplayInfo) {
EW_UNUSED_ARG(aGuiWidth);
EW_UNUSED_ARG(aGuiHeight);
/* check and clean display info structure */
if (!aDisplayInfo)
return 0;
memset(aDisplayInfo, 0, sizeof(XDisplayInfo));
/* initialize given framebuffer */
EwZero((void *) EW_FRAME_BUFFER_ADDR, EW_FRAME_BUFFER_WIDTH * EW_FRAME_BUFFER_HEIGHT * EW_FRAME_BUFFER_DEPTH);
#if EW_USE_OPERATING_SYSTEM == 1
/* create the LCD update semaphore */
LcdUpdateSemaphore = EwBspOsSemaphoreCreate( 1, 1 );
#endif
/* Polarity configuration */
/* Initialize the horizontal synchronization polarity as active low */
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AH;
/* Initialize the vertical synchronization polarity as active low */
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AH;
/* Initialize the data enable polarity as active low */
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
/* Initialize the pixel clock polarity as input pixel clock */
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
// for some reason the display content is shifted.... ??? msy
#define SHIFT 1
/* Timing configuration for LCD */
/* Horizontal synchronization width = Hsync - 1 */
hltdc.Init.HorizontalSync = 108 - SHIFT;
/* Vertical synchronization height = Vsync - 1 */
hltdc.Init.VerticalSync = 13 - SHIFT;
/* Accumulated horizontal back porch = Hsync + HBP - 1 */
hltdc.Init.AccumulatedHBP = 108 + 106 - SHIFT;
/* Accumulated vertical back porch = Vsync + VBP - 1 */
hltdc.Init.AccumulatedVBP = 13 + 11 - SHIFT;
/* Accumulated active width = Hsync + HBP + Active Width - 1 */
hltdc.Init.AccumulatedActiveW = 108 + 106 + 1024 - SHIFT;
/* Accumulated active height = Vsync + VBP + Active Height - 1 */
hltdc.Init.AccumulatedActiveH = 13 + 11 + 600 - SHIFT;
/* Total width = Hsync + HBP + Active Width + HFP - 1 */
hltdc.Init.TotalWidth = 108 + 106 + 1024 + 106 - SHIFT;
/* Total height = Vsync + VBP + Active Height + VFP - 1 */
hltdc.Init.TotalHeigh = 13 + 11 + 600 + 11 - SHIFT;
/* Configure R,G,B component values for LCD background color */
hltdc.Init.Backcolor.Blue = 0;
hltdc.Init.Backcolor.Green = 0;
hltdc.Init.Backcolor.Red = 0;
hltdc.Instance = LTDC;
/* Layer1 Configuration */
LayerConfig.WindowX0 = 0;
LayerConfig.WindowX1 = EW_FRAME_BUFFER_WIDTH;
LayerConfig.WindowY0 = 0;
LayerConfig.WindowY1 = EW_FRAME_BUFFER_HEIGHT;
/* Pixel Format configuration: translate framebuffer color format into LTDC mode */
LayerConfig.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
/* Start Address will be set by Graphics Engine */
LayerConfig.FBStartAdress = (uint32_t) EW_FRAME_BUFFER_ADDR;
/* Alpha constant (255 totally opaque) */
LayerConfig.Alpha = 255;
/* Default Color configuration (configure A,R,G,B component values) */
LayerConfig.Alpha0 = 0;
LayerConfig.Backcolor.Blue = 0;
LayerConfig.Backcolor.Green = 0;
LayerConfig.Backcolor.Red = 0;
/* Configure blending factors */
LayerConfig.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
LayerConfig.BlendingFactor2 = LTDC_BLENDING_FACTOR1_PAxCA;
/* Configure the number of lines and number of pixels per line */
LayerConfig.ImageWidth = EW_FRAME_BUFFER_WIDTH;
LayerConfig.ImageHeight = EW_FRAME_BUFFER_HEIGHT;
/* Configure the LTDC */
if (HAL_LTDC_Init(&hltdc) != HAL_OK)
EwPrint("EwBspDisplayInit: Could not configure LTDC!\n");
/* Configure the Layer */
if (HAL_LTDC_ConfigLayer(&hltdc, &LayerConfig, LAYER_INDEX) != HAL_OK)
EwPrint("EwBspDisplayInit: Could not configure layer!\n");
#if EW_USE_OPERATING_SYSTEM == 1
/* initially take the LcdUpdate token for the first LCD update */
EwBspOsSemaphoreWait( LcdUpdateSemaphore, 1000 );
#endif
#if EW_USE_DOUBLE_BUFFER == 1
/* Configure the vsync */
if (HAL_LTDC_ProgramLineEvent(&hltdc, 0) != HAL_OK)
EwPrint("EwBspDisplayInit: Could not configure interrupt for vsync!\n");
#endif
/* return the current display configuration */
aDisplayInfo->FrameBuffer = (void *) EW_FRAME_BUFFER_ADDR;
aDisplayInfo->DoubleBuffer = (void *) EW_DOUBLE_BUFFER_ADDR;
aDisplayInfo->BufferWidth = EW_FRAME_BUFFER_WIDTH;
aDisplayInfo->BufferHeight = EW_FRAME_BUFFER_HEIGHT;
aDisplayInfo->DisplayWidth = EW_DISPLAY_WIDTH;
aDisplayInfo->DisplayHeight = EW_DISPLAY_HEIGHT;
#if EW_USE_DOUBLE_BUFFER == 1
aDisplayInfo->UpdateMode = EW_BSP_DISPLAY_UPDATE_NORMAL;
#else
aDisplayInfo->UpdateMode = EW_BSP_DISPLAY_UPDATE_PARTIAL;
#endif
return 1;
}
6. DMA2D
int EwBspGraphicsInit(uint32_t aDstColorMode) {
/* clear entire accelerator struct including layer configurations */
memset(&hdma2d, 0, sizeof(DMA2D_HandleTypeDef));
/* prepare configuration of the DMA2D graphics accelerator */
hdma2d.Instance = DMA2D;
hdma2d.Init.Mode = DMA2D_M2M;
hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB565;
hdma2d.Lock = HAL_UNLOCKED;
hdma2d.State = HAL_DMA2D_STATE_RESET;
TransferInProgress = 0;
/* initialize the DMA2D graphics accelerator */
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
return 0;
return 1;
}
6. Video
Help me.
Thank you.
Solved! Go to Solution.
2024-03-02 01:25 PM - edited 2024-03-03 10:45 PM
Dear @Kim KyungTack ,
It seems you already checked this application Note : https://www.st.com/resource/en/application_note/an4861-lcdtft-display-controller-ltdc-on-stm32-mcus-stmicroelectronics.pdf
few hints to try :
1) the color format seems 16b (RGB565) : to be confirmed (if yes this excludes 1KB crossing issue described in AN4861)
2) section 4.6.1 : Disable FMC bank1 if not used .
3) to reduce pixel clock from 51MHz to 40MHz or less to see what happens .
Please let us know if you progressed on such behavior .
Cheers,
STOne-32
2024-03-02 01:25 PM - edited 2024-03-03 10:45 PM
Dear @Kim KyungTack ,
It seems you already checked this application Note : https://www.st.com/resource/en/application_note/an4861-lcdtft-display-controller-ltdc-on-stm32-mcus-stmicroelectronics.pdf
few hints to try :
1) the color format seems 16b (RGB565) : to be confirmed (if yes this excludes 1KB crossing issue described in AN4861)
2) section 4.6.1 : Disable FMC bank1 if not used .
3) to reduce pixel clock from 51MHz to 40MHz or less to see what happens .
Please let us know if you progressed on such behavior .
Cheers,
STOne-32
2024-03-03 04:12 PM
Thank you. Since lowering the clock to 40Mhz, it works fine.
2024-03-04 05:04 AM
So Most probably it seems a Bandwidth optimization . Is that possible to have the same video with 40MHz Clock ?