本帖最后由 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
|