打印
[STM32H7]

【STM32H745I-DISCO试用】8、jpeg硬件解码+DMA2D

[复制链接]
618|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 sujingliang 于 2025-1-31 09:52 编辑



1、MPU配置



对应代码:
外存只配了16MB,应该可以配32MB
void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x0;
  MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
  MPU_InitStruct.SubRegionDisable = 0x87;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  MPU_InitStruct.BaseAddress = 0xD0000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_16MB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}


2、FMC配置


对应代码:

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 SDRAM2 memory initialization sequence
  */
  hsdram2.Instance = FMC_SDRAM_DEVICE;
  /* hsdram2.Init */
  hsdram2.Init.SDBank = FMC_SDRAM_BANK2;
  hsdram2.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
  hsdram2.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
  hsdram2.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
  hsdram2.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
  hsdram2.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
  hsdram2.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
  hsdram2.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
  hsdram2.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
  hsdram2.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
  /* SdramTiming */
  SdramTiming.LoadToActiveDelay = 2;
  SdramTiming.ExitSelfRefreshDelay = 6;
  SdramTiming.SelfRefreshTime = 4;
  SdramTiming.RowCycleDelay = 6;
  SdramTiming.WriteRecoveryTime = 2;
  SdramTiming.RPDelay = 2;
  SdramTiming.RCDDelay = 2;

  if (HAL_SDRAM_Init(&hsdram2, &SdramTiming) != HAL_OK)
  {
    Error_Handler( );
  }

  /* USER CODE BEGIN FMC_Init 2 */

  /* USER CODE END FMC_Init 2 */
}
3、JPEG配置

