本帖最后由 南来之风 于 2025-3-10 11:05 编辑
本实验展示了如何使用硬件JPEG解码器解码存储在内部Flash中的JPGE图片,解码后的图片格式为YCbCr。然后使用DMA2D把这种格式转换为ARGB888,之后显示在LCD上。
首先配置系统时钟:
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
HAL_StatusTypeDef ret = HAL_OK;
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 5;
RCC_OscInitStruct.PLL.PLLN = 160;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLQ = 4;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
if(ret != HAL_OK)
{
Error_Handler();
}
/* Select PLL as system clock source and configure bus clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | \
RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
if(ret != HAL_OK)
{
Error_Handler();
}
/*
Note : The activation of the I/O Compensation Cell is recommended with communication interfaces
(GPIO, SPI, FMC, QSPI ...) when operating at high frequencies(please refer to product datasheet)
The I/O Compensation Cell activation procedure requires :
- The activation of the CSI clock
- The activation of the SYSCFG clock
- Enabling the I/O Compensation Cell : setting bit[0] of register SYSCFG_CCCSR
*/
/*activate CSI clock mondatory for I/O Compensation Cell*/
__HAL_RCC_CSI_ENABLE() ;
/* Enable SYSCFG clock mondatory for I/O Compensation Cell */
__HAL_RCC_SYSCFG_CLK_ENABLE() ;
/* Enables the I/O Compensation Cell */
HAL_EnableCompensationCell();
}
初始化JPEG解码器:HAL_JPEG_Init(&JPEG_Handle);
HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)
{
/* These are the sample quantization tables given in JPEG spec ISO/IEC 10918-1 standard , section K.1. */
static const uint8_t JPEG_LUM_QuantTable[JPEG_QUANT_TABLE_SIZE] =
{
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
static const uint8_t JPEG_CHROM_QuantTable[JPEG_QUANT_TABLE_SIZE] =
{
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
/* Check the JPEG handle allocation */
if (hjpeg == NULL)
{
return HAL_ERROR;
}
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
if (hjpeg->State == HAL_JPEG_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hjpeg->Lock = HAL_UNLOCKED;
hjpeg->InfoReadyCallback = HAL_JPEG_InfoReadyCallback; /* Legacy weak InfoReadyCallback */
hjpeg->EncodeCpltCallback = HAL_JPEG_EncodeCpltCallback; /* Legacy weak EncodeCpltCallback */
hjpeg->DecodeCpltCallback = HAL_JPEG_DecodeCpltCallback; /* Legacy weak DecodeCpltCallback */
hjpeg->ErrorCallback = HAL_JPEG_ErrorCallback; /* Legacy weak ErrorCallback */
hjpeg->GetDataCallback = HAL_JPEG_GetDataCallback; /* Legacy weak GetDataCallback */
hjpeg->DataReadyCallback = HAL_JPEG_DataReadyCallback; /* Legacy weak DataReadyCallback */
if (hjpeg->MspInitCallback == NULL)
{
hjpeg->MspInitCallback = HAL_JPEG_MspInit; /* Legacy weak MspInit */
}
/* Init the low level hardware */
hjpeg->MspInitCallback(hjpeg);
}
#else
if (hjpeg->State == HAL_JPEG_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hjpeg->Lock = HAL_UNLOCKED;
/* Init the low level hardware : GPIO, CLOCK */
HAL_JPEG_MspInit(hjpeg);
}
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */
/* Change the JPEG state */
hjpeg->State = HAL_JPEG_STATE_BUSY;
/* Start the JPEG Core*/
__HAL_JPEG_ENABLE(hjpeg);
/* Stop the JPEG encoding/decoding process*/
hjpeg->Instance->CONFR0 &= ~JPEG_CONFR0_START;
/* Disable All Interrupts */
__HAL_JPEG_DISABLE_IT(hjpeg, JPEG_INTERRUPT_MASK);
/* Flush input and output FIFOs*/
hjpeg->Instance->CR |= JPEG_CR_IFF;
hjpeg->Instance->CR |= JPEG_CR_OFF;
/* Clear all flags */
__HAL_JPEG_CLEAR_FLAG(hjpeg, JPEG_FLAG_ALL);
/* init default quantization tables*/
hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);
hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);
hjpeg->QuantTable2 = NULL;
hjpeg->QuantTable3 = NULL;
/* init the default Huffman tables*/
if (JPEG_Set_HuffEnc_Mem(hjpeg) != HAL_OK)
{
hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;
return HAL_ERROR;
}
/* Enable header processing*/
hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;
/* Reset JpegInCount and JpegOutCount */
hjpeg->JpegInCount = 0;
hjpeg->JpegOutCount = 0;
/* Change the JPEG state */
hjpeg->State = HAL_JPEG_STATE_READY;
/* Reset the JPEG ErrorCode */
hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;
/*Clear the context filelds*/
hjpeg->Context = 0;
/* Return function status */
return HAL_OK;
}
初始化配置LCD BSP_LCD_Init(0, LCD_ORIENTATION_LANDSCAPE);
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] Initializes the LCD in default mode.
* @param Instance LCD Instance
* @param Orientation LCD_ORIENTATION_LANDSCAPE
* @retval BSP status
*/
int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation)
{
return BSP_LCD_InitEx(Instance, Orientation, LTDC_PIXEL_FORMAT_ARGB8888, LCD_DEFAULT_WIDTH, LCD_DEFAULT_HEIGHT);
}
调用JPEGE_Decode_DMA解码JPEG图片
JPEG_Decode_DMA(&JPEG_Handle, (uint32_t)image_320_240_jpg, IMAGE_320_240_JPG_SIZE , JPEG_OUTPUT_DATA_BUFFER);
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] Decode_DMA
* @param hjpeg: JPEG handle pointer
* @param FrameSourceAddress : video buffer address.
* @param DestAddress : YCbCr destination Frame Buffer Address.
* @retval None
*/
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;
}
调用HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info); 来获取JPEG图片信息。
/**
* @brief Extract the image configuration from the JPEG header during the decoding
* @param hjpeg pointer to a JPEG_HandleTypeDef structure that contains
* the configuration information for JPEG module
* @param pInfo pointer to a JPEG_ConfTypeDef structure that contains
* The JPEG decoded header information
* @retval HAL status
*/
HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
{
uint32_t yblockNb;
uint32_t cBblockNb;
uint32_t cRblockNb;
/* Check the JPEG handle allocation */
if ((hjpeg == NULL) || (pInfo == NULL))
{
return HAL_ERROR;
}
/*Read the conf parameters */
if ((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
{
pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;
}
else if ((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0UL)
{
pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;
}
else if ((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)
{
pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;
}
else
{
return HAL_ERROR;
}
pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000UL) >> 16;
pInfo->ImageWidth = (hjpeg->Instance->CONFR3 & 0xFFFF0000UL) >> 16;
if ((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))
{
yblockNb = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;
cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;
cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;
if ((yblockNb == 1UL) && (cBblockNb == 0UL) && (cRblockNb == 0UL))
{
pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/
}
else if ((yblockNb == 0UL) && (cBblockNb == 0UL) && (cRblockNb == 0UL))
{
pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
}
else if ((yblockNb == 3UL) && (cBblockNb == 0UL) && (cRblockNb == 0UL))
{
pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;
}
else /*Default is 4:4:4*/
{
pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
}
}
else
{
pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
}
pInfo->ImageQuality = JPEG_GetQuality(hjpeg);
/* Return function status */
return HAL_OK;
}
[size=13.3333px]调用DMA2D转换图片格式: DMA2D_CopyBuffer((uint32_t *)JPEG_OUTPUT_DATA_BUFFER, (uint32_t *)LCD_FRAME_BUFFER, xPos , yPos, JPEG_Info.ImageWidth, JPEG_Info.ImageHeight, JPEG_Info.ChromaSubsampling);
[size=13.3333px]
/**
* @brief Copy the Decoded image to the display Frame buffer.
* @param pSrc: Pointer to source buffer
* @param pDst: Pointer to destination buffer
* @param x: destination Horizontal offset.
* @param y: destination Vertical offset.
* @param xsize: image width
* @param ysize: image Height
* @param ChromaSampling : YCbCr Chroma sampling : 4:2:0, 4:2:2 or 4:4:4
* @retval None
*/
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;
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 #############*/
DMA2D_Handle.Init.Mode = DMA2D_M2M_PFC;
DMA2D_Handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
DMA2D_Handle.Init.OutputOffset = LCD_X_Size - xsize;
DMA2D_Handle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA; /* No Output Alpha Inversion*/
DMA2D_Handle.Init.RedBlueSwap = DMA2D_RB_REGULAR; /* No Output Red & Blue swap */
/*##-2- DMA2D Callbacks Configuration ######################################*/
DMA2D_Handle.XferCpltCallback = NULL;
/*##-3- Foreground Configuration ###########################################*/
DMA2D_Handle.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
DMA2D_Handle.LayerCfg[1].InputAlpha = 0xFF;
DMA2D_Handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_YCBCR;
DMA2D_Handle.LayerCfg[1].ChromaSubSampling = cssMode;
DMA2D_Handle.LayerCfg[1].InputOffset = inputLineOffset;
DMA2D_Handle.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR; /* No ForeGround Red/Blue swap */
DMA2D_Handle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; /* No ForeGround Alpha inversion */
DMA2D_Handle.Instance = DMA2D;
/*##-4- DMA2D Initialization ###########################################*/
HAL_DMA2D_Init(&DMA2D_Handle);
HAL_DMA2D_ConfigLayer(&DMA2D_Handle, 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_X_Size) + x) * 4;
HAL_DMA2D_Start(&DMA2D_Handle, (uint32_t)pSrc, destination, xsize, ysize);
HAL_DMA2D_PollForTransfer(&DMA2D_Handle, 25); /* wait for the previous DMA2D transfer to ends */
}
[size=13.3333px]解码后的图片展示:
[size=13.3333px]
附python代码把本地jpeg图片转换成hex格式:
from PIL import Image
import binascii
import re
def jpg_to_hex(file_path):
# 打开图像
with open(file_path, 'rb') as image_file:
# 读取文件的二进制数据
binary_data = image_file.read()
# 将二进制数据转换为十六进制
hex_data = binascii.hexlify(binary_data)
#return hex_data
# 转换为字符串
hex_string = hex_data.decode('utf-8')
return hex_string
# 示例用法
file_path = 'IMG320240.jpg'
hex_representation = jpg_to_hex(file_path)
#print(hex_representation)
split_str = [hex_representation[i:i+2] for i in range(0, len(hex_representation), 2)]
print(split_str)
|
|