开始的我用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<<8)) && (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:
目前官方的触屏驱动有两个,我们看下
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 ;
}
/*设备打开函数,创建了AD C中断的挂钩函数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);
}
}
目前发现的一个问题是,ecos之前曾经采纳了一个牛的patch,他应用HAL_TABLE实现了基于Microwindows的APP定义方式。
很巧妙,那么什么是HAL_TABLE呢,我们可以理解为为了实现更好的表的管理的一种机制,可以把我们要存放的表通过宏
放到内存中的某个位置,大家可以在google上找一下,ecos在这个部分应用还是比较有特点的。
尤其是在二维表的处理上有很多特别的应用,redboot的一些命令就是例子
ecos_mw_app.h
typedef void fun(CYG_ADDRWORD);
typedef struct _mw_app_entry {
char *name;
fun *entry;
int prio;
fun *init;
cyg_handle_t t;
cyg_thread t_obj;
char stack[STACKSIZE];
} CYG_HAL_TABLE_TYPE _mw_app_entry_t;
#define _mw_app(_name_,_id_,_pri_,_init_) /
externC void _id_##_thread(CYG_ADDRWORD data); /
_mw_app_entry_t _mw_app_##_pri_##_##_id_ /
CYG_HAL_TABLE_QUALIFIED_ENTRY(_mw_apps,_pri_) = /
{ _name_, _id_##_thread, _pri_, _init_};
#define ECOS_MW_STARTUP_PRIORITY 11
#define ECOS_MW_NANOX_PRIORITY (ECOS_MW_STARTUP_PRIORITY+1)
#define ECOS_MW_KND_PRIORITY (ECOS_MW_STARTUP_PRIORITY+2)
#define ECOS_MW_NANOWM_PRIORITY (ECOS_MW_STARTUP_PRIORITY+4)
#define ECOS_MW_APP_PRIORITY (ECOS_MW_STARTUP_PRIORITY+5)
ecos_app.c
CYG_HAL_TABLE_BEGIN( __MW_APP_TAB__, _mw_apps );
CYG_HAL_TABLE_END( __MW_APP_TAB_END__, _mw_apps );
extern struct _mw_app_entry __MW_APP_TAB__[], __MW_APP_TAB_END__;
为什么提到这个呢,到目前位置我不能十分的确定是这个机制有问题还是QEMU本身对于内存管理的问题。
如果我在Microwindows访问我的设备文件,就是open我们之前创建的/dev/ts这个时候貌似用HAL_TABLE存放的UI线程信息就读不到了。
如果可以打message,可以看到不能创建我们要的Microwindows的一些线程,当然也就不能看到画面了。
比较简单的做法就是参考ecos之前的代码,或者干脆去看官方Microwindows的代码,用一个数组去存放线程信息。
struct nx_thread _threads[] = {
{ "System startup", startup_thread, 11 },
{ "Nano-X server", nanox_thread, 12 },
{ "Nano-WM", nanowm_thread, 14 },
/*{ "Nano-KBD", nxkbd_thread, 13 },*/
#ifdef USE_NXSCRIBBLE
{ "Scribble", nxscribble_thread, 20 },
#endif
#ifdef USE_LANDMINE
{ "Landmine", landmine_thread, 19 },
#endif
#ifdef USE_NTETRIS
{ "Nano-Tetris", ntetris_thread, 18 },
# endif
#ifdef USE_WORLD
{ "World Map", world_thread, 21 },
#endif
{ "demo", demo_thread, 22 },
};
接下来你就看到Microwindows了,进入下一个环节。