对应代码:
static void MX_JPEG_Init(void)
{

  /* USER CODE BEGIN JPEG_Init 0 */

  /* USER CODE END JPEG_Init 0 */

  /* USER CODE BEGIN JPEG_Init 1 */

  /* USER CODE END JPEG_Init 1 */
  hjpeg.Instance = JPEG;
  if (HAL_JPEG_Init(&hjpeg) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN JPEG_Init 2 */

  /* USER CODE END JPEG_Init 2 */

}



4、DMA2D配置


关于LTDC配置略,与前文相同。

5、JPEG硬件解码

功能依次读取MMC中的1.jpg-18.jpg,通过JPEG_Decode_DMA解码,DMA2D_CopyBuffer显示在LCD。

jpeg文件缓存:
uint8_t jpeg_buffer[1024*1024] __attribute__((section(".bss.ARM.__at_0xD0200000")));

0xD0000000:LTDC显存地址
0xD0100000:解码后数据首地址
0xD0200000:解码前数据首地址
static void JPEG_hard_decode(uint8_t index)
{
                FRESULT res;
                uint32_t xPos = 0, yPos = 0;
                char image_file[50];
                memset(image_file,0,50);
                sprintf(image_file,"image%d.jpg",index);
               
                if(f_mount(&MMCFatFs, (TCHAR const*)MMCPath, 0) != FR_OK)
                {
                        printf("f_mount error\r\n");
                        return;
                }
               
                if(f_open(&MyFile, image_file, FA_READ) != FR_OK)
    {
                        printf("f_open jpeg error\r\n");
      return;
    }else{
                        printf("f_open jpeg ok\r\n");
                }
               
                if(FR_OK==f_read(&MyFile,jpeg_buffer,sizeof(jpeg_buffer),&jpeg_read_size))
                {
                        printf("f_read ok\r\n");
                        printf("jpeg_read_size:%d\r\n",jpeg_read_size);
                        JPEG_Decode_DMA(&hjpeg, 0xD0200000, jpeg_read_size , 0xD0100000);//(uint32_t)jpeg_buffer,(uint32_t)_onepic
                          while(Jpeg_HWDecodingEnd == 0)
                        {
                        }
                        HAL_JPEG_GetInfo(&hjpeg, &JPEG_Info);  
                        xPos = (LCD_RES_X - JPEG_Info.ImageWidth)/2;
                        yPos = (LCD_RES_Y - JPEG_Info.ImageHeight)/2;   
                       
                        printf("xPos:%d,yPos:%d,ImageWidth:%d,ImageHeight:%d,ChromaSubsampling:%d\r\n", xPos , yPos, JPEG_Info.ImageWidth, JPEG_Info.ImageHeight, JPEG_Info.ChromaSubsampling);
                        DMA2D_CopyBuffer((uint32_t *)0xD0100000, (uint32_t*)LCD_FRAME_BUFFER, xPos , yPos, JPEG_Info.ImageWidth, JPEG_Info.ImageHeight, JPEG_Info.ChromaSubsampling);
                       
                }
                else
                        printf("f_read error\r\n");
               
                f_close(&MyFile);
}


JPEG_Decode_DMA函数来自例程中decode_dma.c文件。

uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)
{
  JPEGSourceAddress =  FrameSourceAddress ;
  FrameBufferAddress = DestAddress;
  Input_frameIndex=0;
  Input_frameSize = FrameSize;
  
  Jpeg_HWDecodingEnd = 0;
  
  /* Start JPEG decoding with DMA method */
  HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,(uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);
  
  
  return 0;
  
}
DMA2D_CopyBuffer内容如下,也是源于例程
static void DMA2D_CopyBuffer(uint32_t *pSrc, uint32_t *pDst, uint16_t x, uint16_t y, uint16_t xsize, uint16_t ysize, uint32_t ChromaSampling)
{   
  
  uint32_t cssMode = DMA2D_CSS_420, inputLineOffset = 0;  
  uint32_t destination = 0;
        uint16_t timeout=0;
  
  if(ChromaSampling == JPEG_420_SUBSAMPLING)
  {
    cssMode = DMA2D_CSS_420;
   
    inputLineOffset = xsize % 16;
    if(inputLineOffset != 0)
    {
      inputLineOffset = 16 - inputLineOffset;
    }   
  }
  else if(ChromaSampling == JPEG_444_SUBSAMPLING)
  {
    cssMode = DMA2D_NO_CSS;
   
    inputLineOffset = xsize % 8;
    if(inputLineOffset != 0)
    {
      inputLineOffset = 8 - inputLineOffset;
    }   
  }
  else if(ChromaSampling == JPEG_422_SUBSAMPLING)
  {
    cssMode = DMA2D_CSS_422;
   
    inputLineOffset = xsize % 16;
    if(inputLineOffset != 0)
    {
      inputLineOffset = 16 - inputLineOffset;
    }      
  }  
  
  /*##-1- Configure the DMA2D Mode, Color Mode and output offset #############*/
  hlcd_dma2d.Init.Mode         = DMA2D_M2M_PFC;
  hlcd_dma2d.Init.ColorMode    = DMA2D_OUTPUT_ARGB8888;
  hlcd_dma2d.Init.OutputOffset = LCD_RES_X - xsize;
  hlcd_dma2d.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;  /* No Output Alpha Inversion*/  
  hlcd_dma2d.Init.RedBlueSwap   = DMA2D_RB_REGULAR;     /* No Output Red & Blue swap  DMA2D_RB_SWAP*/  
  
  /*##-2- DMA2D Callbacks Configuration ######################################*/
  hlcd_dma2d.XferCpltCallback  = NULL;
  
  /*##-3- Foreground Configuration ###########################################*/
  hlcd_dma2d.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
  hlcd_dma2d.LayerCfg[1].InputAlpha = 0xFF;
  hlcd_dma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_YCBCR;
  hlcd_dma2d.LayerCfg[1].ChromaSubSampling = DMA2D_NO_CSS;//cssMode;
  hlcd_dma2d.LayerCfg[1].InputOffset = inputLineOffset;
  hlcd_dma2d.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR; /* No ForeGround Red/Blue swap */
  hlcd_dma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; /* No ForeGround Alpha inversion */  
  
  hlcd_dma2d.Instance          = DMA2D;
  
  /*##-4- DMA2D Initialization     ###########################################*/
  HAL_DMA2D_Init(&hlcd_dma2d);
  HAL_DMA2D_ConfigLayer(&hlcd_dma2d, 1);
  
  /*##-5-  copy the new decoded frame to the LCD Frame buffer ################*/
  //BSP_LCD_GetXSize(0, &LCD_X_Size);
  destination = (uint32_t)pDst + ((y * LCD_RES_X) + x) * 4;

        SCB_CleanDCache_by_Addr((uint32_t*)pSrc, xsize*ysize*3);
  HAL_DMA2D_Start(&hlcd_dma2d, (uint32_t)pSrc, destination, xsize, ysize);
  HAL_DMA2D_PollForTransfer(&hlcd_dma2d, 25);  /* wait for the previous DMA2D transfer to ends */
        while((__HAL_DMA2D_GET_FLAG(&hlcd_dma2d,DMA2D_FLAG_TC)==0)&&(timeout<0X5000))//等待DMA2D完成
        {
                timeout++;
        }
}
jpeg硬件解码后的数据格式为YCBCR,经过DMA2D转换为ARGB8888

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

49

主题

97

帖子

0

粉丝