7. 屏幕与触摸

LubanCat-P1板卡支持mipi屏的显示,屏幕适用野火MIPI屏幕,有5.5寸、7寸以及10.1寸MIPI屏幕。

屏幕资料: 野火MIPI屏幕

7.1. 屏幕显示

7.1.1. 连接屏幕

屏幕通过fpc排线连接到板卡,如下图所示:

未找到图片

7.1.2. 初始化屏幕

不同尺寸的屏幕初始化序列和时序参数不同,在初始化的时候需要指定屏幕和相关参数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#5.5寸mipi屏幕初始化
sudo /mnt/system/usr/bin/sample_panel --panel=HX8399_1080P

#7寸mipi屏幕初始化
sudo /mnt/system/usr/bin/sample_panel --panel=EK79007

#10.1寸mipi屏幕初始化
sudo /mnt/system/usr/bin/sample_panel --panel=ILI9881C

#加载fb驱动
sudo insmod /mnt/system/ko/cvi_fb.ko

注意

旧的系统请使用/mnt/system/usr/bin/sample_panel初始化屏幕序列,fb驱动使用/mnt/system/ko/cvi_fb.ko。

7.1.3. 测试屏幕

7.1.3.1. 屏幕自测

算能sg200x修改内部寄存器可以进行屏幕自测,执行以下命令:

1
2
sudo devmem 0x0a088000 32 0xC0
sudo devmem 0x0a088094 32 0x0701000a

效果如下:

未找到图片

7.1.3.2. 屏幕刷屏

使用framebuffer编写测试程序。

fb_test.c
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include <unistd.h>  
#include <stdio.h>  
#include <fcntl.h>  
#include <linux/fb.h>  
#include <sys/mman.h>  
#include <stdlib.h>  
#include <string.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <errno.h>

#define ARGB8888

#define PAUSE()                                                                                                        \
    do {                                                                                                           \
        printf("---------------press Enter key to continue!---------------\n");                                    \
        getchar();                                                                                             \
    } while (0)


#if defined(ARGB8888)	// 32bits
#define RED      0xFFFF0000
#define GREEN    0xFF00FF00
#define BLUE     0xFF0000FF
#define YELLOW   0xFFFFFF00
#define WHITE    0xFFFFFFFF 
#define BLACK    0xFF000000
void fill_color(uint32_t *fb_addr, uint32_t bit_map, int psize)
{
    int i;
    int pix_count = psize / 4;
    for(i=0; i<pix_count; i++) {
        *fb_addr = bit_map;
        fb_addr++;
    }
}
#else	// 16bits
#define RED      0xFC00
#define GREEN    0x83E0
#define BLUE     0x801F
#define YELLOW   0xFFE0
#define WHITE    0xFFFF 
#define BLACK    0x8000
void fill_color(short *fb_addr, short bit_map, int psize)
{
    int i;
    for(i=0; i<psize; i++) {
        *fb_addr = bit_map;
        fb_addr++;
    }
}
#endif

void _fb_get_info(int fp, struct fb_fix_screeninfo *finfo, struct fb_var_screeninfo *vinfo)
{
    long screensize=0;  

    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 = finfo->line_length * vinfo->yres;

    printf("The ID=%s\n", finfo->id);
    printf("The phy mem = 0x%x, total size = %d(byte)\n", finfo->smem_start, finfo->smem_len);  
    printf("line length = %d(byte)\n", finfo->line_length);  
    printf("xres = %d, yres = %d, bits_per_pixel = %d\n", vinfo->xres, vinfo->yres, vinfo->bits_per_pixel);  
    printf("xresv = %d, yresv = %d\n", vinfo->xres_virtual, vinfo->yres_virtual);  
    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);
    printf("Expected screensize = %d(byte), using %d frame\n", screensize, finfo->smem_len/screensize);
}

