问题现象 客户正在开发的项目想使用Crank[1]做LCD GUI界面,所以使用MIMXRT1050开发板和SDK library提供的Crank工程做功能验证与评估,在此过程中,他们注意到显示屏(RK043FN02H-CT)最左上角的(0,0)像素点显示为白色或者绿色(如下图所示),并且这个现象在测试Coffee Machine和Home Controls工程时都有复现,但并未出现在LVGL和emWin相关的工程中,所以客户怀疑此现象与硬件无关,猜测与SDK library中的PXP驱动有关。
图 1 问题分析与解决小编根据客户的描述复现了上述问题现象,并在经过如下测试步骤后,基本认同客户的猜测,认为问题与硬件设计无关,并在与AE team沟通后,确认问题现象确与PXP驱动相关,导致gr_generic_display_update()函数更新LCD时,数组值有错码。 - 降低LCD的DCLK频率
- 采用更稳定的外置电源供电
- 在IAR、MCUXpresso都有复现问题现象
解决方式有两种(如下图所示),第一种为使能ping-pong模式的双buffer缓存机制,以空间换时间,交替将显示数据传给LCD,这样的话,可以舍弃PXP模块,第二种方法是在原有程序基础上,修改PXP驱动,代码修改量相对较小。
图 2 修改后代码如下所示,允许开发者可以通过宏 #define APP_USE_PXP x 自主选择上述两种解决方式的任何一种。 - #define APP_USE_PXP 1
- /*
- * Configure the PXP block to handle the framebuffer transfer in hardware.
- *
- * We will assume 16bit RGB565 based framebuffer
- * - The LCD peripheral is setup to use eLCDIF_Buffer[0]
- * - Storyboard is configured to render single buffer, eLCDIF_Buffer[1]
- * - The PXP will be configured to transfer from eLCDIF_Buffer[1] to eLCDIF_Buffer[0]
- */
- static void APP_InitPxp(void)
- {
- PXP_Init(APP_PXP);
- /* PS configure. */
- const pxp_ps_buffer_config_t psBufferConfig = {
- .pixelFormat = kPXP_PsPixelFormatRGB565,
- .swapByte = false,
- .bufferAddr = (uint32_t)eLCDIF_Buffer[1],
- .bufferAddrU = 0U,
- .bufferAddrV = 0U,
- .pitchBytes = APP_IMG_WIDTH * APP_BPP,
- };
- PXP_SetProcessSurfaceBackGroundColor(APP_PXP, 0x1f);
- PXP_SetProcessSurfaceBufferConfig(APP_PXP, &psBufferConfig);
- PXP_SetProcessSurfacePosition(APP_PXP, 0, 0, APP_IMG_WIDTH, APP_IMG_HEIGHT);
- /* Disable AS. */
- PXP_SetAlphaSurfacePosition(APP_PXP, 0xFFFFU, 0xFFFFU, 0U, 0U);
- /* Output config. */
- outputBufferConfig.pixelFormat = kPXP_OutputPixelFormatRGB565;
- outputBufferConfig.interlacedMode = kPXP_OutputProgressive;
- outputBufferConfig.buffer0Addr = (uint32_t)eLCDIF_Buffer[0];
- outputBufferConfig.buffer1Addr = 0U;
- outputBufferConfig.pitchBytes = APP_IMG_WIDTH * APP_BPP;
- outputBufferConfig.width = APP_IMG_WIDTH;
- outputBufferConfig.height = APP_IMG_HEIGHT;
- PXP_SetOutputBufferConfig(APP_PXP, &outputBufferConfig);
- /* Disable CSC1, it is enabled by default. */
- PXP_EnableCsc1(APP_PXP, false);
- /* Process 16x16 pixel blocks - Note: make sure this is appropriate for the display geometry */
- PXP_SetProcessBlockSize(APP_PXP, kPXP_BlockSize16);
- }
- int
- gr_generic_display_init(gr_generic_display_info_t *info) {
- BOARD_InitLcdifPixelClock();
- /* enable backlight */
- BOARD_InitLcd();
- info->num_layers = 1;
- info->layer_info = &main_layer;
- #if APP_USE_PXP
- main_layer.num_buffers = 1; // Single render buffer for Storyboard
- main_layer.buffer[0] = (void *)eLCDIF_Buffer[1];
- #else
- main_layer.num_buffers = 2; // double (ping-pong) render buffers for Storyboard
- main_layer.buffer[0] = (void *)eLCDIF_Buffer[0];
- main_layer.buffer[1] = (void *)eLCDIF_Buffer[1];
- #endif
- main_layer.render_format = GR_RENDER_FMT_RGB565;
- main_layer.width = (uint16_t)APP_IMG_WIDTH;;
- main_layer.height = (uint16_t)APP_IMG_HEIGHT;
- main_layer.stride = (uint16_t)(main_layer.width * GR_RENDER_FMT_BYTESPP(main_layer.render_format));
- ELCDIF_RgbModeInit(APP_ELCDIF, &eLCDIF_rgbConfig);
- #if APP_USE_PXP
- /* configure PXP for hardware assisted framebuffer transfer */
- APP_InitPxp();
- #else
- /* Enable interrupt LCDIF_IRQn request in the NVIC. */
- EnableIRQ(LCDIF_IRQn);
- /* Enable interrupts */
- ELCDIF_EnableInterrupts(ELCDIF_PERIPHERAL, (kELCDIF_CurFrameDoneInterruptEnable | kELCDIF_TxFifoUnderflowInterruptEnable));
- #endif
- ELCDIF_SetNextBufferAddr(APP_ELCDIF, (uint32_t)eLCDIF_Buffer[0]);
- ELCDIF_RgbModeStart(APP_ELCDIF);
- return 0;
- }
- int
- gr_generic_display_update(const gr_generic_display_info_t *info) {
- #if APP_USE_PXP
- /* invalidate cache on the buffer about to be being written to LCD by pxp*/
- DCACHE_CleanInvalidateByRange((uint32_t)info->layer_info[0].buffer[info->layer_info[0].buffer_draw_index], APP_IMG_HEIGHT * APP_IMG_WIDTH * GR_RENDER_FMT_BYTESPP(info->layer_info[0].render_format) );
- /* Start PXP. */
- PXP_Start(APP_PXP);
- /* Wait for process complete. */
- while (!(kPXP_CompleteFlag & PXP_GetStatusFlags(APP_PXP))) {}
- PXP_ClearStatusFlags(APP_PXP, kPXP_CompleteFlag);
- #else
- /* invalidate cache on the buffer about to be being written to LCD */
- DCACHE_CleanInvalidateByRange((uint32_t)info->layer_info[0].buffer[info->layer_info[0].buffer_draw_index], APP_IMG_HEIGHT * APP_IMG_WIDTH * GR_RENDER_FMT_BYTESPP(info->layer_info[0].render_format) );
- s_frame_done = false;
- ELCDIF_SetNextBufferAddr(APP_ELCDIF, (uint32_t)info->layer_info[0].buffer[info->layer_info[0].buffer_draw_index]);
- while(s_frame_done == false) {}
- #endif
- return 0;
- }
复制代码欢迎留言和我分享你的疑惑和见解 ,也欢迎收藏或转发 [1]Crank: https://www.cranksoftware.com/
|