Touch Screen
简介
触控驱动我们实现了一个名为”touch”的rt_device统一对上的接口,其内部有一个简单的框架用于注册不同的触控驱动,并自动选择适配的驱动。 本章节主要介绍Touch device的内部框架功能以及如何注册一个新触控到该框架。
Touch device的实现分2部分
rt_device设备(drv_touch.c )
注册了一个名为”touch”的device,对外提供中断回调注册和读触控数据接口
创建了一个task用于和触控设备的慢速通信(如初始化、读取触控点数据等)
对读到的触控数据点,做缓存、过滤(过滤重复点)、缓存溢出丢包处理
具体触控设备的驱动实现
向touch_device注册一个新驱动并提供以下实现:
probe 识别支持设备
init 识别设备后的初始化
deinit 识别设备后的去初始化
read_point 读一个有效数据点(注意:还有未读走的数据点返回RT_EOK, 否则返回其他值)
一个信号量 用于阻塞rt_device层的线程
同时内部需要实现:
触控中断的检测
通信接口的初始化
增加一个新触控代码的流程
1. 选择example\rt_driver下对应板子的工程
这个工程里面有一个读取触控数据并打印的线程 touch_read_task
2. 将新驱动添加到编译工程里面
添加新触控代码到目录_customer\peripherals_内
可以从其他已有的驱动复制一份代码,然后将名字、Slave_Address、读取流程等改成自己的
备注
注意修改复制代码目录下的Kconfig文件的depend宏
在_customer\peripherals\Kconfig_内,为新加的驱动添加一个隐藏开选项,比如:
config TSC_USING_TMA525B bool default n
在板级的配置的屏幕模组的开关中添加前面添加的隐藏触控开关:
config LCD_USING_ED_LB55DSI13902_DSI_LB555 bool "1.39 round 454RGB*454 DSI LCD(ED-LB55DSI13902)" select TSC_USING_TMA525B <-------- 添加的触控开关 select LCD_USING_RM69330 select BSP_LCDC_USING_DSI if LCD_USING_ED_LB55DSI13902_DSI_LB555 config LCD_RM69330_VSYNC_ENABLE bool "Enable LCD VSYNC (TE signal)" def_bool n endif
若用scons 编译,则需要进入工程的menuconfig选择菜单,然后选择前面新增的屏幕模组,最终生成_.config_和_rtconfig.h_
若用Keil编译,也可以直接添加源代码进入(但还是建议和scons编译添加方法一样,这样下次重新生成Keil工程后会自动加入)
3. 检查新增的触控用到的pin,以及reset pin 的pinmux是否正确
SDK的
drv_io.c
内 函数_BSP_TP_PowerUp&BSP_TP_PowerDown_,对触控做了上下电和reset的操作
触控调试的建议
先检查供电、reset脚的状态是否正常
然后检查通信接口波形是否正常,比如I2C接口是否有ack
tma525b触控设备的驱动实现示例代码
tma525b通过TOUCH_IRQ_PIN的下降沿为触发条件,I2C为通信接口速度400KHz, I2C读写超时时间5ms 该实现中在中断中释放信号量使touch_device层调用自己的read_point去获取触控数据 同时在中断中关闭中断使能,在进read_point后再打开中断使能,防止中断太多反复release太多信号量
static struct rt_i2c_bus_device *ft_bus = NULL;
static struct touch_drivers tma525b_driver;
static rt_err_t i2c_write(rt_uint8_t *buf, rt_uint16_t len)
{
rt_int8_t res = 0;
struct rt_i2c_msg msgs;
msgs.addr = I2C_ADDR; /* slave address */
msgs.flags = RT_I2C_WR; /* write flag */
msgs.buf = buf; /* Send data pointer */
msgs.len = len;
if (rt_i2c_transfer(ft_bus, &msgs, 1) == 1)
{
res = RT_EOK;
}
else
{
res = -RT_ERROR;
}
return res;
}
static rt_err_t i2c_read(rt_uint8_t *buf, rt_uint16_t len)
{
rt_int8_t res = 0;
struct rt_i2c_msg msgs[2];
msgs[0].addr = I2C_ADDR; /* Slave address */
msgs[0].flags = RT_I2C_RD; /* Read flag */
msgs[0].buf = buf; /* Read data pointer */
msgs[0].len = len; /* Number of bytes read */
if (rt_i2c_transfer(ft_bus, msgs, 1) == 1)
{
res = RT_EOK;
}
else
{
res = -RT_ERROR;
}
return res;
}
void tma525b_irq_handler(void *arg)
{
rt_err_t ret = RT_ERROR;
rt_pin_irq_enable(TOUCH_IRQ_PIN, 0);
ret = rt_sem_release(tma525b_driver.isr_sem);
RT_ASSERT(RT_EOK == ret);
}
static rt_err_t read_point(touch_msg_t p_msg)
{
rt_err_t ret = RT_ERROR;
rt_uint8_t touch_report[16];
rt_pin_irq_enable(TOUCH_IRQ_PIN, 1);
//read touch report
if(RT_EOK == i2c_read((rt_uint8_t *)touch_report, 16))
{
if(touch_report[1] == 1)
{
p_msg->event = TOUCH_EVENT_DOWN;
}
else
{
p_msg->event = TOUCH_EVENT_UP;
}
p_msg->x = touch_report[2];
p_msg->y = touch_report[3];
if(touch_report[4] > 1)
return RT_EOK; //More pending touch data
else
return RT_EEMPTY; //No more touch data to be read
}
p_msg->event = TOUCH_EVENT_NONE; //Read point fail
return RT_ERROR;
}
static rt_err_t init(void)
{
rt_pin_mode(TOUCH_IRQ_PIN, PIN_MODE_INPUT);
rt_pin_attach_irq(TOUCH_IRQ_PIN, PIN_IRQ_MODE_FALLING, tma525b_irq_handler, (void *)(rt_uint32_t)TOUCH_IRQ_PIN);
rt_pin_irq_enable(TOUCH_IRQ_PIN, 1); //Must enable before read I2C
return RT_EOK;
}
static rt_err_t deinit(void)
{
rt_pin_detach_irq(TOUCH_IRQ_PIN);
return RT_EOK;
}
static rt_bool_t probe(void)
{
rt_err_t err;
ft_bus = (struct rt_i2c_bus_device *)rt_device_find(TOUCH_DEVICE_NAME);
if (RT_Device_Class_I2CBUS != ft_bus->parent.type)
{
ft_bus = NULL;
}
if (ft_bus)
{
rt_device_open((rt_device_t)ft_bus, RT_DEVICE_FLAG_RDWR);
}
else
{
LOG_I("bus not find\n");
return RT_FALSE;
}
{
struct rt_i2c_configuration configuration =
{
.mode = 0,
.addr = 0,
.timeout = 5,
.max_hz = 400000,
};
rt_i2c_configure(ft_bus, &configuration);
}
LOG_I("tma525b probe OK");
return RT_TRUE;
}
static struct touch_ops ops =
{
read_point,
init,
deinit
};
static int rt_tma525b_init(void)
{
tma525b_driver.probe = probe;
tma525b_driver.ops = &ops;
tma525b_driver.user_data = RT_NULL;
tma525b_driver.isr_sem = rt_sem_create("tma525b", 0, RT_IPC_FLAG_FIFO);
rt_touch_drivers_register(&tma525b_driver);
return 0;
}
INIT_COMPONENT_EXPORT(rt_tma525b_init);
Touch device上层使用方法的示例代码
示例通过注册中断回调释放信号量,然后信号量再去驱动读触控数据,然后打印触控点
static struct rt_semaphore tp_sema;
static rt_err_t tp_rx_indicate(rt_device_t dev, rt_size_t size)
{
rt_sem_release(&tp_sema);
return RT_EOK;
}
static void touch_read_task(void *parameter)
{
rt_sem_init(&tp_sema, "tpsem", 0, RT_IPC_FLAG_FIFO);
/*Open touch device*/
rt_device_t touch_device = NULL;
touch_device = rt_device_find("touch");
if (touch_device)
{
if (RT_EOK == rt_device_open(touch_device, RT_DEVICE_FLAG_RDONLY))
{
touch_device->rx_indicate = tp_rx_indicate;
while (1)
{
rt_err_t err;
struct touch_message touch_data;
err = rt_sem_take(&tp_sema, rt_tick_from_millisecond(500));
if (RT_EOK == err)
{
rt_device_read(touch_device, 0, &touch_data, 1);
rt_kprintf("read data %d, [%d,%d]\r\n", touch_data.event, touch_data.x, touch_data.y);
}
}
}
else
{
rt_kprintf("Touch open error!\n");
touch_device = NULL;
}
}
else
{
rt_kprintf("No touch device found!\n");
}
}