Double buffering: synchronizing LTDC with DMA2D or other method to eliminate the tear flicker
I am using a STM32F429BI module + 7" LCD RGB to display the amplifier settings and also a vu-meter.
https://it.aliexpress.com/item/1005002482177244.html
http://www.audiodesignguide.com/sw1/20240507_215200.mp4
I would like to increase the speed of refresh to eliminate the tear flicker of vu-meter using the Double buffering like described in this following doc (see Multiple buffering techniques such as the double buffering) or other methods, do you know how to modify my code ?
I am using this function to plot the pixel for vu-meter
void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t RGB_Code)
{
/* Write data value to all SDRAM memory */
if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565)
{ /* RGB565 format */
*(__IO uint16_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))) = (uint16_t)RGB_Code;
}
else
{ /* ARGB8888 format */
*(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) = RGB_Code;
}
}
this function to read the background of vu-meter to restore the pixel before plot a new value
uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos)
{
uint32_t ret = 0;
if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888)
{
/* Read data value from SDRAM memory */
// ret = *(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos)));
ret = *(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos)));
}
else if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888)
{
/* Read data value from SDRAM memory */
ret = (*(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))) & 0x00FFFFFF);
}
else if((hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88))
{
/* Read data value from SDRAM memory */
ret = *(__IO uint16_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos)));
}
else
{
/* Read data value from SDRAM memory */
ret = *(__IO uint8_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos)));
}
return ret;
}
and this configuration set
void StartDefaultTask(void const * argument)
{
MX_GPIO_Init();
MX_CRC_Init();
MX_DMA2D_Init();
MX_FMC_Init();
MX_LTDC_Init();
MX_TIM4_Init();
.....
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 15;
RCC_OscInitStruct.PLL.PLLN = 144;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 5;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
Error_Handler();
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
PeriphClkInitStruct.PLLSAI.PLLSAIN = 60;
PeriphClkInitStruct.PLLSAI.PLLSAIR = 2;
PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
}
static void MX_DMA2D_Init(void)
{
hdma2d.Instance = DMA2D;
hdma2d.Init.Mode = DMA2D_M2M;
hdma2d.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
hdma2d.Init.OutputOffset = 0;
hdma2d.LayerCfg[1].InputOffset = 0;
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
hdma2d.LayerCfg[1].InputAlpha = 0;
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
{
Error_Handler();
}
if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN DMA2D_Init 2 */
/* USER CODE END DMA2D_Init 2 */
}
static void MX_LTDC_Init(void)
{
/* USER CODE BEGIN LTDC_Init 0 */
/* USER CODE END LTDC_Init 0 */
LTDC_LayerCfgTypeDef pLayerCfg = {0};
/* USER CODE BEGIN LTDC_Init 1 */
/* USER CODE END LTDC_Init 1 */
hltdc.Instance = LTDC;
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
#define HBP 80
#define VBP 40
#define HSW 1
#define VSW 1
#define HFP 190
#define VFP 22
#define LCD_Width 800
#define LCD_Height 480
#define LCD_Pixels 800*480
#define LCD_MemoryAdd 0xD0000000
hltdc.Init.HorizontalSync = HSW - 1;
hltdc.Init.VerticalSync = VSW -1 ;
hltdc.Init.AccumulatedHBP = HBP + HSW -1;
hltdc.Init.AccumulatedVBP = VBP + VSW -1;
hltdc.Init.AccumulatedActiveW = LCD_Width + HSW + HBP -1;
hltdc.Init.AccumulatedActiveH = LCD_Height + VSW + VBP -1;
hltdc.Init.TotalWidth = LCD_Width + HSW + HBP + HFP - 1;
hltdc.Init.TotalHeigh = LCD_Height + VSW + VBP + VFP - 1;
hltdc.Init.Backcolor.Blue = 0;
hltdc.Init.Backcolor.Green = 0;
hltdc.Init.Backcolor.Red = 0;
if (HAL_LTDC_Init(&hltdc) != HAL_OK)
{
Error_Handler();
}
pLayerCfg.WindowX0 = 0;
pLayerCfg.WindowX1 = 799;
pLayerCfg.WindowY0 = 0;
pLayerCfg.WindowY1 = 479;
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888;
pLayerCfg.Alpha = 255;
pLayerCfg.Alpha0 = 0;
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
pLayerCfg.FBStartAdress = 0xD0000000;
pLayerCfg.ImageWidth = 800;
pLayerCfg.ImageHeight = 480;
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 0;
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN LTDC_Init 2 */
/* USER CODE END LTDC_Init 2 */
}
Yesterday evening I tried to use the following function with DMA to write the 3 x 190 pixels of vu-meter but the result is worst
void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length)
{
uint32_t Xaddress = 0;
/* Get the line address */
Xaddress = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos);
/* Write line */
LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, Length, 1, 0, DrawProp[ActiveLayer].TextColor);
}
