cancel
Showing results for 
Search instead for 
Did you mean: 

JPEG encoding issue when using DMA on STM32H7B3

ALamb.314
Associate II

with libjpeg or using hardware in polling, mode compression works fine.

but when using DMA image is getting corrupted

#include "jpeg_encode.h"
 
#include "jpeglib.h"
#include "jdata_conf.h"
 
// variables used for dma mode
uint32_t YCBCR_Size;
uint32_t YCBCR_Index;
uint32_t YCBCR_Packets;
uint32_t YCBCR_Packet_Size;
uint8_t *YCBCR_IMG;
uint8_t Encoded_Flag;
uint8_t DMA_Mode;
 
uint32_t JPEG_Size;
 
uint32_t JPEG_Encode_SW(uint8_t *img,        // pointer input rgb map
                        uint32_t img_x,      // image width
                        uint32_t img_y,      // image hight
                        uint8_t img_bytpp,   // bytes per pixel
                        uint8_t quality,     // out jpeg quality
                        uint8_t *jpg_out,    // where out jpeg is stored, must be sizes appropriately
                        uint32_t jpg_out_sz) // size of output buffer
{
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
 
  JSAMPROW row_pointer[1];
  uint32_t row_stride;
 
  cinfo.err = jpeg_std_error(&jerr);
 
  jpeg_create_compress(&cinfo);
  cinfo.image_width = img_x;
  cinfo.image_height = img_y;
 
  cinfo.input_components = 3;
  cinfo.in_color_space = JCS_RGB;
 
  jpeg_set_defaults(&cinfo);
  jpeg_set_quality(&cinfo, quality, TRUE);
 
  jpeg_mem_dest(&cinfo, &jpg_out, &jpg_out_sz);
 
  jpeg_start_compress(&cinfo, TRUE);
 
  row_stride = img_x * img_bytpp;
 
  while (cinfo.next_scanline < cinfo.image_height)
  {
    row_pointer[0] = &img[cinfo.next_scanline * row_stride];
    jpeg_write_scanlines(&cinfo, row_pointer, 1);
  }
 
  jpeg_finish_compress(&cinfo);
  jpeg_destroy_compress(&cinfo);
 
  return jpg_out_sz;
}
 
uint32_t JPEG_Encode_HW(JPEG_HandleTypeDef *hjpeg,
                        uint8_t *img,       // pointer input rgb map
                        uint32_t img_x,     // image width
                        uint32_t img_y,     // image hight
                        uint8_t img_bytpp,  // bytes per pixel
                        uint8_t quality,    // out jpeg quality
                        uint8_t *ycbcr_tmp, // temperory buffer for ycbcr conversion, must be sizes appropriately
                        uint8_t *jpg_out)   // where out jpeg is stored, must be sizes appropriately
{
  JPEG_ConfTypeDef Conf;
  JPEG_RGBToYCbCr_Convert_Function pRGBToYCbCr_Convert_Function;
 
  uint32_t ycbcr_mcu = 0;
  uint32_t ycbcr_size = 0;
  JPEG_Size = 0;
  DMA_Mode = 0;
  Encoded_Flag = 0;
 
  Conf.ImageWidth = img_x;
  Conf.ImageHeight = img_y;
  Conf.ChromaSubsampling = JPEG_420_SUBSAMPLING;
  Conf.ColorSpace = JPEG_YCBCR_COLORSPACE;
  Conf.ImageQuality = quality;
 
  // get the numbers of mcus and appropriate function to rgb to ycbcr
  JPEG_GetEncodeColorConvertFunc(&Conf, &pRGBToYCbCr_Convert_Function, &ycbcr_mcu);
 
  // convert rgb to ycbcr mcu in one go
  pRGBToYCbCr_Convert_Function(img, ycbcr_tmp, 0, (img_x * img_y * img_bytpp), &ycbcr_size);
 
  HAL_JPEG_ConfigEncoding(hjpeg, &Conf);
 
  // convert ycbcr mcus to jpeg in one go
  HAL_JPEG_Encode(hjpeg, ycbcr_tmp, ycbcr_size, jpg_out, (img_x * img_y * img_bytpp), 1000);
 
  // JPEG_Size is updated in HAL_JPEG_DataReadyCallback
  return JPEG_Size;
}
 
