使用RioTboard开发板,通过自己设计LCD驱动电路,RioTboard配置LCD。本文主要介绍RioTboard开发板的LCD接口和修改驱动代码实现7寸LCD的显示。
使用硬件
RioTboard开发板,自己开发的7寸LCD驱动板,HDMI线。
使用软件
嵌入式linux开发环境+AD10 PCB设计软件。
首先介绍下RioTboard主处理器是freescale的imx6 Solo芯片,具有强大的数据处理和图像处理功能。
拿到板子后首先根据文档熟悉板子接口
从图中可以看到和LCD相关的就有LVDS接口和HDMI接口,如果我们自己做7寸屏幕的LCD驱动,就先用LVDS接口了
然后分析开发板LVDS接口的引脚定义,
看到原理图中的LVDS接口是四对,一对时钟,3对数据线,外加触摸屏的I2C接口和触摸中断,正好可以连接带触摸的LCD。于是开始着手弄LCD驱动+触摸小板,考虑到电容屏价格高,选择了电阻触摸,使用I2C接口的电阻触摸芯片。整个lcd驱动小板的主要规划如下:
1) LCD电源规划:
LCD需要电源有背光,VGH、VGL、DVDD、VCOM,其中
- 上电时序:DVDD->VGL->VGH->Data->B/L
- 掉电时序:B/L->Data->VGH->VGL->DVDD
Data包括RGB信号、U/D、L/R、DCLK、HS、VE、DE。
B/L是背光。
以上电源基本确定。
2) LVDS转RGB
由于demo板使用的是LVDS信号输出,LCD接收RGB信号,所以要完成LVDS信号转为RGB信号,为了操作简单,选择不需要编程的转换芯片。
3) 触摸屏
触摸使用的是电阻式触摸屏,由于LVDS接口信号中只有I2C和触摸中断,具体安排使用I2C接口的电阻式触摸屏芯片。
经过2天原理图绘制确认和PCB打板,期待已久的LCD驱动板终于出炉了,下面看看图片:
板子到了后就要研究代码看看如何修改支持我的LCD。
按照官方手册内容,LVDS输出是适合9.7寸LCD的,我们要更换LCD的话,就必须自己学会阅读驱动源码和配置参数。在看驱动之前我们首先应该了解LCD的显示原理:
这个说简单也简单,说麻烦一不是一两句就能说明白的,和我们主题不是那么相关,在这里就不阐述了,但是我们必须要看一下linux系统对LCD这个硬件做的抽象(详细参见:Documentationfbframebuffer.txt,源代码中Doucumentation下的文档都是很好的文档,能解决大家很多迷惑的问题,有时候大家一筹莫展的时候看看这个文件夹下的相关文档,也许大家就会豁然开朗。)
图中重要的参数有7个,下面我就看看这个抽象有关的数据结构参数和定义:RIOTboard板子的源代码中结构体如下:
struct fb_videomode { constchar *name; /* optional */ u32refresh; /* optional */ u32xres; u32yres; u32pixclock; u32left_margin; u32right_margin; u32upper_margin; u32lower_margin; u32hsync_len; u32vsync_len; u32sync; u32vmode; u32flag;};具体含义:
名称
| 意义
| 备注
| const char *name
| LCD名字,可以自己定义
| | u32 refresh
| 刷新频率,一般定义为60
| | u32 xres
| 行像素
| | u32 yres
| 列像素
| | u32 pixclock
| 像素时钟
| | u32 left_margin
| 在每行或每列的象素数据开始输出时要插入的象素时钟周期数
| | u32 right_margin
| 在每行或每列的象素结束到LCD 行时钟输出脉冲之间的象素时钟数
| | u32 upper_margin
| 在垂直同步周期之后帧开头时的无效行数
| | u32 lower_margin
| 本帧数据输出结束到下一帧垂直同步周期开始之前的无效行数
| | u32 hsync_len
| 行同步脉宽
| | u32 vsync_len
| 场同步脉宽
| | u32 sync
| 同步极性设置
| 可根据情况自行设置
| u32 vmode
| 一般配置为隔行扫描
| | u32 flag
| 未使用
| |
下面我们就看看根据我们实际的LCD规格书来填充这些参数,首先我们看LCD规格书中的timing时序:
以上就是关于LCD的主要参数列表。
下面看看根据我们自己LCD规格书配置参数。
- Const char *name:这个是对应的LCD参数的名字,可以自己起名,但是要和后面给内核传递的参数名字一样。
- Refresh:这个就是我们熟悉的刷新频率,我们不讨论LCD和CRT的刷新频率问题,这里选择默认60就好了。
- Xres和Yres这两个是分辨率参数,即行和列的像素个数,我们的LCD是800*480的,直接就填写800和480就行了.
- Pixclock:是像素时钟,在linux文档中给出了计算公式: pixclock = 1000000 / DCF
下面看看后面6个参数的计算,首先看看LCD规格书里面的timing参数:
可以看到LCD时钟是33.3M,所以pixclock=1000000/33.3=30030
行同步脉冲宽度是一个时钟周期,所以,hsync_len=1
场同步脉冲的宽度是一个行周期,所以vsync_len = 1
然后看看一帧图像的时序图:
根据up_margin定义:在垂直同步周期之后帧开头时的无效行数,也就是图中的tvb-tvpw即23-1=22。
根据lower_margin定义:本帧数据输出结束到下一帧垂直同步周期开始之前的无效行数
Lower_margin=tv-tvd-up_margin,就是525-480-22=23.
然后再看看一行的时序图:
这个图有点模糊了,根据left_margin 定义:在每行或每列的象素数据开始输出时要插入的象素时钟周期数,left_margin=thb,即46
根据u32 right_margin定义:在每行或每列的象素结束到LCD 行时钟输出脉冲之间的象素时钟数.right_margin=th-thd-thb,即1056-800-46=210.
这样相对于LCD的主要参数我们就设置完毕了。
根据上述的内容来修改RIoTboard的LCD配置文件,来使LCD的分辨率等参数适合我们的7寸LCD。
首先我们看看使用LVDS0通道输出的配置步骤:
1. 打开ldb.c文件找到static struct fb_videomode ldb_modedb[]这个结构体定义:
结构体定义中将LCD配置参数修改为适合我们LCD的配置参数,具体配置方式上文给出了分析,请自行查阅,其中红色字体是我们根据上述计算内容修改好的:
staticstruct fb_videomode ldb_modedb[] = {{ "LDB-WXGA", 60, 1280, 800, 14065, 40, 40, 10, 3, 80, 10, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_DETAILED,}, { "LDB-XGA", 60, 800, 480, 30030, 210, 46, 22, 23, 1, 1, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_DETAILED,}, { "LDB-1080P60", 60, 1920, 1080, 7692, 100, 40, 30, 3, 10, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_DETAILED,},};
2. 调整BSP文件,找到board-mx6q-riot.c文件,找到static struct fsl_mxc_ldb_platform_data ldb_data结构体定义:
staticstruct fsl_mxc_ldb_platform_data ldb_data = {.ipu_id = 0,.disp_id = 0,.ext_ref = 1,.mode = LDB_SEP0,//这个地方设置LVDS输出通道,LDB_SEP0为LVDS0通道输出。.sec_ipu_id = 0,.sec_disp_id = 1,};
这个LVDS输出通道,RIoTboard上默认也是使用LVDS0,所以我们就不用修改了。
现在主要修改这两个参数,然后重新编译kernel,下载运行,就可以看到我们的ubuntu在7寸屏上的完美显示了。接下来就是触摸的I2C驱动了,
本来以为I2C是比较简单的linux驱动,但是看了linux下的I2C驱动程序框架确实不是一般的麻烦,在这里简单的描述下使用RIoTboard上的I2C接口的I2C通信问题。
首先实验环境,是使用RIoTboard的I2C3接口,即miniHDMI上的I2C接口,连接7寸LCD的触摸屏芯片TSC2007(I2C接口).
通信调试简单步骤:
- 1.配置menuconfig选项,选在tsc2007驱动,现在想想当时触摸屏芯片选择TSC2007芯片真是幸运,源代码中就用这个芯片的驱动文件,这样就少了很多工作。
- 2.驱动文件有了,就是tsc2007.c,现在就是配置RIoTboard的I2C通信接口的问题了。
我们在源代码中做如下修改:
添加I2C platform_data:
struct tsc2007_platform_data tsc2007_data = {.model = 2007,.x_plate_ohms = 180,.fuzzx = 0,.fuzzy = 0,.fuzzz = 0,.init_platform_hw = tsc2007_init_hw,.exit_platform_hw = tsc2007_exit_hw,.get_pendown_state = tsc2007_state_hw,.irq_pin = RIOT_Touch_Int,};添加I2C board_info:
static struct i2c_board_info mxc_i2c2_board_info[] __initdata = {{ I2C_BOARD_INFO("tsc2007", (0x90>>1)),.platform_data = &tsc2007_data, }, }; //tsc2007 i2c clienttsc2007的I2C地址配置为0x90。
接下来就实现tsc2007的三个硬件函数
- .init_platform_hw = tsc2007_init_hw,
- .exit_platform_hw = tsc2007_exit_hw,
- .get_pendown_state = tsc2007_state_hw,
具体实现大家可以根据自己需要,来具体实现。
在tsc2007.c文件中添加读取触摸坐标的打印信息:
/* Prepare for next touch reading - power down ADC, enable PENIRQ */
tsc2007_xfer(tsc, PWRDOWN);
printk("zfm read the x is %d,y is %d z1 is %d z2 is %d /n",tc->x,tc->y,tc->z1,tc->z2);
这样我们编译uImage,下载,查看串口终端:
由此可见我们的I2C和tsc2007的通信已经建立并能读取数据。后面就是将触摸屏的坐标数据传给操作系统,但是我们用的是ubuntu,还没有研究透彻如何使用触摸,就先到这儿了,其余的等慢慢在做,有时间出一系列教程。多谢大家支持。
下面看看现实效果,手机拍照像素不高,大家勉强看看,实际现实还是挺好的:
先看看整体连接:
再看看细节: |