cancel
Showing results for 
Search instead for 
Did you mean: 

DMA2D: incorrect transfer of JPEG image

Alex Gab
Associate III

Hello to everyone,

I'm working on displaying JPEG files using STM32H745BIT6 chip.

I successfully configured all peripherals (LTDC, DMA2D, HW JPEG decoder) and now I'm able to dislay JPEG data. At first JPEG decoder converts JPEG data to YCbCr data and then DMA2D converts that data to RGB and transmits it to the screen (1024x768).

Here's part of the code:

// JPEG HW decoding
JPEG_Decode(&hjpeg, (uint32_t)image_320_240_jpg, IMAGE_320_240_JPG_SIZE , (uint32_t)JPEG_OUTPUT_DATA_BUFFER);
 
// Waiting for the end of decoding
 while(Jpeg_HWDecodingEnd == 0);
 
// Getting JPEG data
 HAL_JPEG_GetInfo(&hjpeg, &JPEG_Info);
 
// Set the org of the image
 xPos = 0;
 yPos = 0;
 
// Send the image using DMA2D
 DMA2D_CopyBufferJPEG((uint32_t *)JPEG_OUTPUT_DATA_BUFFER, (uint32_t *)0xC2000000, xPos, yPos, JPEG_Info.ImageWidth, JPEG_Info.ImageHeight, JPEG_Info.ChromaSubsampling);

Here's the screen:


_legacyfs_online_stmicro_images_0693W00000bjqvqQAA.png 

The only problem is when X-coordinate of the image makes it to be out of the screen area, the "outer" part of the image is showing at the begining of the screen.

For example, if xPos == 800 then the screen is:


_legacyfs_online_stmicro_images_0693W00000bjqwKQAQ.png 

How to avoid this "tail drawing"?

I guess something is missing in DMA2D transfer function.

Here's the code:

void DMA2D_CopyBufferJPEG(uint32_t *pSrc, uint32_t *pDst, uint16_t x, uint16_t y, uint16_t xsize, uint16_t ysize, uint32_t ChromaSampling)
{
  uint32_t cssMode = LL_DMA2D_CSS_420, inputLineOffset = 0;
  uint32_t destination = 0;
  uint16_t LCD_X_Size;
 
  while (DMA2D->CR & DMA2D_CR_START);
 
  LCD_X_Size = 1024;
 
  if(ChromaSampling == JPEG_420_SUBSAMPLING)
  {
    cssMode = LL_DMA2D_CSS_420;
 
    inputLineOffset = xsize % 16;
    if(inputLineOffset != 0)
    {
      inputLineOffset = 16 - inputLineOffset;
    }
  }
  else if(ChromaSampling == JPEG_444_SUBSAMPLING)
  {
    cssMode = LL_DMA2D_CSS_444;
 
    inputLineOffset = xsize % 8;
    if(inputLineOffset != 0)
    {
      inputLineOffset = 8 - inputLineOffset;
    }
  }
  else if(ChromaSampling == JPEG_422_SUBSAMPLING)
  {
    cssMode = LL_DMA2D_CSS_422;
 
    inputLineOffset = xsize % 16;
    if(inputLineOffset != 0)
    {
      inputLineOffset = 16 - inputLineOffset;
    }
  }
 
  /*##-1- Configure the DMA2D Mode, Color Mode and output offset #############*/
  LL_DMA2D_SetMode(DMA2D, LL_DMA2D_MODE_M2M_PFC);
  LL_DMA2D_SetOutputColorMode(DMA2D, LL_DMA2D_OUTPUT_MODE_RGB565);
  LL_DMA2D_SetLineOffset(DMA2D, LCD_X_Size - xsize);
  LL_DMA2D_FGND_SetColorMode(DMA2D, LL_DMA2D_INPUT_MODE_YCBCR);
  LL_DMA2D_FGND_SetAlphaMode(DMA2D, LL_DMA2D_ALPHA_MODE_REPLACE);
  LL_DMA2D_FGND_SetAlpha(DMA2D, 0xFF);
  LL_DMA2D_FGND_SetLineOffset(DMA2D, inputLineOffset);
  LL_DMA2D_FGND_SetRBSwapMode(DMA2D, LL_DMA2D_RB_MODE_REGULAR);
  LL_DMA2D_FGND_SetAlphaInvMode(DMA2D, LL_DMA2D_ALPHA_REGULAR);
  LL_DMA2D_FGND_SetChrSubSampling(DMA2D, cssMode);
 
  destination = (uint32_t)pDst + ((y * LCD_X_Size) + x) * 2;
 
  LL_DMA2D_FGND_SetMemAddr(DMA2D, (uint32_t)pSrc);
  LL_DMA2D_SetOutputMemAddr(DMA2D, destination);
  LL_DMA2D_SetNbrOfPixelsPerLines(DMA2D, xsize);
  LL_DMA2D_SetNbrOfLines(DMA2D, ysize);
 
  LL_DMA2D_Start(DMA2D);
 
  while (DMA2D->CR & DMA2D_CR_START);
}

What am I doing wrong?

