一、开发环境
1.TencentOS物联网开发套件,MCU为RT1060
2.IDE:MCUXpresso v11.4.1
3.屏幕为微雪4.3寸IPS屏幕,RGB888接口
二、使用MCUXpreso的配置工具
1.利用IDE的功能,从SDK中导入例程hello_world,作为程序基本框架。
2.打开IDE配置工具中的外设页面。
3.在左侧外设中添加LCDIF,打开外设LCDIF的设置。
RGB mode initialization部分根据屏幕的参数来由用户配置,包括屏幕像素帧率等参数。
在途中可以看到IDE报了一个warning。因为根据像素点和帧率等参数计算出来的LCD控制器时钟与实际时钟有差别,实际时钟是由硬件决定的,无法配置得和用户设计的参数一模一样,因此IDE会产生一个警告信息。该警告信息不影响屏幕正常工作。图中也可以看到我们设计的帧率是60Hz,但按照目前的时钟配置,实际帧率应为64Hz。
下部分Signals polarity是LCD控制信号的极性,根据屏幕的接口来设置。
值得注意的是,LCD data bus即LCD数据总线的格式中,RGB888格式有两种,一种是未经过打包的,占用32bits的格式,另一种是舍弃了最高8位的24bits格式。这个格式一定要和自己编写的程序对应起来,否则屏幕显示会出错。
LCDIF_Buffer是显存变量,工具会以此为名称开辟一个内存空间。用户可以修改LCDIF_Buffer中的值来显示自己想要的内容。
记得勾选上那个start RGB mode,否则需要在用户程序中加上开启RGB模式的代码。
最下面的配置内容与LCD控制器的中断有关。在该程序中,我开启了帧传输完成的中断。LCDIF_IRQn是我们需要重写的中断函数。
按照以上配置后,点击更新代码,会在工程目录中增加peripheral.c和.h文件,在其中完成了LCD的初始化工作。
三、程序代码
打开peripheral源文件和头文件,看下官方配置工具为我们完成了哪些工作。(文章中只展现出部分代码)
//peripheral.c
const elcdif_rgb_mode_config_t LCDIF_rgbConfig = {
.panelWidth = LCDIF_PANEL_WIDTH,
.panelHeight = LCDIF_PANEL_HEIGHT,
.hsw = 30U,
.hfp = 210U,
.hbp = 30U,
.vsw = 4U,
.vfp = 4U,
.vbp = 4U,
.polarityFlags = (kELCDIF_VsyncActiveLow | kELCDIF_HsyncActiveLow | kELCDIF_DataEnableActiveHigh | kELCDIF_DriveDataOnRisingClkEdge),
.bufferAddr = (uint32_t) LCDIF_Buffer[0],
.pixelFormat = kELCDIF_PixelFormatXRGB8888,
.dataBus = kELCDIF_DataBus24Bit
};
/* RGB buffer */
AT_NONCACHEABLE_SECTION_ALIGN(uint32_t LCDIF_Buffer[2][LCDIF_PANEL_HEIGHT][LCDIF_PANEL_WIDTH], LCDIF_RGB_BUFFER_ALIGN);
这部分是构建LCD控制器的设置参数,就是我们之前在配置工具中填写的像素、帧率等设置。
最下面一行代码是申请了一段内存空间LCDIF_Buffer,用作显存。具体实现方法请看本文参考资料中的野火的RT1052开发板教程。
//peripheral.c
static void LCDIF_init(void) {
/* RGB mode initialization */
ELCDIF_RgbModeInit(LCDIF_PERIPHERAL, &LCDIF_rgbConfig);
/* Enable interrupts */
ELCDIF_EnableInterrupts(LCDIF_PERIPHERAL, (kELCDIF_CurFrameDoneInterruptEnable));
/* Enable interrupt LCDIF_IRQn request in the NVIC. */
EnableIRQ(LCDIF_LCDIF_IRQN);
/* RGB mode start */
ELCDIF_RgbModeStart(LCDIF_PERIPHERAL);
}
/***********************************************************************************************************************
* Initialization functions
**********************************************************************************************************************/
void BOARD_InitPeripherals(void)
{
/* Initialize components */
LCDIF_init();
}
/***********************************************************************************************************************
* BOARD_InitBootPeripherals function
**********************************************************************************************************************/
void BOARD_InitBootPeripherals(void)
{
BOARD_InitPeripherals();
}
看这些函数的名字就知道,这段代码是对外设LCD控制器的初始化和中断配置,并进行了层层包装。我们在main函数中调用最后的BOARD_InitBootPeripheraals函数即可完成对外设的初始化。
从上述代码分析中可知,配置工具已经帮我们把LCD控制器设置好了,用户只需要调用一个函数即可,降低了代码开发量。之后用户根据自己需求,设计应用层面的代码即可。
我写了一段代码,让屏幕交替显示蓝色和白色。主要还是参考了野火的RT1052教程中的程序。
//mylcd.c
#include "my_rd_lcd.h"
#include "fsl_common.h"
#include "stdint.h"
#include "fsl_debug_console.h"
#define MY_RD_LCD_TEST 1
//创建显存空间
//同样已通过IDE自带的设计工具设置好
//AT_NONCACHEABLE_SECTION_ALIGN(pixel_t
//s_psBufferLcd[2][LCD_PIXEL_HEIGHT][LCD_PIXEL_WIDTH], FRAME_BUFFER_ALIGN);
static uint32_t current_frame_buff = (uint32_t)LCDIF_Buffer[0];
static pixel_t current_text_color = CL_WHITE;
static pixel_t current_back_color = CL_BLUE;
static uint8_t s_frameDone = 1;
static uint8_t frameBufferIndex = 0;
/* 帧计数器 */
static volatile uint32_t s_frame_count = 0;
static void put_pixel(uint16_t x, uint16_t y, pixel_t color)
{
if((x < LCDIF_PANEL_WIDTH) && (y < LCDIF_PANEL_HEIGHT))
{
//LCDIF_Buffer[0][y][x] = color;
*(pixel_t*)(current_frame_buff + LCD_BPP*(x + (LCDIF_PANEL_WIDTH * y))) = color;
}
}
void LCDIF_LCDIF_IRQHANDLER(void)
{
volatile uint32_t intStatus;
intStatus = ELCDIF_GetInterruptStatus(LCDIF);
ELCDIF_ClearInterruptStatus(LCDIF, intStatus);
if (intStatus & kELCDIF_CurFrameDone)
{
s_frameDone = 1;
s_frame_count++;
}
}
四、运行结果
本程序让屏幕显示完一帧数据后,立刻显示下一帧,并通过systick中断计时,计算出屏幕的刷新帧率,可以达到80的帧率。
在此还遇到了个问题,LCDIF的时钟源默认是选用PLL3产生的,实测中发现LCD的时钟频率不对,改为PLL2后,才是正确的时钟频率,尚待探究。
利用MCUXpresso用户可以非常方便地开发NXP的单片机程序,尤其是使用RT1060这种跨界MCU中比较复杂的外设。用户使用官方的配置工具更有助于理解外设的功能,不必对着官方例程一行一行地改代码了,加快开发进度,减少出错的概率。
用惯了KEIL开发ARM后,使用这种基于eclipse的IDE还是感觉有些不习惯。但是因为是NXP官方设计的,更加适合开发NXP的单片机,而且提供了许多KEIL没有的更便于开发的工具。而且这种IDE还是完全免费的,对于个人爱好者而言,还是很有必要学习并使用MCUXpresso来开发单片机项目的。
更新:
该问题已解决。原因是IDE生成clock.c中把PLL3的时钟分频代码注释掉了。
五、参考
Embedfire-rt1052: 野火imx-rt1052开发板项目组https://gitee.com/Embedfire-rt10524.3inch Capacitive Touch LCD - Waveshare Wiki
https://www.waveshare.net/wiki/4.3inch_Capacitive_Touch_LCD2021 TencentOS Tiny AIoT应用创新大赛TencentOS Tiny AIoT 应用创新大赛是腾讯TencentOS团队联合恩智浦半导体、ARM中国发起的线上开发者活动,主要面向中小企业嵌入式工程师、广大嵌入式开发者、物联网爱好者、创客团队等,期待广大开发者能参与到国内开源项目中,通过开源协同,基于TencentOS Tiny打造更多新颖、实用、有价值和创造力的AIoT应用及解决方案。
https://cloud.tencent.com/developer/competition/introduction/10032