void JPEG_Encode_HW_DMA(JPEG_HandleTypeDef *hjpeg,
                        uint8_t *img,       // pointer input rgb map
                        uint32_t img_x,     // image width
                        uint32_t img_y,     // image hight
                        uint8_t img_bytpp,  // bytes per pixel
                        uint8_t quality,    // out jpeg quality
                        uint8_t *ycbcr_tmp, // temperory buffer for ycbcr conversion, must be sizes appropriately
                        uint8_t *jpg_out)   // where out jpeg is stored, must be sizes appropriately
{
  JPEG_ConfTypeDef Conf;
  JPEG_RGBToYCbCr_Convert_Function pRGBToYCbCr_Convert_Function;
 
  uint32_t ycbcr_mcu = 0;
  uint32_t ycbcr_size = 0;
  JPEG_Size = 0;
  DMA_Mode = 1;
  Encoded_Flag = 0;
 
  Conf.ImageWidth = img_x;
  Conf.ImageHeight = img_y;
  Conf.ChromaSubsampling = JPEG_420_SUBSAMPLING;
  Conf.ColorSpace = JPEG_YCBCR_COLORSPACE;
  Conf.ImageQuality = quality;
 
  // get the numbers of mcus and appropriate function to rgb to ycbcr
  JPEG_GetEncodeColorConvertFunc(&Conf, &pRGBToYCbCr_Convert_Function, &ycbcr_mcu);
 
  // convert rgb to ycbcr mcu in one go
  pRGBToYCbCr_Convert_Function(img, ycbcr_tmp, 0, (img_x * img_y * img_bytpp), &ycbcr_size);
 
  HAL_JPEG_ConfigEncoding(hjpeg, &Conf);
 
  YCBCR_Index = 0x00;
  YCBCR_Size = ycbcr_size;
  YCBCR_IMG = ycbcr_tmp;
  YCBCR_Packet_Size = 8 * 1024;
  YCBCR_Packets = YCBCR_Size / YCBCR_Packet_Size;
  YCBCR_Index++;
  YCBCR_IMG += YCBCR_Packet_Size;
 
  // feed ycbcr mcus to jpeg in blocks of YCBCR_Packet_Size
  HAL_JPEG_Encode_DMA(hjpeg, ycbcr_tmp, YCBCR_Packet_Size, jpg_out, 16 * 1024);
}
 
// poll encoding status if using dma mode
uint8_t JPEG_Get_Status(uint32_t *size)
{
  uint8_t tmp = Encoded_Flag;
  *size = JPEG_Size;
  Encoded_Flag = 0;
  return tmp;
}
//////////////////////////////////////// callbacks and ISRS ////////////////////////////////////////////
/**
  * @brief JPEG Get Data callback
  * @param hjpeg: JPEG handle pointer
  * @param NbEncodedData: Number of encoded (consummed) bytes from input buffer
  * @retval None
  */
void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbEncodedData)
{
  if (DMA_Mode)
  {
    if (YCBCR_Index == YCBCR_Packets)
    {
      YCBCR_Packet_Size = YCBCR_Size % YCBCR_Packet_Size;
    }
 
    // feed ycbcr mcus to jpeg in blocks of YCBCR_Packet_Size
    HAL_JPEG_ConfigInputBuffer(hjpeg, YCBCR_IMG, YCBCR_Packet_Size);
    YCBCR_Index++;
    YCBCR_IMG += YCBCR_Packet_Size;
 
    if (YCBCR_Index > YCBCR_Packets)
    {
      YCBCR_Index = 0x00;
      // if HAL_JPEG_Pause or HAL_JPEG_ConfigInputBuffer with zero length here then HAL_JPEG_DataReadyCallbackn will not be called
      HAL_JPEG_ConfigInputBuffer(hjpeg, YCBCR_IMG, 4);
    }
  }
}
 
/**
  * @brief JPEG Data Ready callback
  * @param hjpeg: JPEG handle pointer
  * @param pDataOut: pointer to the output data buffer
  * @param OutDataLength: length of output buffer in bytes
  * @retval None
  */
void HAL_JPEG_DataReadyCallback(JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)
{
  JPEG_Size = OutDataLength;
}
 
/**
  * @brief  JPEG Error callback
  * @param hjpeg: JPEG handle pointer
  * @retval None
  */
void HAL_JPEG_ErrorCallback(JPEG_HandleTypeDef *hjpeg)
{
  while (1)
  {
  }
}
 
/*
  * @brief JPEG Decode complete callback
  * @param hjpeg: JPEG handle pointer
  * @retval None
  */
void HAL_JPEG_EncodeCpltCallback(JPEG_HandleTypeDef *hjpeg)
{
  Encoded_Flag = 1;
}

0693W000006I7cbQAC.png0693W000006I7cWQAS.png0693W000006I7cRQAS.png

1 ACCEPTED SOLUTION

Accepted Solutions
frackers
Senior

Check that the memory you use for the DMA buffers is accessible to the JPG block. I had 6 months of grief finding this out on an F7 as by default only the first 128k is in the correct cache region

View solution in original post

2 REPLIES 2
frackers
Senior

Check that the memory you use for the DMA buffers is accessible to the JPG block. I had 6 months of grief finding this out on an F7 as by default only the first 128k is in the correct cache region

Thanks

got it working

I had to put

 SCB_CleanInvalidateDCache();

 SCB_InvalidateICache();

before dma call and removing this line "HAL_JPEG_ConfigInputBuffer(hjpeg, YCBCR_IMG, 4);" from HAL_JPEG_GetDataCallback