Thanks for your attention.

4 REPLIES 4
KDJEM.1
ST Employee

Hello @mrnukeab​ ,

Please make sure that the Layer Settings for the LTDC are well configured and precisely the Window Horizontal Stop equal to 1024.

For that I recommend you to take a look to the Example: creating a basic graphical application Section6.2 in AN4861.

I hope this help you!

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Alex Gab
Associate III

Hello, Kaouthar!

Thank you for the answer!

Here's my LTDC and DMA2D init functions for 1024x768 screen size and RGB565 mode generated from STM32CubeMX using LL:

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;
  hltdc.Init.HorizontalSync = 136;
  hltdc.Init.VerticalSync = 1;
  hltdc.Init.AccumulatedHBP = 296;
  hltdc.Init.AccumulatedVBP = 24;
  hltdc.Init.AccumulatedActiveW = 1320;
  hltdc.Init.AccumulatedActiveH = 792;
  hltdc.Init.TotalWidth = 1344;
  hltdc.Init.TotalHeigh = 807;
  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 = 1024;
  pLayerCfg.WindowY0 = 0;
  pLayerCfg.WindowY1 = 768;
  pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
  pLayerCfg.Alpha = 255;
  pLayerCfg.Alpha0 = 0;
  pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
  pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
  pLayerCfg.FBStartAdress = 0xC2000000;
  pLayerCfg.ImageWidth = 1024;
  pLayerCfg.ImageHeight = 768;
  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 */
 
}
static void MX_DMA2D_Init(void)
{
 
  /* USER CODE BEGIN DMA2D_Init 0 */
 
  /* USER CODE END DMA2D_Init 0 */
 
  /* Peripheral clock enable */
  LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_DMA2D);
 
  /* USER CODE BEGIN DMA2D_Init 1 */
 
  /* USER CODE END DMA2D_Init 1 */
  LL_DMA2D_SetMode(DMA2D, LL_DMA2D_MODE_M2M);
  LL_DMA2D_SetOutputColorMode(DMA2D, LL_DMA2D_OUTPUT_MODE_RGB565);
  LL_DMA2D_SetLineOffset(DMA2D, 0);
  LL_DMA2D_FGND_SetColorMode(DMA2D, LL_DMA2D_INPUT_MODE_RGB565);
  LL_DMA2D_FGND_SetAlphaMode(DMA2D, LL_DMA2D_ALPHA_MODE_NO_MODIF);
  LL_DMA2D_FGND_SetAlpha(DMA2D, 0);
  LL_DMA2D_FGND_SetLineOffset(DMA2D, 0);
  LL_DMA2D_FGND_SetRBSwapMode(DMA2D, LL_DMA2D_RB_MODE_REGULAR);
  LL_DMA2D_FGND_SetAlphaInvMode(DMA2D, LL_DMA2D_ALPHA_REGULAR);
  LL_DMA2D_FGND_SetChrSubSampling(DMA2D, LL_DMA2D_CSS_444);
  /* USER CODE BEGIN DMA2D_Init 2 */
 
  /* USER CODE END DMA2D_Init 2 */
 
}

Seems that Window Horizontal Stop is equal to 1024. But, somehow, the problem still exists...

The value in Layer1 WHSPPOS register is 1320 including horizontal back porch value.


_legacyfs_online_stmicro_images_0693W00000bkpUbQAI.pngMaybe this is the reason...

Thanks for your attention.

KDJEM.1
ST Employee

Hi @mrnukeab​ ,

Thank you for these details.

For example if the LTDC_BPCR register is configured to 0x000E0005 (AHBP[11:0] is 0xE) and the LTDC_AWCR register is configured to 0x028E01E5 (AAW[11:0] is 0x28E). To configure the horizontal position of a window size of 630x460, with horizontal start offset of 5 pixels in the active data area:

1. layer window first pixel, WHSTPOS[11:0], must be programmed to 0x14 (0xE+1+0x5)

2. layer window last pixel, WHSPPOS[11:0], must be programmed to 0x28A.

Thanks and best regards,

Kaouthar

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

snguy.1
Associate

Hi Alex Gab

Have you finished the jpeg decode and DMA2D project yet? I am working about them. I have a problem about using JPEG decode and DMA2D. You can fix for me, thanks?

Below is the process I follow:
Step 1: Convert Hex data of Image JPEG from file.h from flash memory
JPEG_Decode_DMA(&hjpeg, (uint32_t)image_320_240_jpg, IMAGE_320_240_JPG_SIZE , JPEG_OUTPUT_DATA_BUFFER);
while(Jpeg_HWDecodingEnd == 0){
}
Step 2: Use DMA2D convert YCBCR to RGB888
DMA2D_CopyBuffer((uint32_t *)JPEG_OUTPUT_DATA_BUFFER, (uint32_t *)LCD_FRAME_BUFFER, JPEG_Info.ImageWidth, JPEG_Info.ImageHeight);
while(Flag_Dma2d_complete==0){
}

