0

I have connected a 800x480 pixel display via LTDC to a STM32H735G-DK discovery board. In principle it is running and showing the pictures correctly. The problem is, when putting the decoded picture into the double buffer, the currently shown picture flickers shortly. This picture is in the second buffer, which is not be written at the moment of decoding. You can see this in the following video: https://youtu.be/0S_rc7cHPf8

At the beginning the code is halted every time before the next JPEG is decoded. When running the decode it flickers. The changing of the shown double buffer definitely doesn't flicker. In the second half of the video, the code is running without debug breaks, so it is flickering more or less continuously.


Setup

  1. I get a JPEG via network, which is written to the Octo-SPI Flash memory.
  2. The JPEG is decoded with the given JPEG-decoder from: STM32Cube\Repository\STM32Cube_FW_H7_V1.11.1\Projects\STM32H735G-DK\Applications\LibJPEG\LibJPEG_Decoding The decoded picture is again stored in the Octo-SPI Flash memory.
static void decode()
{
    if (idx == 0 || idx > sizeof(buf))
    {
        return;
    }

    static struct jpeg_decompress_struct cinfo;
    /* This struct represents a JPEG error handler */
    static struct jpeg_error_mgr jerr;

    /* Decode JPEG Image */
    JSAMPROW buffer[2] = { 0 }; /* Output row buffer */
    uint32_t row_stride = 0; /* physical row width in image buffer */

    buffer[0] = _aucLine;

    /* Step 1: allocate and initialize JPEG decompression object */
    cinfo.err = jpeg_std_error(&jerr);

    /* Initialize the JPEG decompression object */
    jpeg_create_decompress(&cinfo);

    jpeg_mem_src(&cinfo, buf, idx);

    /* Step 3: read image parameters with jpeg_read_header() */
    jpeg_read_header(&cinfo, TRUE);

    /* Step 4: set parameters for decompression */
    cinfo.dct_method = JDCT_FLOAT;

    /* Step 5: start decompressor */
    jpeg_start_decompress(&cinfo);

    row_stride = IMAGE_WIDTH * 3;
    while (cinfo.output_scanline < cinfo.output_height) // During this loop the picture flickers
    {
        (void) jpeg_read_scanlines(&cinfo, buffer, 1);

        if (Jpeg_CallbackFunction(buffer[0], row_stride) != 0)
        {
            break;
        }
    }

    /* Step 6: Finish decompression */
    jpeg_finish_decompress(&cinfo);

    /* Step 7: Release JPEG decompression object */
    jpeg_destroy_decompress(&cinfo);
}

  1. After decoding BSP_LCD_Relaod(0, BSP_LCD_RELOAD_VERTICAL_BLANKING) gets called. By this, an interrupt will occur after VSYNC, so the LTDC-buffer is swapped to the second one, with the new drawn picture.
void HAL_LTDC_ReloadEventCallback(LTDC_HandleTypeDef *hltdc)
{
  extern uint32_t bufferIndex;
  bufferIndex ^= 1;
  BSP_LCD_SetLayerAddress(0, 0, bufferIndex ? LCD_LAYER_0_ADDRESS : LCD_LAYER_1_ADDRESS);
}
  1. The cycle begins again

This is the function called by the decode-function:

static uint8_t Jpeg_CallbackFunction(uint8_t* Row, uint32_t DataLength)
{
  static DMA2D_HandleTypeDef hdma2d_eval;
  
  offset = ((bufferIndex ? LCD_LAYER_1_ADDRESS : LCD_LAYER_0_ADDRESS) + (IMAGE_WIDTH * (IMAGE_HEIGHT - line_counter - 1) * 4));
  
  /* Configure the DMA2D Mode, Color Mode and output offset */
  hdma2d_eval.Init.Mode         = DMA2D_M2M_PFC;
  hdma2d_eval.Init.ColorMode    = DMA2D_OUTPUT_ARGB8888;
  hdma2d_eval.Init.OutputOffset = 0;
  hdma2d_eval.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;  /* No Output Alpha Inversion*/
  hdma2d_eval.Init.RedBlueSwap   = DMA2D_RB_SWAP;     /* No Output Red & Blue swap */
  
  /* Foreground Configuration */
  hdma2d_eval.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
  hdma2d_eval.LayerCfg[1].InputAlpha = 0xFF;
  hdma2d_eval.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB888;
  hdma2d_eval.LayerCfg[1].InputOffset = 0;
  
  hdma2d_eval.Instance = DMA2D;
  
  /* DMA2D Initialization */
  if(HAL_DMA2D_Init(&hdma2d_eval) == HAL_OK)
  {
    if(HAL_DMA2D_ConfigLayer(&hdma2d_eval, 1) == HAL_OK)
    {
      /*
       * As the decode is done by the CPU, a cache clean
       * is needed to ensure that the DMA2D will copy the correct data
       */
      SCB_CleanDCache_by_Addr((uint32_t*)Row, ROW_SIZE);
      if (HAL_DMA2D_Start(&hdma2d_eval, (uint32_t)Row, (uint32_t)offset, IMAGE_WIDTH, 1) == HAL_OK)
      {
        /* Polling For DMA transfer */
        HAL_DMA2D_PollForTransfer(&hdma2d_eval, 10);
      }
    }
  }
  line_counter--;
  return 0;
}

