简介
触控驱动我们实现了一个名为"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: 触控驱动软件结构
增加一个新触控代码的流程
1. 选择example\rt_driver下对应板子的工程
- 这个工程里面有一个读取触控数据并打印的线程 touch_read_task
2. 将新驱动添加到编译工程里面
- 添加新触控代码到目录customer\peripherals内
- 可以从其他已有的驱动复制一份代码,然后将名字、Slave_Address、读取流程等改成自己的
- Note
- 注意修改复制代码目录下的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;
msgs.flags = RT_I2C_WR;
msgs.buf = buf;
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;
msgs[0].flags = RT_I2C_RD;
msgs[0].buf = buf;
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);
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;
else
return RT_EEMPTY;
}
p_msg->event = TOUCH_EVENT_NONE;
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);
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);
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");
}
}