int main ()   
{  
    int fp=0;  
    struct fb_var_screeninfo vinfo;  
    struct fb_fix_screeninfo finfo;  
    void *fbp = NULL;    
    uint32_t *test_fbp = NULL;
    int x = 0, y = 0;  
    long location = 0;
    int i;
    int num = 1;
    int pix_size=0;

    fp = open("/dev/fb0", O_RDWR);  

    if(fp < 0) {  
        printf("Error : Can not open framebuffer device/n");  
        exit(1);  
    }  

    printf("-- Default fb info --\n");
    _fb_get_info(fp, &finfo, &vinfo);

#if !defined(ARGB8888)
    vinfo.xres = 720;
    vinfo.yres = 1280;
    vinfo.xres_virtual = 720;
    vinfo.yres_virtual = 2560;
    vinfo.bits_per_pixel = 16;
    if(ioctl(fp, FBIOPUT_VSCREENINFO, &vinfo)){  
        printf("Error putting variable information/n");  
        exit(3);  
    }  

    printf("-- Updated fb info --\n");
    _fb_get_info(fp, &finfo, &vinfo);
#endif

    fbp = mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fp, 0);
    if (fbp == MAP_FAILED)
    {
        printf ("Error: failed to map framebuffer device to memory.\n");
        exit (4);  
    }
    printf("Get virt mem = %p\n", fbp);  

    pix_size = finfo.line_length * 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");
        vinfo.xoffset = 0;
        vinfo.yoffset = 0;
        fill_color(fbp, YELLOW, pix_size);
        if (ioctl(fp, FBIOPAN_DISPLAY, &vinfo) != 0) {
        	printf("\nPAN_DISPLAY err(%d)\n", errno);
	}
        sleep(1);

        printf("\ndrawing BLUE......\n");
        vinfo.xoffset = 0;
        vinfo.yoffset = 0;
        fill_color(fbp, BLUE, pix_size);
        if (ioctl(fp, FBIOPAN_DISPLAY, &vinfo) != 0) {
        	printf("\nPAN_DISPLAY err(%d)\n", errno);
	}
        sleep(1);
        
        printf("\ndrawing RED......\n");
        vinfo.xoffset = 0;
        vinfo.yoffset = 0;
        fill_color(fbp, RED, pix_size);
        if (ioctl(fp, FBIOPAN_DISPLAY, &vinfo) != 0) {
        	printf("\nPAN_DISPLAY err(%d)\n", errno);
	}
        sleep(1);
	PAUSE();
    }

    munmap(fbp, finfo.smem_len); /*解除映射*/  

    close (fp);
    return 0;
}  

交叉编译测试程序:

1
2
3
4
5
#交叉编译
riscv64-unknown-linux-musl-gcc fb_test.c -o fb_test -march=rv64imafdcvxthead -mcmodel=medany -mabi=lp64d

#运行测试
sudo ./fb_test

串口信息如下:

未找到图片

可以看到打印显示设备ID、显存起始地址和大小、屏幕分辨率、虚拟分辨率、显示模式等信息。

屏幕效果:

依次黄、蓝、红依次刷新,按下回车后退出。

未找到图片

7.2. 触摸

野火mipi屏幕使用的触摸芯片为gt911/gt928,系统启动时会加载gt9xx驱动:

cat@lubancat:~$ dmesg |  grep goodix
[   17.008689] input: goodix-ts as /devices/virtual/input/input1

可从以上信息可知触摸芯片是gt911,i2c的通信地址14,触摸面板的大小1024*600以及工作模式等。

触摸屏属于input输入子系统的设备,会在/dev/input下注册想用的事件, 执行dmesg | grep input 以及 ls -l /dev/input 的确定对应的事件编号

1
2
3
4
5
6
7
8
9
root@lubancat:/home/cat# ls -l /dev/input
total 0
drwxr-xr-x 2 root root      60 Nov 22 04:57 by-path
crw-rw---- 1 root input 13, 64 Nov 22 04:57 event0
crw-rw---- 1 root input 13, 65 Nov 22 04:57 event1
root@lubancat:/home/cat# dmesg | grep input
[    1.858676] input: sgpio-keys as /devices/platform/sgpio-keys/input/input0
[   21.153372] input: goodix-ts as /devices/virtual/input/input1
root@lubancat:/home/cat#

