打印
[STM32N6]

【STM32N6570-DK测评】jpeg硬解码并显示到LCD

[复制链接]
1018|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
STM32N6系列硬件上集成jpeg decoder和encoder,所以可以用此jpeg deocder来硬解码,免去libjpeg或者tjpgdec等软件jpeg解码库的移植,而且速度上基于硬件的jpeg解码肯定快,且占用资源少。

可能是STM32N6很新的缘故,STM32Cube_FW_N6自带的例子中只有jpeg解码(Projects/STM32N6570-DK/Examples/JPEG/JPEG_DecodingFromOSPI_DMA/),但无显示到LCD的动作,咱写点代码给他添上。

理论篇:
STM32N6的jpeg decoder解码输出是标准YCbCr格式,但要显示到LCD还需要转成RGB格式。因STM32Cube_FW_N6中STM32N6570-DK bsp中LCD默认采取RGB565格式,所以我们需要做一个YCbCr->RGB565的转换,这个转换可以由软件做,也可以由硬件做。幸运的是STM32N6的集成的DMA2D有这个转换功能,配置好DMA2D参数即可高效率转换。

实做篇:
充分利用N6的大sram
因N6有4.2MB的sram,而且物理地址连续,大可以充分利用起来,不过这里需要注意下有些SRAM默认是disable的,可能为省电的缘故,比如AXISRAM3\4\5\6默认是disable的。笔者使能它们的代码如下:
  RCC->MEMENSR = RCC_MEMENSR_AXISRAM3ENS |

                 RCC_MEMENSR_AXISRAM4ENS |

                 RCC_MEMENSR_AXISRAM5ENS |

                 RCC_MEMENSR_AXISRAM6ENS |

                 RCC_MEMENSR_CACHEAXIRAMENS;

  RAMCFG_SRAM3_AXI->CR &= ~RAMCFG_CR_SRAMSD;

  RAMCFG_SRAM4_AXI->CR &= ~RAMCFG_CR_SRAMSD;

  RAMCFG_SRAM5_AXI->CR &= ~RAMCFG_CR_SRAMSD;

  RAMCFG_SRAM6_AXI->CR &= ~RAMCFG_CR_SRAMSD;


LCD buffer地址
改动stm32n6570_discovery_conf.h中默认的LCD buffer的地址为AXISRAM3的基地址
#define LCD_LAYER_0_ADDRESS                 0x34200000U



MPU设置
上述地址空间按ARMV8M默认是cacheable地址,用于LCD buffer时cache无用,所以配置下MPU

  MPU_Region_InitTypeDef default_config = {0};
  MPU_Attributes_InitTypeDef attr_config = {0};
  uint32_t primask_bit = __get_PRIMASK();

  /* disable the MPU */
  HAL_MPU_Disable();
  /* create an attribute configuration for the MPU */
  attr_config.Attributes = INNER_OUTER(MPU_NOT_CACHEABLE);
  attr_config.Number = MPU_ATTRIBUTES_NUMBER0;
  HAL_MPU_ConfigMemoryAttributes(&attr_config);
  /* Create a non cacheable region */
  /*Normal memory type, code execution allowed */
  default_config.Enable = MPU_REGION_ENABLE;
  default_config.Number = MPU_REGION_NUMBER0;
  default_config.BaseAddress = 0x34200000;
  default_config.LimitAddress = 0x34270000;
  default_config.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  default_config.AccessPermission = MPU_REGION_ALL_RW;
  default_config.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  default_config.AttributesIndex = MPU_ATTRIBUTES_NUMBER0;
  HAL_MPU_ConfigRegion(&default_config);

  /* enable the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
  /* Exit critical section to lock the system and avoid any issue around MPU mechanisme */
  __set_PRIMASK(primask_bit);


JPED decoder -> LTDC pipeline关键代码
JPEG decoder -> DMA 搬运到sram -> DMA2D YCbCr RGB565转换-> LTDC pipeline关键代码:

  /* Initialize the LCD   */
  BSP_LCD_Init(0, LCD_ORIENTATION_LANDSCAPE);

  UTIL_LCD_SetFuncDriver(&LCD_Driver);
  UTIL_LCD_SetLayer(0);

  /* Get the LCD Width */
  BSP_LCD_GetXSize(0,&LCD_X_Size);
  BSP_LCD_GetYSize(0,&LCD_Y_Size);

  /* Display example brief   */
  LCD_BriefDisplay();

  HAL_Delay(1000);

  MX_HPDMA1_Init();
  MX_JPEG_Init();
  tickstart = HAL_GetTick();

  /*JPEG Decoding with DMA (Not Blocking ) Method */
  JPEG_Decode_DMA(&hjpeg, (uint32_t)image_320_240_jpg, IMAGE_320_240_JPG_SIZE, (uint32_t)
rawBuffer);

  /* Wait till end of JPEG decoding or exceed TimeOut*/
  while((Jpeg_HWDecodingEnd == 0) && ((HAL_GetTick() - tickstart) < 5000))
  {
  }

  if (Jpeg_HWDecodingEnd != 0)
  {
    BSP_LED_On(LED_GREEN);
  }
  else
  {
    BSP_LED_On(LED_RED);
  }
  /*##-5- Get JPEG Info  ###############################################*/
  HAL_JPEG_GetInfo(&hjpeg, &JPEG_Info);

  /*##-9- Copy RGB decoded Data to the display FrameBuffer  ############*/
  xPos = (LCD_X_Size - JPEG_Info.ImageWidth)/2;
  yPos = (LCD_Y_Size - JPEG_Info.ImageHeight)/2;

  DMA2D_CopyBuffer((uint32_t *)rawBuffer, (uint32_t *)LCD_LAYER_0_ADDRESS, xPos , yPos, JPEG_Info.ImageWidth, JPEG_Info.ImageHeight, JPEG_Info.ChromaSubsampling);

  /* Infinite loop */
  while (1)
  {
  }


运行结果:


使用特权

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

本版积分规则

42

主题

159

帖子

1

粉丝