页次: 1
我克隆了`lv_port_linux_frame_buffer`,并且重新配置了项目。问题已经解决。
我尝试使用lvgl来实现一个图形界面的程序,现在UI可以显示在屏幕上,但是触摸屏没有反应。
我用的触摸芯片是GT911,我使用evtest或者ts_print都能读取到触摸屏的信息,但是lvgl应用却似乎没有调用evdev_read()。下面是我用evtest的输出:
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0: rk805 pwrkey
/dev/input/event1: goodix-ts
/dev/input/event2: adc-keys
/dev/input/event3: Rmoncam A2 1080P: RMONCAM A2 10
Select the device event number [0-3]: 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 800
Event code 54 (ABS_MT_POSITION_Y)
Value 0
Min 0
Max 1280
Event code 57 (ABS_MT_TRACKING_ID)
Value 0
Min 0
Max 255
Properties:
Property type 1 (INPUT_PROP_DIRECT)
Testing ... (interrupt to exit)
Event: time 1501847472.953342, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 1501847472.953342, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 195
Event: time 1501847472.953342, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 92
Event: time 1501847472.953342, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 26
Event: time 1501847472.953342, type 3 (EV_ABS), code 50 (ABS_MT_WIDTH_MAJOR), value 26
Event: time 1501847472.953342, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 0
Event: time 1501847472.953342, ++++++++++++++ SYN_MT_REPORT ++++++++++++
Event: time 1501847472.953342, -------------- SYN_REPORT ------------
Event: time 1501847472.964185, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 195
Event: time 1501847472.964185, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 92
Event: time 1501847472.964185, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 26
Event: time 1501847472.964185, type 3 (EV_ABS), code 50 (ABS_MT_WIDTH_MAJOR), value 26
Event: time 1501847472.964185, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 0
Event: time 1501847472.964185, ++++++++++++++ SYN_MT_REPORT ++++++++++++
Event: time 1501847472.964185, -------------- SYN_REPORT ------------
Event: time 1501847472.974098, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 195
Event: time 1501847472.974098, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 92
Event: time 1501847472.974098, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 26
Event: time 1501847472.974098, type 3 (EV_ABS), code 50 (ABS_MT_WIDTH_MAJOR), value 26
Event: time 1501847472.974098, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 0
Event: time 1501847472.974098, ++++++++++++++ SYN_MT_REPORT ++++++++++++
Event: time 1501847472.974098, -------------- SYN_REPORT ------------
Event: time 1501847472.984269, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 195
Event: time 1501847472.984269, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 92
Event: time 1501847472.984269, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 26
Event: time 1501847472.984269, type 3 (EV_ABS), code 50 (ABS_MT_WIDTH_MAJOR), value 26
Event: time 1501847472.984269, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 0
Event: time 1501847472.984269, ++++++++++++++ SYN_MT_REPORT ++++++++++++
Event: time 1501847472.984269, -------------- SYN_REPORT ------------
Event: time 1501847472.994804, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0
Event: time 1501847472.994804, -------------- SYN_REPORT ------------
对于lvgl程序,我在lv_drv_conf.h中启用了如下内容:
# define USE_EVDEV 1
# define EVDEV_NAME "/dev/input/event1"
下面是我的主函数,以及evdev_read()函数。
int main(void)
{
// DRM_Init();
// pthread_t pth_capt;
// pthread_create(&pth_capt, NULL, (void*)V4L2_SP_Streaming, NULL);
#if 1
/* ================ */
/* ===== LVGL ===== */
/* ================ */
/*LittlevGL init*/
lv_init();
/*Linux frame buffer device init*/
drm_init();
/*A small buffer for LittlevGL to draw the screen's content*/
static lv_color_t buf[DISP_BUF_SIZE], buf1[DISP_BUF_SIZE];
/*Initialize a descriptor for the buffer*/
static lv_disp_draw_buf_t disp_buf;
// lv_disp_draw_buf_init(&disp_buf, buf, NULL, DISP_BUF_SIZE);
lv_disp_draw_buf_init(&disp_buf, buf, buf1, DISP_BUF_SIZE);
/*Initialize and register a display driver*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.draw_buf = &disp_buf;
disp_drv.flush_cb = drm_flush;
disp_drv.hor_res = 800;
disp_drv.ver_res = 1280;
// disp_drv.screen_transp = 1;
lv_disp_drv_register(&disp_drv);
#if 1
// trans background
lv_style_t style_scr_act;
lv_style_init(&style_scr_act);
lv_style_set_bg_opa(&style_scr_act, LV_OPA_TRANSP);
lv_obj_add_style(lv_scr_act(), &style_scr_act, 0);
// lv_disp_set_bg_opa(lv_scr_act(), LV_OPA_TRANSP);
#endif
#if 1
evdev_init();
static lv_indev_drv_t indev_drv_1;
lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/
indev_drv_1.type = LV_INDEV_TYPE_POINTER;
/*This function will be called periodically (by the library) to get the mouse position and state*/
indev_drv_1.read_cb = evdev_read;
lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1);
// debug
if (mouse_indev)
{
printf("register success.\n");
}
else
{
printf("register fail.\n");
}
#endif
#if 1
/*Set a cursor for the mouse*/
LV_IMG_DECLARE(mouse_cursor_icon)
lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
lv_img_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/
lv_indev_set_cursor(mouse_indev, cursor_obj); /*Connect the image object to the driver*/
#endif
mystart();
printf("Start handler\n");
/*Handle LitlevGL tasks (tickless mode)*/
while(1) {
lv_timer_handler();
usleep(5000);
}
#endif
// pthread_exit(NULL);
return 0;
}
void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
struct input_event in;
printf("[DEBUG] Entered evdev_read() function...\n");
while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) {
if(in.type == EV_REL) {
printf("[DEBUG] in.type == EV_REL\n");
if(in.code == REL_X)
#if EVDEV_SWAP_AXES
evdev_root_y += in.value;
#else
evdev_root_x += in.value;
#endif
else if(in.code == REL_Y)
#if EVDEV_SWAP_AXES
evdev_root_x += in.value;
#else
evdev_root_y += in.value;
#endif
} else if(in.type == EV_ABS) {
printf("[DEBUG] in.type == EV_ABS\n");
if(in.code == ABS_X)
#if EVDEV_SWAP_AXES
evdev_root_y = in.value;
#else
evdev_root_x = in.value;
#endif
else if(in.code == ABS_Y)
#if EVDEV_SWAP_AXES
evdev_root_x = in.value;
#else
evdev_root_y = in.value;
#endif
else if(in.code == ABS_MT_POSITION_X)
#if EVDEV_SWAP_AXES
evdev_root_y = in.value;
#else
evdev_root_x = in.value;
#endif
else if(in.code == ABS_MT_POSITION_Y)
#if EVDEV_SWAP_AXES
evdev_root_x = in.value;
#else
evdev_root_y = in.value;
#endif
else if(in.code == ABS_MT_TRACKING_ID) {
if(in.value == -1)
evdev_button = LV_INDEV_STATE_REL;
else if(in.value == 0)
evdev_button = LV_INDEV_STATE_PR;
}
} else if(in.type == EV_KEY) {
printf("[DEBUG] in.type == EV_KEY\n");
if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) {
if(in.value == 0)
evdev_button = LV_INDEV_STATE_REL;
else if(in.value == 1)
evdev_button = LV_INDEV_STATE_PR;
} else if(drv->type == LV_INDEV_TYPE_KEYPAD) {
#if USE_XKB
data->key = xkb_process_key(in.code, in.value != 0);
#else
switch(in.code) {
case KEY_BACKSPACE:
data->key = LV_KEY_BACKSPACE;
break;
case KEY_ENTER:
data->key = LV_KEY_ENTER;
break;
case KEY_PREVIOUS:
data->key = LV_KEY_PREV;
break;
case KEY_NEXT:
data->key = LV_KEY_NEXT;
break;
case KEY_UP:
data->key = LV_KEY_UP;
break;
case KEY_LEFT:
data->key = LV_KEY_LEFT;
break;
case KEY_RIGHT:
data->key = LV_KEY_RIGHT;
break;
case KEY_DOWN:
data->key = LV_KEY_DOWN;
break;
case KEY_TAB:
data->key = LV_KEY_NEXT;
break;
default:
data->key = 0;
break;
}
#endif /* USE_XKB */
if (data->key != 0) {
/* Only record button state when actual output is produced to prevent widgets from refreshing */
data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
}
evdev_key_val = data->key;
evdev_button = data->state;
return;
}
}
}
if(drv->type == LV_INDEV_TYPE_KEYPAD) {
/* No data retrieved */
data->key = evdev_key_val;
data->state = evdev_button;
return;
}
if(drv->type != LV_INDEV_TYPE_POINTER)
return ;
/*Store the collected data*/
#if EVDEV_CALIBRATE
data->point.x = map(evdev_root_x, EVDEV_HOR_MIN, EVDEV_HOR_MAX, 0, drv->disp->driver->hor_res);
data->point.y = map(evdev_root_y, EVDEV_VER_MIN, EVDEV_VER_MAX, 0, drv->disp->driver->ver_res);
#else
data->point.x = evdev_root_x;
data->point.y = evdev_root_y;
#endif
// debug
printf("[DEBUG] evdev_root_x: %d\n", evdev_root_x);
printf("[DEBUG] evdev_root_y: %d\n", evdev_root_y);
printf("[DEBUG] evdev_button: %d\n", evdev_button);
data->state = evdev_button;
if(data->point.x < 0)
data->point.x = 0;
if(data->point.y < 0)
data->point.y = 0;
if(data->point.x >= drv->disp->driver->hor_res)
data->point.x = drv->disp->driver->hor_res - 1;
if(data->point.y >= drv->disp->driver->ver_res)
data->point.y = drv->disp->driver->ver_res - 1;
printf("[DEBUG] Leaving evdev_read() function...\n");
return ;
}
通过打印信息可以确定,程序进入了handler循环,并且没有挂掉。但是evdev_read()函数中的调试信息没有被打印,我尝试了触摸屏和鼠标,均不能使其被调用。我参考了github上的一个问题,该用户使用了/dev/input/touchscreen0替换/event2,并且解决了该问题。但是我这边只有如下的设备:
by-id by-path event0 event1 event2 event3 mice
我使用的kernel版本是4.19,lvgl版本为8.3。我不确定是否时程序对evdev的初始化出现了问题。
感谢您的回复。
可以看到D14的数据本来应该拉高的,但是Nano这边却在将SDA拉低。
但是除了这一位和低八位的数据,接收的其他数据确是正常的。之后我又使用gpiod库来手动模拟了i2c,但是该问题仍然存在:
可以看到,除了config八位的数据是正常的,data的数据均没有被拉起来。这三个字节使用同一段代码读取,不知道是哪里出的问题。下面是我模拟i2c的代码:
struct gpiod_chip* gpiochip0;
struct gpiod_line* line_SCL;
struct gpiod_line* line_SDA;
int PE11Num = (4 * 32) + 11;
int PE12Num = (4 * 32) + 12;
bool i2cInit()
{
gpiochip0 = gpiod_chip_open("/dev/gpiochip0");
line_SCL = gpiod_chip_get_line(gpiochip0, PE11Num);
line_SDA = gpiod_chip_get_line(gpiochip0, PE12Num);
int reqSCL = gpiod_line_request_output(line_SCL, "SCL", 1);
int reqSDA = gpiod_line_request_output(line_SDA, "SDA", 1);
return !(reqSCL | reqSDA);
}
bool i2cSDAConf(bool toOutput)
{
int reqSDA;
gpiod_line_release(line_SDA);
if (toOutput)
{
int reqSDA = gpiod_line_request_output(line_SDA, "SDA", 1);
}
else
{
int reqSDA = gpiod_line_request_input(line_SDA, "SDA");
}
return !reqSDA;
}
void i2cSDALevel(bool toHigh)
{
gpiod_line_set_value(line_SDA, toHigh);
}
void i2cSCLLevel(bool toHigh)
{
gpiod_line_set_value(line_SCL, toHigh);
}
void i2cDelay()
{
for (int i = 0; i < 1000; ++i) { /* do nothing */ }
}
void i2cStart()
{
i2cSDALevel(1);
i2cSCLLevel(1);
i2cDelay();
i2cSDALevel(0);
i2cDelay();
i2cSCLLevel(0);
i2cDelay();
}
void i2cEnd()
{
i2cSDALevel(0);
i2cDelay();
i2cSCLLevel(1);
i2cDelay();
i2cSDALevel(1);
}
void i2cACK()
{
// make sure the SDA is output before send
i2cSDAConf(1);
i2cSDALevel(0);
i2cDelay();
i2cSCLLevel(1);
i2cDelay();
i2cSCLLevel(0);
i2cDelay();
}
void i2cNACK()
{
// make sure the SDA is output before send
i2cSDAConf(1);
i2cSDALevel(1);
i2cDelay();
i2cSCLLevel(1);
i2cDelay();
i2cSCLLevel(0);
i2cDelay();
}
bool i2cSDARelease()
{
// i2cSDALevel(0);
return i2cSDAConf(0);
}
bool i2cWaitAck()
{
return !i2cGetSDA();
}
void i2cSend(u8 data)
{
// make sure the SDA is output before send
i2cSDAConf(1);
for (int i = 0; i < 8; ++i)
{
if (data & 0x80)
i2cSDALevel(1);
else
i2cSDALevel(0);
i2cDelay();
i2cSCLLevel(1);
i2cDelay();
i2cSCLLevel(0);
i2cDelay();
data <<= 1;
}
// 释放SDA
i2cSDARelease();
}
bool i2cGetSDA()
{
i2cSCLLevel(1);
i2cDelay();
bool level = gpiod_line_get_value(line_SDA);
i2cSCLLevel(0);
i2cDelay();
return level;
}
u8 i2cReceive()
{
i2cSDARelease();
u8 data;
for (int i = 0; i < 8; ++i)
{
data <<= 1;
data |= i2cGetSDA();
}
return data;
}
u8 i2cReceiveDebug(u32* biasDebug)
{
i2cSDARelease();
u8 data;
for (int i = 0; i < 8; ++i)
{
data <<= 1;
data |= i2cGetSDA();
*biasDebug <<= 2;
// 查看pull寄存器状态
static int dev_fd;
unsigned char *map_base;
dev_fd = open("/dev/mem", O_RDWR);
map_base = (unsigned char *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, GPIO_PAGE_OFFSET);
*biasDebug |= (*(volatile u32*)(map_base + GPIO_BASE_OFFSET + rPE_PULL0)) >> 24 & 0b11;
munmap(map_base, MAP_SIZE);
}
return data;
}
void i2cRelease()
{
gpiod_chip_close(gpiochip0);
}
void i2cClear()
{
i2cSDARelease();
for (int i = 0; i < 32; ++i)
{
i2cSCLLevel(0);
i2cSCLLevel(1);
}
}
ADS1110读取,在start之前和end之后,我输出了一段scl的时钟,以期对清楚ADS1110的寄存器内容。
void ADS1110_ReadData()
{
if(!i2cInit())
{
printf("I2C init error\n");
i2cRelease();
exit(1);
}
i2cClear();
i2cSDAConf(1);
i2cStart();
u8 addr = 0b10010001;
i2cSend(addr);
if (!i2cWaitAck())
{
printf("none ACK received\n");
printf("%d\n", gpiod_line_direction(line_SDA));
i2cRelease();
exit(1);
}
u8 data[3];
data[0] = i2cReceive();
i2cACK();
data[0] = i2cReceive();
i2cACK();
data[0] = i2cReceive();
i2cNACK();
i2cEnd();
i2cClear();
i2cRelease();
printf("%x %x %x\n", data[0] & 0xFF, data[1] & 0xFF, data[2] & 0xFF);
}
同时,总线上只有ADS1110一个设备:
# i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
小弟今天用Licheepi Nano读取ADS1110,当输入数据小于等于1V时,能得到正确的数据,但是当输入大于1v时,得到的数据则是不正确的。代码如下:
#define NUMS 10
char readbuf[NUMS];
int main(int argc, char** argv)
{
int file = open("/dev/i2c-0", O_RDWR);
// addr = 1001 xxx
int addr = 0b1001000;
if (file < 0)
{
printf("openfile error!\n");
exit(1);
}
if (ioctl(file, I2C_SLAVE, addr) < 0)
{
printf("ioctl error!\n");
exit(1);
}
// Debug Gain 1
readbuf[0] = 0x0C;
if (write(file, readbuf, 1) != 1)
{
printf("write error!\n");
exit(1);
}
if (read(file, readbuf, 3) != 3)
{
printf("read error!\n");
exit(1);
}
printf("%x %x %x\n", readbuf[0] & 0xff, readbuf[1] & 0xff, readbuf[2] & 0xff);
close(file);
exit(EXIT_SUCCESS);
}
上述代码中我写入0x0C,使ADS1110以15sps、16bits输出,同时增益为1。当输入为1V时,输出为`3E 00 0C`,即,3E00 / 32767 * 2.048;当输入为1.5V时,输出大约应为`5E 00 0C'左右,但是我得到的数据大约为`1D 00`。使用调试器的时候能正确读取,请问我这里是哪里没写对吗,感谢大佬指出。
已解决。
我是一个嵌入式小白,前几天看了一位大佬的代码完成了基础的IO。源码是从PE4 PE5 PE6输出,我现在想通过PE2来输出信号,请问要怎么修改呢?可以请您具体讲一下例如&0X00000FFF之类的操作具体是什么含义吗?同时我要怎么完成信号输入呢?
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#define GPIO_REG_BASE 0x01C20800 //GPIO物理基地址 (小页4kb)
#define MAP_SIZE 0x400 //MMU页大小
#define GPIO_BASE_OFFSET (GPIO_REG_BASE & 0X00000FFF) //GPIO基地址偏移计算
#define GPIO_PAGE_OFFSET (GPIO_REG_BASE & 0XFFFFF000) //获得页偏移
#define rPE_CFG0 0X90 //PE_CFG0寄存器地址偏移
#define rPE_DAT 0XA0 //PE_DAT寄存器地址偏移
#define rPE_PULL0 0XAC //PE_PULL0寄存器地址偏移
int GPIOE_456_ON(unsigned char *MAP_BASE);//点亮PE4,PE5,PE6 这3盏LED
int GPIOE_456_OFF(unsigned char *MAP_BASE);//关闭PE4,PE5,PE6 这3盏LED
int main(int argc, char **argv)
{
static int dev_fd;
unsigned char *map_base;
/*参数验证*/
if(argc!=2 || (strcmp(argv[1],"on") && strcmp(argv[1],"off"))){
printf("argv_error!please input 'on' or 'off'!\n");
exit (0);
}
dev_fd = open("/dev/mem", O_RDWR );
if (dev_fd < 0){
printf("open(/dev/mem) failed.\n");
return 0;
}
map_base = (unsigned char *)mmap(NULL, 0x400,PROT_READ | PROT_WRITE, MAP_SHARED,dev_fd, GPIO_PAGE_OFFSET); //把物理地址映射到虚拟地址
if(*map_base) printf("mmap_fail!\n"); //是否映射成功
if(!strcmp(argv[1],"on")) GPIOE_456_ON(map_base); //点亮PE4,PE5,PE6 这3盏LED
if(!strcmp(argv[1],"off")) GPIOE_456_OFF(map_base);//关闭PE4,PE5,PE6 这3盏LED
//usleep(1000000);
if(dev_fd) close(dev_fd);
munmap(map_base,MAP_SIZE);//解除映射关系
return 0;
}
//GPIOE_456_ON
int GPIOE_456_ON(unsigned char *MAP_BASE)
{
unsigned int PE_CFG0,PE_DAT;
PE_CFG0=*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPE_CFG0);
PE_DAT=*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPE_DAT);
*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPE_CFG0)=((PE_CFG0 & 0XF000FFFF)|0X01110000);
*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPE_DAT)=((PE_DAT & 0XFFFFFF8F)|0X00000070);
}
//GPIOE_456_OFF
int GPIOE_456_OFF(unsigned char *MAP_BASE)
{
unsigned int PE_CFG0,PE_DAT;
PE_CFG0=*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPE_CFG0);
PE_DAT=*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPE_DAT);
*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPE_CFG0)=((PE_CFG0 & 0XF000FFFF)|0X01110000);
*(volatile unsigned int *)(MAP_BASE+GPIO_BASE_OFFSET+rPE_DAT)=((PE_DAT & 0XFFFFFF8F));
}
页次: 1