手上刚好有一块 2.8 寸的TFT LCD,买的firefly 的RK3288 没有显示屏,就想物尽其用,让LCD显示一些系统信息如IP 内存占用大小。
下面记录一下折腾的过程
1、接线 ,杜邦线连接:
RK3288 引脚标号 | LCD ili9341引脚标号 |
42 VCC | VCC |
41 GND | GND |
36 SPI0_CSN0 | CS |
17 GPIO7_A3 | RESET |
15 GPIO7_B1 | DC |
37 SPI0_TXD | SDI(MOSI) |
35 SPI0_CLK | SCK |
32 VCCIO_3.3V | LED |
38 SPI0_RXD | SDO(MISO) |
|
|
2、增加内核配置,修改设备树
目前最新的4.1x内核均包含了市面上常见的SPI液晶屏的驱动(fbtft),我们所要做的仅仅是在设备树中添加节点。
不过目前为止fbtft并未转正,依然存放在 drivers/staging 目录中。
配置内核添加fbtft驱动
使用make menuconfig配置内核,加入ili9341驱动。fbtft还支持更多型号的SPI总线的液晶屏。关于支持列表这里就不一一列出,可以进入menuconfig中查看。
Device Drivers ---> [] Staging drivers ---> <> Support for small TFT LCD display modules ---> <> FB driver for the ILI9341 LCD Controller <> Generic FB driver for TFT LCD displays
修改设备树注册ili9341
设备树有包含和覆盖特性,所以我们可以在不修改默认配置文件的情况下,新增我们的板子的修改。
新建 arch/arm/boot/dts/sun8i-v3s-licheepi-zero-spitft.dts
里面加入如下内容,一个就是 删除 原来的simplefb节点(uboot里有使能fb的操作,必须删除而不是disable才行)
二就是增加ili9341 挂载在spi0上。这样fbtft驱动在加载的时候就会自动找到这个节点,挂载驱动,显示。
//这里spi速率使用了50M,超出9341的手册范围,但实际测试可以使用。
注意这里删除后,uboot仍然会初始化RGB的驱动,只是内核会使用spi显示。
如果需要完全去除RGB上的显示,需要在uboot里关闭显示。
&spi0 { status = "okay"; ili9341@0 { compatible = "ilitek,ili9341"; reg = <0>; spi-max-frequency = <50000000>; rotate = <270>; bgr; fps = <30>; buswidth = <8>; reset-gpios = <&gpio7 3 GPIO_ACTIVE_LOW>; dc-gpios = <&gpio7 9 GPIO_ACTIVE_LOW>; debug = <0>; }; };
./build.sh -kernel 生成boot.img 烧写到板子上
dmesg | grep fb 查看相关的启动信息
3、测试
通用的fb 操作
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#define RED 0xF800
#define YELLOW 0xFFE0
#define BLUE 0x001F
#define WHITE 0xFFFF
#define BLACK 0x0000
void fill_color16(short *fb_addr, short bit_map, int psize)
{
int i;
for(i=0; i<psize; i++) {
*fb_addr = bit_map;
fb_addr++;
}
}
int main ()
{
int fp=0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long screensize=0;
char *fbp = NULL, *test_fbp=NULL;
int x = 0, y = 0;
long location = 0;
int i;
int num = 5;
int pix_size=0;
fp = open("/dev/graphics/fb0", O_RDWR);
if(fp < 0) {
printf("Error : Can not open framebuffer device/n");
exit(1);
}
if(ioctl(fp, FBIOGET_FSCREENINFO, &finfo)){
printf("Error reading fixed information/n");
exit(2);
}
if(ioctl(fp, FBIOGET_VSCREENINFO, &vinfo)){
printf("Error reading variable information/n");
exit(3);
}
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
printf("The phy mem = 0x%x, total size = %d(byte)\n", finfo.smem_start, finfo.smem_len);
printf("xres = %d, yres = %d, bits_per_pixel = %d\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
printf("So the screensize = %d(byte), using %d frame\n", screensize, finfo.smem_len/screensize);
printf("vinfo.xoffset = %d, vinfo.yoffset = %d\n", vinfo.xoffset, vinfo.yoffset);
printf("vinfo.vmode is :%d\n", vinfo.vmode);
printf("finfo.ypanstep is :%d\n", finfo.ypanstep);
printf("vinfo.red.offset=0x%x\n", vinfo.red.offset);
printf("vinfo.red.length=0x%x\n", vinfo.red.length);
printf("vinfo.green.offset=0x%x\n", vinfo.green.offset);
printf("vinfo.green.length=0x%x\n", vinfo.green.length);
printf("vinfo.blue.offset=0x%x\n", vinfo.blue.offset);
printf("vinfo.blue.length=0x%x\n", vinfo.blue.length);
printf("vinfo.transp.offset=0x%x\n", vinfo.transp.offset);
printf("vinfo.transp.length=0x%x\n", vinfo.transp.length);
fbp =(char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp,0);
if ((int)fbp == -1)
{
printf ("Error: failed to map framebuffer device to memory./n");
exit (4);
}
printf("Get virt mem = %p\n", fbp);
pix_size = vinfo.xres * vinfo.yres;
/* using first frame, for FBIOPAN_DISPLAY
* 当刷新需要调用FBIOPAN_DISPLAY, 要告知驱动刷哪块帧, 用到下面两个参数
* 如果使用第二帧buffer -> vinfo.xoffset = 0; vinfo.yoffset = vinfo.yres;
*/
vinfo.xoffset = 0;
vinfo.yoffset = 0;
/* show color loop */
while(num--) {
printf("\ndrawing YELLOW......\n");
fill_color16((short *)fbp, YELLOW, pix_size);
//ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
sleep(3);
printf("\ndrawing BLUE......\n");
fill_color16((short *)fbp, BLUE, pix_size);
//ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
sleep(3);
printf("\ndrawing RED......\n");
fill_color16((short *)fbp, RED, pix_size);
//ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
sleep(3);
}
#if 1
/*这是你想画的点的位置坐标,(0,0)点在屏幕左上角*/
x = 10;
y = 10;
location = x * (vinfo.bits_per_pixel / 8) + y * finfo.line_length;
test_fbp = fbp + location;
printf("draw line.......\n");
for(i = 0; i < (vinfo.xres - x); i++)
*test_fbp++ = i+30;
//ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
#endif
munmap(fbp, screensize); /*解除映射*/
close (fp);
return 0;
}
显示效果:驱动实现自刷新, 应用依次显示黄、蓝、红,最后画线
参考:
http://zero.lichee.pro/%E9%A9%B1%E5%8A%A8/SPI_LCD.html