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)
{
}
运行结果:
|