I don't get the cause of the problem. I definitly write to the correct buffer in the decode-function. After decoding (and before switching the buffer) the content of the display doesn't change. Only after calling BSP_LCD_Relaod(0, BSP_LCD_RELOAD_VERTICAL_BLANKING), the display does change to the current one. Maybe the Octo-SPI is too slow for storing the decoded picture at the same time the LTDC is loading the picture showing it on screen?

What could be the reason for this flickering? How can I investigate the cause of the flickering? What could I do against the flickering?


Update - problem solved! (Partly)

I did some measuring and found a 100 MHz display clock frequency. The lcd's datasheet recommends 33.3 MHz at maximum. Therefore I changed the clock configuration to 33.3 MHz:

__weak HAL_StatusTypeDef MX_LTDC_ClockConfig(LTDC_HandleTypeDef *hltdc)
{
  RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;

  /* LCD clock configuration */
  /* PLL3_VCO Input = HSE_VALUE/PLL3M = 25 MHz / 32 = 781.25 kHz */
  /* PLL3_VCO Output = PLL3_VCO Input * PLL3N = 781.25 kHz * 128 = 100 MHz */
  /* PLLLCDCLK = PLL3_VCO Output/PLL3R = 100 MHz / 3 = 33.3 MHz */
  /* LTDC clock frequency = PLLLCDCLK = ~33.3 MHz */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
    PeriphClkInitStruct.PLL3.PLL3M = 32;
    PeriphClkInitStruct.PLL3.PLL3N = 128;
    PeriphClkInitStruct.PLL3.PLL3P = 2;
    PeriphClkInitStruct.PLL3.PLL3Q = 2;
    PeriphClkInitStruct.PLL3.PLL3R = 3;
    PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_3;
    PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
    PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

  return HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
}

LCD timings

With this configuration I have no flickering anymore! Nice! :) But now the pictures get grainy and streaky: Grainy LCD I think this happens due to the really low refresh rate of only 21 Hz. If I roughly roll over: 33.3 MHz / 800 (pixel width) / 480 (pixel height) = 86 Hz. Of course, there is some overhead, so the real frequency is a bit lower than that. But 21 Hz is one fourth of my estimation.

Why do I have such a low refresh rate? How can I increase the refresh rate?


Update 2 - problem solved!

The vertical back porch was way too high. I calculated the TotalHeigh to get 60 Hz (Refresh Rate = DCLK/TotalWidth/TotalHeigh) and calculated the values AccumulatedVBP and AccumulatedActiveH with STM32CubeMX. Now I have the following Init:

__weak HAL_StatusTypeDef MX_LTDC_Init(LTDC_HandleTypeDef *hltdc, uint32_t Width, uint32_t Height)
{
    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;
    hltdc->Init.HorizontalSync = 0;
    hltdc->Init.VerticalSync = 0;
    hltdc->Init.AccumulatedHBP = 46;
    hltdc->Init.AccumulatedVBP = 156; // Was too high
    hltdc->Init.AccumulatedActiveW = 846;
    hltdc->Init.AccumulatedActiveH = 636;
    hltdc->Init.TotalWidth = 862;
    hltdc->Init.TotalHeigh = 643;
    hltdc->Init.Backcolor.Blue = 0;
    hltdc->Init.Backcolor.Green = 0;
    hltdc->Init.Backcolor.Red = 0;

    return HAL_LTDC_Init(hltdc);
}

Now I have exactly 60 Hz refresh rate! - Problem solved!

peter
  • 1
  • 2

0 Answers0