Step 3: Send data of LCD_FRAME_BUFFER to computer by USART
unsigned char *p;
p = (unsigned char*)LCD_FRAME_BUFFER;
for(i=0; i<(JPEG_Info.ImageWidth*JPEG_Info.ImageHeight*3); i++)
{
HAL_UART_Transmit(&huart1, p+i, 1024, 5000);
i += 1024;
IWDG_ReloadCounter();
}
Step 4: Convert data give from USART to image rgb888 on QT5 tool and show on label and Image I have then:

snguy1_0-1703899081240.png

I don't know where is wrong, color of image false, all image as gray.


This is full my code:

DMA2D_HandleTypeDef hdma2d;

/* DMA2D init function */
void MX_DMA2D_Init(void)
{

/* USER CODE BEGIN DMA2D_Init 0 */

/* USER CODE END DMA2D_Init 0 */

/* USER CODE BEGIN DMA2D_Init 1 */

/* USER CODE END DMA2D_Init 1 */

hdma2d.Instance = DMA2D;
hdma2d.Init.Mode = DMA2D_M2M_PFC;
hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB888;
hdma2d.Init.OutputOffset = 0;
hdma2d.LayerCfg[1].InputOffset = 0;
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_YCBCR;
hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
hdma2d.LayerCfg[1].InputAlpha = 0;
hdma2d.LayerCfg[1].ChromaSubSampling = DMA2D_CSS_420;
hdma2d.XferCpltCallback = HAL_DMA2D_transfer_complete_callback;

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 */
}

void DMA2D_CopyBuffer(uint32_t *pSrc, uint32_t *pDst, uint16_t ImageWidth, uint16_t ImageHeight)
{
uint32_t xPos, yPos, destination;
/*##-1- calculate the destination transfer address ############*/
xPos = 0;
yPos = 0;
destination = (uint32_t)pDst + ((yPos * 320) + xPos) * 2;
/* copy the new decoded frame to the LCD Frame buffer*/

HAL_DMA2D_Start_IT(&hdma2d, (uint32_t)pSrc, destination, ImageWidth, ImageHeight);
HAL_DMA2D_PollForTransfer(&hdma2d, 1);
/* wait for the previous DMA2D transfer to ends */
}
void HAL_DMA2D_transfer_complete_callback (DMA2D_HandleTypeDef* dma2dHandle)
{
Flag_Dma2d_complete = 1;
}


int main(void)
{
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* Enable I-Cache---------------------------------------------------------*/
//SCB_EnableICache();

/* Enable D-Cache---------------------------------------------------------*/
//SCB_EnableDCache();

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */
// uint8_t *p;
uint32_t i;
/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_IWDG1_Init();
MX_TIM1_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
MX_SDMMC1_SD_Init();

MX_MDMA_Init();

MX_JPEG_Init();

MX_FATFS_Init();

MX_DMA2D_Init();
/* USER CODE BEGIN 2 */
//MX_MDMA_Init();
//MX_JPEG_Init();
MX_FATFS_Init();
HAL_TIM_Base_Start_IT(&htim1);
#if(USE_MP3_MODULE_DB)
Sd_ViewRootDir();
Sd_CreateNewFile();
Sd_ReadFileData();
Sd_CreateDir();
Sd_DeleteDirFile();
Sd_WriteFileTest();
if(MP3_Init()==true)
{
printf("MP3 init success\r\n");
if(MP3_Play("008.mp3")==true){
printf("MP3 play success\r\n");
}else{
printf("MP3 play error\r\n");
}
}else{
printf("MP3 init error\r\n");
}
#endif
JPEG_Decode_DMA(&hjpeg, (uint32_t)image_320_240_jpg, IMAGE_320_240_JPG_SIZE , JPEG_OUTPUT_DATA_BUFFER);
while(Jpeg_HWDecodingEnd == 0){
}

char M[128];
HAL_JPEG_GetInfo(&hjpeg, &JPEG_Info);
sprintf(M,"JPEG_Info %d %d %d %d %d\r\n",JPEG_Info.ChromaSubsampling, JPEG_Info.ColorSpace, JPEG_Info.ImageHeight, JPEG_Info.ImageWidth, JPEG_Info.ImageQuality);
UartPutString(M);

DMA2D_CopyBuffer((uint32_t *)JPEG_OUTPUT_DATA_BUFFER, (uint32_t *)LCD_FRAME_BUFFER, JPEG_Info.ImageWidth, JPEG_Info.ImageHeight);
while(Flag_Dma2d_complete==0){
}
UartPutString("Flag_Dma2d_complete\r\n");

unsigned char *p;
p = (unsigned char*)LCD_FRAME_BUFFER;
for(i=0; i<(JPEG_Info.ImageWidth*JPEG_Info.ImageHeight*3); i++)
{
HAL_UART_Transmit(&huart1, p+i, 1024, 5000);
i += 1024;
IWDG_ReloadCounter();
}

/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while(1)
{
#if(USE_MP3_MODULE_DB)
MP3_Feeder();
#endif
if(counter1ms >= 1000)
{
counter1ms = 0;
//printf("1s\r\n");
}
IWDG_ReloadCounter();
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}