MCUXpresso_MIMXRT1052xxxxB/boards/evkbimxrt1050/display_examples/h264_freertos/display.c
2022-04-08 22:46:35 +08:00

295 lines
8.0 KiB
C

/*
* Copyright 2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_common.h"
#include "display_support.h"
#include "fsl_debug_console.h"
#include "fsl_pxp.h"
#include "fsl_fbdev.h"
#include "fsl_cache.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define ENABLE_DISPLAY 1
#define ENABLE_PXP_INTERRUPT 1
/*
* In this project, the framebuffer pixel format is set to RGB565. The input YUV420
* data is converted to RGB565, then sent to display controller.
*/
#ifdef DEMO_BUFFER_BYTE_PER_PIXEL
#undef DEMO_BUFFER_BYTE_PER_PIXEL
#endif
#define DEMO_BUFFER_BYTE_PER_PIXEL 2
#ifdef DEMO_BUFFER_PIXEL_FORMAT
#undef DEMO_BUFFER_PIXEL_FORMAT
#endif
#define DEMO_BUFFER_PIXEL_FORMAT kVIDEO_PixelFormatRGB565
/*******************************************************************************
* Prototypes
******************************************************************************/
#if ENABLE_DISPLAY
static int DEMO_InitPXP(void);
static int DEMO_InitFBDEV(void);
#endif
/*******************************************************************************
* Variables
******************************************************************************/
#if ENABLE_DISPLAY
#if !DEMO_BUFFER_FIXED_ADDRESS
AT_NONCACHEABLE_SECTION_ALIGN(
static uint8_t s_frameBuffer[DEMO_BUFFER_COUNT][DEMO_BUFFER_HEIGHT][DEMO_BUFFER_WIDTH][DEMO_BUFFER_BYTE_PER_PIXEL],
FRAME_BUFFER_ALIGN);
#define DEMO_BUFFER0_ADDR (uint32_t) s_frameBuffer[0]
#if DEMO_BUFFER_COUNT > 1
#define DEMO_BUFFER1_ADDR (uint32_t) s_frameBuffer[1]
#endif
#if DEMO_BUFFER_COUNT > 2
#define DEMO_BUFFER2_ADDR (uint32_t) s_frameBuffer[2]
#endif
#endif
static const uint32_t s_frameBufferAddress[DEMO_BUFFER_COUNT] = {DEMO_BUFFER0_ADDR,
#if DEMO_BUFFER_COUNT > 1
DEMO_BUFFER1_ADDR,
#endif
#if DEMO_BUFFER_COUNT > 2
DEMO_BUFFER2_ADDR
#endif
};
/* FBDEV */
static fbdev_t s_fbdev;
static fbdev_fb_info_t s_fbInfo;
/* PXP */
static pxp_output_buffer_config_t s_pxpOutputBufferConfig;
static pxp_ps_buffer_config_t s_pxpPsBufferConfig;
#if ENABLE_PXP_INTERRUPT
static SemaphoreHandle_t s_pxpCompleteSema;
#endif
#endif
/*******************************************************************************
* Code
******************************************************************************/
#if ENABLE_DISPLAY
#if ENABLE_PXP_INTERRUPT
void PXP_IRQHandler(void)
{
BaseType_t wake = pdFALSE;
if (0U != (kPXP_CompleteFlag & PXP_GetStatusFlags(PXP)))
{
PXP_ClearStatusFlags(PXP, kPXP_CompleteFlag);
(void)xSemaphoreGiveFromISR(s_pxpCompleteSema, &wake);
portYIELD_FROM_ISR(wake);
}
}
#endif
static int DEMO_InitPXP(void)
{
#if ENABLE_PXP_INTERRUPT
/* Semaphore */
s_pxpCompleteSema = xSemaphoreCreateBinary();
if (NULL == s_pxpCompleteSema)
{
return -1;
}
#endif
/* Initialize variables. */
memset(&s_pxpPsBufferConfig, 0, sizeof(s_pxpPsBufferConfig));
memset(&s_pxpOutputBufferConfig, 0, sizeof(s_pxpOutputBufferConfig));
s_pxpPsBufferConfig.pixelFormat = kPXP_PsPixelFormatYVU420;
s_pxpPsBufferConfig.swapByte = false,
s_pxpOutputBufferConfig.pixelFormat = kPXP_OutputPixelFormatRGB565;
s_pxpOutputBufferConfig.interlacedMode = kPXP_OutputProgressive;
s_pxpOutputBufferConfig.pitchBytes = (DEMO_BUFFER_WIDTH * DEMO_BUFFER_BYTE_PER_PIXEL);
/* Initialize hardware. */
PXP_Init(PXP);
PXP_SetProcessSurfaceBackGroundColor(PXP, 0U);
/* Disable AS. */
PXP_SetAlphaSurfacePosition(PXP, 0xFFFFU, 0xFFFFU, 0U, 0U);
PXP_SetCsc1Mode(PXP, kPXP_Csc1YCbCr2RGB);
PXP_EnableCsc1(PXP, true);
#if ENABLE_PXP_INTERRUPT
NVIC_SetPriority(PXP_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
EnableIRQ(PXP_IRQn);
PXP_EnableInterrupts(PXP, kPXP_CompleteInterruptEnable);
#endif
return 0;
}
static int DEMO_InitFBDEV(void)
{
void *buffer;
BOARD_PrepareDisplayController();
FBDEV_Open(&s_fbdev, &g_dc, 0);
FBDEV_GetFrameBufferInfo(&s_fbdev, &s_fbInfo);
s_fbInfo.bufInfo.pixelFormat = DEMO_BUFFER_PIXEL_FORMAT;
s_fbInfo.bufInfo.startX = DEMO_BUFFER_START_X;
s_fbInfo.bufInfo.startY = DEMO_BUFFER_START_Y;
s_fbInfo.bufInfo.width = DEMO_BUFFER_WIDTH;
s_fbInfo.bufInfo.height = DEMO_BUFFER_HEIGHT;
s_fbInfo.bufInfo.strideBytes = (DEMO_BUFFER_WIDTH * DEMO_BUFFER_BYTE_PER_PIXEL);
s_fbInfo.bufferCount = DEMO_BUFFER_COUNT;
for (uint8_t i = 0; i < DEMO_BUFFER_COUNT; i++)
{
s_fbInfo.buffers[i] = (void *)s_frameBufferAddress[i];
}
if (kStatus_Success != FBDEV_SetFrameBufferInfo(&s_fbdev, &s_fbInfo))
{
PRINTF("Set frame buffer info error\r\n");
return -1;
}
/* Set the first frame, it is shown when enabled. */
buffer = FBDEV_GetFrameBuffer(&s_fbdev, 0);
assert(buffer != NULL);
memset(buffer, 0, DEMO_BUFFER_WIDTH * DEMO_BUFFER_BYTE_PER_PIXEL * DEMO_BUFFER_HEIGHT);
FBDEV_SetFrameBuffer(&s_fbdev, buffer, 0);
FBDEV_Enable(&s_fbdev);
return 0;
}
#endif
int DEMO_InitDisplay(void)
{
#if ENABLE_DISPLAY
int ret;
ret = DEMO_InitFBDEV();
if (0 == ret)
{
ret = DEMO_InitPXP();
}
return ret;
#else
return 0;
#endif
}
void DEMO_DisplayFrame(uint16_t width,
uint16_t height,
const uint8_t *Y,
const uint8_t *U,
const uint8_t *V,
uint32_t Y_Stride,
uint32_t UV_Stride)
{
#if ENABLE_DISPLAY
void *buffer;
bool rotate = false;
static uint16_t oldInputWidth = 0U;
static uint16_t oldInputHeight = 0U;
uint16_t lcdWidth = s_fbInfo.bufInfo.width;
uint16_t lcdHeight = s_fbInfo.bufInfo.height;
DCACHE_CleanInvalidateByRange((uint32_t)Y, height * Y_Stride);
DCACHE_CleanInvalidateByRange((uint32_t)U, height * UV_Stride / 2);
DCACHE_CleanInvalidateByRange((uint32_t)V, height * UV_Stride / 2);
/* PS configure. */
s_pxpPsBufferConfig.bufferAddr = (uint32_t)Y;
s_pxpPsBufferConfig.bufferAddrU = (uint32_t)U;
s_pxpPsBufferConfig.bufferAddrV = (uint32_t)V;
s_pxpPsBufferConfig.pitchBytes = Y_Stride;
PXP_SetProcessSurfaceBufferConfig(PXP, &s_pxpPsBufferConfig);
/* Input frame size changed. */
if ((oldInputHeight != height) || (oldInputWidth != width))
{
PRINTF("Input Frame Size: %d x %d\r\n", width, height);
#if DEMO_BUFFER_HEIGHT > DEMO_BUFFER_WIDTH
rotate = (height < width);
#else
rotate = (height > width);
#endif
if (rotate)
{
s_pxpOutputBufferConfig.width = lcdHeight;
s_pxpOutputBufferConfig.height = lcdWidth;
PXP_SetRotateConfig(PXP, kPXP_RotateOutputBuffer, kPXP_Rotate90, kPXP_FlipDisable);
PXP_SetProcessSurfaceScaler(PXP, width, height, lcdHeight, lcdWidth);
PXP_SetProcessSurfacePosition(PXP, 0, 0, lcdHeight - 1, lcdWidth - 1);
}
else
{
s_pxpOutputBufferConfig.width = lcdWidth;
s_pxpOutputBufferConfig.height = lcdHeight;
PXP_SetProcessSurfaceScaler(PXP, width, height, lcdWidth, lcdHeight);
PXP_SetProcessSurfacePosition(PXP, 0, 0, lcdWidth - 1, lcdHeight - 1);
}
oldInputHeight = height;
oldInputWidth = width;
}
buffer = FBDEV_GetFrameBuffer(&s_fbdev, 0);
s_pxpOutputBufferConfig.buffer0Addr = (uint32_t)buffer;
PXP_SetOutputBufferConfig(PXP, &s_pxpOutputBufferConfig);
PXP_Start(PXP);
#if ENABLE_PXP_INTERRUPT
(void)xSemaphoreTake(s_pxpCompleteSema, portMAX_DELAY);
#else
while (0U == (kPXP_CompleteFlag & PXP_GetStatusFlags(PXP)))
{
}
PXP_ClearStatusFlags(PXP, kPXP_CompleteFlag);
#endif
FBDEV_SetFrameBuffer(&s_fbdev, buffer, 0);
#endif
}