|
楼主 |
发表于 2011-4-2 11:33:51
|
显示全部楼层
Microwindows 及触摸屏实现
1. 修复MINI2440 QEMU的BUG开始的我用ecos里面仅有的两个ARM下面的touch 驱动来做一个中断测试,
都快疯了,没有任何反应。
后来看到RT-Thread的例子可以正常运行,于是才想看看他们呢对MINI2440 QEMU的修改。
真的要感谢所有自由组织的无私奉献。
果然,MINI2440的QEMU采用的是S3C2410的TOUCH接口,里面关于PenDown和PenUP的寄存器位都木有。
代码已经上传到了emboslab git 库中qemu-mini2440的ecos-emboslab 分支,这里还是简要介绍一下。
--------------------------------- hw/s3c2410.c ---------------------------------
index d1e4c92..bdf8a73 100644
@@ -1630,6 +1630,14 @@ static void s3c_adc_tick(void *opaque)
qemu_mod_timer(s->tst, qemu_get_clock(vm_clock) +
(ticks_per_sec >> 5));
}
/*
这个是QEMU实现ARM中断方式的机制
可以这样理解:如果对QEMU的窗口做Penup的时候,触发一个专断给CPU。
*/
+ else
+ {
+ if (((s->ts & 3) == 3) && (s->ts & (1<<) && (s->enable))
+ qemu_irq_raise(s->tcirq);
+
+
qemu_mod_timer(s->tst, qemu_get_clock(vm_clock) +
+ (ticks_per_sec >> 5));
+ }
}
static void s3c_adc_event(void *opaque,
@@ -1689,7 +1697,7 @@ static void s3c_adc_write(void *opaque, target_phys_addr_t addr,
break;
case S3C_ADCTSC:
- s->ts = value & 0xff;
+ s->ts = value & 0x1ff; /*增加了Pendown和Penup的控制位*/
break;
case S3C_ADCDLY:
2. 实现触摸屏驱动(尚有BUG)目前官方的触屏驱动有两个,我们看下
ricky@ricky-laptop:ecos-emboslab$ cd packages/devs/touch/arm/
ricky@ricky-laptop:arm$ ls
aaed2000 ipaq
如果让Microwindows支持Touch只要实现这样的一个标准的Touch驱动就可以了。
在Microwindows的部分调用这个标准的ecos字符形设备就可以了。
不过从代码看来,ecos并没有对Touch驱动有严格的API定义,所以在网上你能看到很多种实现方法。
既然Microwindows用了字符形的设备,那么我们也就按照这个架构实现一下吧。
我们先看一下ecos的字符形设备是什么样子的,具体的请看ecos的参考手册(如何生成最新的参考手册,我会在另一篇博客中讲述)
CHAR_DEVIO_TABLE(mini2440_ts_handlers,
NULL, // Unsupported write() function
ts_read,
ts_select,
ts_get_config,
ts_set_config);
CHAR_DEVTAB_ENTRY(mini2440_ts_device,
CYGDAT_DEVS_TOUCH_MINI2440_NAME, /*这个是字符形设备的描述符,在CDL文件中定义"/dev/ts",和Linux的驱动文件很相似 */
NULL, // Base device name
&mini2440_ts_handlers,
ts_init,
ts_lookup, /*重点看这个函数:当设备被open的时候这个callback函数会被调用*/
NULL); // Private data pointer
关于如何实现更好的touch架构,本人还在研究。
现在的方案是
在设备初始化的时候配置硬件资源和终端设置,
在设备被打开,也就是ts_lookup里面创建中断响应函数,把转化好的touch 数据放到队列中等待上层(Microwindows)
来读取。
看下初始化部分
static bool
ts_init(struct cyg_devtab_entry *tab)
{
cyg_uint32 _dummy;
HAL_WRITE_UINT32(ADCCON,S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(9));
HAL_WRITE_UINT32(ADCDLY,50000);
HAL_WRITE_UINT32(ADCTSC,WAIT4INT(0)); /*这里就是使能,PenDownUP终端*/
//HAL_WRITE_UINT32(INTMSK, BIT_ALLMSK);
HAL_READ_UINT32(SUBSRCPND, _dummy);
_dummy |= BIT_SUB_TC;
_dummy |= BIT_SUB_ADC;
HAL_WRITE_UINT32(SUBSRCPND, _dummy);
cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_ADC);
cyg_selinit(&ts_select_info);
/* install interrupt handler */
HAL_READ_UINT32(INTSUBMSK, _dummy);
_dummy &= ~BIT_SUB_ADC;
_dummy &= ~BIT_SUB_TC;
HAL_WRITE_UINT32(INTSUBMSK, _dummy);
HAL_INTERRUPT_UNMASK(CYGNUM_HAL_INTERRUPT_ADC);
return true;
}
/*设备打开函数,创建了ADC中断的挂钩函数cyg_mini2440_ts_isr和cyg_mini2440_ts_dsr*/
if (!_is_open) {
_is_open = true;
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_ADC,
0,
(CYG_ADDRWORD)0,
cyg_mini2440_ts_isr,
cyg_mini2440_ts_dsr,
&ts_thread_handle,
&ts_thread_data);
cyg_drv_interrupt_attach(ts_thread_handle);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ADC);
}
return ENOERR;
}
罗嗦两句,ecos在创建的时候就参考了很多linux的风格,比如我们看到上面的isr和dsr很像Linux对中断处理的上半和下半。
具体的实现机理本人也在研究呢,目前位置我只是知道如何应用。
isr中希望用户能快速的响应终端,在isr结束的时候往往有下面的代码
cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_ADC);
上面的这行主要是在函数返回前开启这个中断
return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
后面这个有两个含义,第一个是告诉系统这个中断我已经知道了,做了我应该做的事情。第二个含义就是红色的部分会在函数返回之后
出发这个终端的DSR处理程序。
那么这个touch驱动到底需要还是不需要DSR呢,本人下不了结论。
本人是做Linux的,知道Linux一般的input driver一般用到后半的多是处理report机制,
为了不把问题复杂化,我们现让硬件能动起来,欢迎其他人给我建议
2440的Touch中断处理暂时比较简单
if (res& (1 << 10))/*ADC的采用的后要继续出发PenDownUP中断*/
{
//diag_printf("ADC Interrupt\n");
HAL_READ_UINT32(SUBSRCPND, reg);
reg |= BIT_SUB_ADC;
HAL_WRITE_UINT32(SUBSRCPND, reg);
x = read_ts_x();
y = read_ts_y();
lastX = x; lastY = y;
//diag_printf("X = %x, Y = %x\n", x, y);
HAL_WRITE_UINT32(ADCTSC,WAIT4INT(1));
}
if (res& (1 << 9)){ /*PenDownUp中断记录Touch的按下和抬起,同时出发ADC的采样*/
//diag_printf("TS Interrupt\n");
HAL_READ_UINT32(SUBSRCPND, reg);
reg |= BIT_SUB_TC;
HAL_WRITE_UINT32(SUBSRCPND, reg);
HAL_READ_UINT32(ADCDAT0, data0);
HAL_READ_UINT32(ADCDAT1, data1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
if(updown)
{
x = read_ts_x();
y = read_ts_y();
//diag_printf("X = %x, Y = %x\n", x, y);
//diag_printf("pen_down#######################################################################\n");
if ((x < X_THRESHOLD) || (y < Y_THRESHOLD)) {
// Ignore 'bad' samples
}
lastX = x; lastY = y;
HAL_WRITE_UINT32(ADCTSC, S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST);
HAL_READ_UINT32(ADCCON, reg);
reg |= S3C2410_ADCCON_ENABLE_START;
HAL_WRITE_UINT32(ADCCON, reg);
pen_down = true;
}
else
{
x = lastX;
y = lastY;
HAL_WRITE_UINT32(ADCTSC,WAIT4INT(0));
pen_down = false;
//diag_printf("pen_up#######################################################################\n");
}
}
/*把合理的数据处理后放入一个events数组中,等待上层来读取*/
if (num_events < MAX_EVENTS) {
num_events++;
ev = &_events[_event_put++];
if (_event_put == MAX_EVENTS) {
_event_put = 0;
}
ev->button_state = pen_down ? 0x04 : 0x00;
ev->xPos = x;
ev->yPos = y;
if (ts_select_active) {
ts_select_active = false;
cyg_selwakeup(&ts_select_info);
}
} |
|