可知触摸对应的事件为/dev/input/event1。

注意

使用屏幕时,请确认屏幕的连接是正确的,没有接屏幕也会有input的设备产生,但是会没有数据的生成。

7.2.1. 使用evtest测试触摸

在终端上执行evtest命令并选择触摸屏进行测试。

1
2
3
4
5
6
7
8
#执行evtest命令
sudo evtest

No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:      sgpio-keys
/dev/input/event1:      goodix-ts
Select the device event number [0-1]:
  • sgpio-keys为用户按键和pwr按键,对应事件event0

  • goodix-ts为屏幕触摸,对应事件event1

输入数字1,测试屏幕触摸。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
cat@lubancat:~$ sudo evtest
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:      sgpio-keys
/dev/input/event1:      goodix-ts
Select the device event number [0-1]: 1
Input driver version is 1.0.1
Input device ID: bus 0x18 vendor 0xdead product 0xbeef version 0x28bb
Input device name: "goodix-ts"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
        Event code 330 (BTN_TOUCH)
Event type 3 (EV_ABS)
        Event code 48 (ABS_MT_TOUCH_MAJOR)
        Value      0
        Min        0
        Max      255
        Event code 50 (ABS_MT_WIDTH_MAJOR)
        Value      0
        Min        0
        Max      255
        Event code 53 (ABS_MT_POSITION_X)
        Value      0
        Min        0
        Max     1024
        Event code 54 (ABS_MT_POSITION_Y)
        Value      0
        Min        0
        Max      600
        Event code 57 (ABS_MT_TRACKING_ID)
        Value      0
        Min        0
        Max      255
Properties:
Property type 1 (INPUT_PROP_DIRECT)
Testing ... (interrupt to exit)

输入后会把基本的输入信息打印出来,可以根据这些信息,获取触摸屏的基本信息。

点击屏幕,将会有信息打印。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
Property type 1 (INPUT_PROP_DIRECT)
Testing ... (interrupt to exit)
Event: time 1700602231.652645, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 1700602231.652645, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 205
Event: time 1700602231.652645, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 300
Event: time 1700602231.652645, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 15
Event: time 1700602231.652645, type 3 (EV_ABS), code 50 (ABS_MT_WIDTH_MAJOR), value 15
Event: time 1700602231.652645, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 0
Event: time 1700602231.652645, ++++++++++++++ SYN_MT_REPORT ++++++++++++
Event: time 1700602231.652645, -------------- SYN_REPORT ------------
Event: time 1700602231.662620, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 205
Event: time 1700602231.662620, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 300
Event: time 1700602231.662620, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 15
Event: time 1700602231.662620, type 3 (EV_ABS), code 50 (ABS_MT_WIDTH_MAJOR), value 15
Event: time 1700602231.662620, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 0
Event: time 1700602231.662620, ++++++++++++++ SYN_MT_REPORT ++++++++++++
Event: time 1700602231.662620, -------------- SYN_REPORT ------------
Event: time 1700602231.672945, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0
Event: time 1700602231.672945, -------------- SYN_REPORT ------------
  • 第3行:按键事件(EV_KEY),按钮代码(code 330)代表触摸(BTN_TOUCH),其值(value)为1,表示触摸屏被触摸。

  • 第4行:绝对坐标事件(EV_ABS),代码(code 53)代表触摸点的X轴位置(ABS_MT_POSITION_X),其值为205。

  • 第5行:绝对坐标事件(EV_ABS),代码(code 54)代表触摸点的Y轴位置(ABS_MT_POSITION_Y),其值为300。

  • 第6行:触摸点的主要接触区域(ABS_MT_TOUCH_MAJOR),值为15

  • 第7行:触摸点的主要宽度(ABS_MT_WIDTH_MAJOR),值为15。

  • 第8行:触摸点的追踪ID(ABS_MT_TRACKING_ID),值为0。

  • 第9、10行:第一条是多点触摸报告同步开始,第二条是输入事件同步报告。

  • 第18行:按键事件,按钮代码为触摸(BTN_TOUCH),其值为0,表示触摸屏停止触摸。