历史上的今天
今天是:2025年03月23日(星期日)
2021年03月23日 | S3C6410开发板按键驱动代码分析及测试代码分析
2021-03-23 来源:eefocus
在本文中,我们对S3C6410开发板按键驱动代码的实现过程进行分析,然后通过一个实例对按键功能进行测试。在本文的资源中包含了设备驱动的源码和测试的源码。
一、设备驱动源码分析
按键的设备驱动主要实现了模块的初始化、模块的卸载、设备打开、设备关闭、设备读取、设备阻塞功能。
1、模块初始化
模块的初始化的源码如下所示。
static int __init dev_init(void)
{
int ret;
ret = misc_register(&misc);
printk (DEVICE_NAME"tinitializedn");
return ret;
}
这段代码只实现了一个功能,就是使用misc_register()函数向内核注册按键的混杂设备。
2、模块卸载
模块卸载的代码比较简单,如下所示。
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
模块卸载代码实现的功能是将按键的混杂设备从内核中取消注册。
3、设备打开
设备打开代码主要实现了按键对应的GPIO接口的初始化。
static int s3c64xx_buttons_open(struct inode *inode, struct file *file)
{
int i;
int err = 0;
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
if (button_irqs[i].irq < 0) {
continue;
}
err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,
button_irqs[i].name, (void *)&button_irqs[i]);
if (err)
break;
}
if (err) {
i--;
for (; i >= 0; i--) {
if (button_irqs[i].irq < 0) {
continue;
}
disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
}
return -EBUSY;
}
ev_press = 1;
return 0;
}
在这段代码中,使用request_irq()函数用来初始化GPIO接口,主要是开启了GPIO接口的输入中断功能,将中断号与中断处理函数、中断描述结构体绑定在一起。其中,button_irqs[i].irq是中断号,buttons_interrupt是中断处理函数,(void *)&button_irqs[i]是指向中断描述结构体的指针,函数还将中断的模式设置为双边沿触发。当按下或松开按键时,会产生下降沿或上升沿,就会触发中断,中断会把相应的中断描述结构体保持下来,并转到buttons_interrupt函数去处理中断。
buttons_interrupt()函数的源码如下所示。
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
int down;
int number;
unsigned tmp;
udelay(0);
number = button_irqs->number;
switch(number) {
case 0: case 1: case 2: case 3: case 4: case 5:
tmp = readl(S3C64XX_GPNDAT);
down = !(tmp & (1< case 6: case 7: tmp = readl(S3C64XX_GPLDAT); down = !(tmp & (1 << (number + 5))); break; default: down = 0; } if (down != (key_values[number] & 1)) { key_values[number] = '0' + down; ev_press = 1; wake_up_interruptible(&button_waitq); } return IRQ_RETVAL(IRQ_HANDLED); } 中断处理函数的重要输入是中断描述结构体dev_id,结构体内部包含了,中断号、按键编号、以及按键名。程序根据按键编号对GPIO数据寄存器的值进行读取,从而判断外部输入电平的状态,并将按键状态保存到key_values[ ]数组中,‘1’代表按键按下,‘0’代表按键没有按下。当按键状态有变化时,程序调用wake_up_interruptible(&button_waitq);将阻塞的内核排队队列唤醒。 4、设备关闭 设备关闭代码如下所示 static int s3c64xx_buttons_close(struct inode *inode, struct file *file) { int i; for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { if (button_irqs[i].irq < 0) { continue; } free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); } return 0; } 功能比较简单,主要是将按键的中断功能禁止。 5、设备读取 设备的读取代码主要是读取8个按键的状态,代码如下。 static int s3c64xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) { unsigned long err; if (!ev_press) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; else wait_event_interruptible(button_waitq, ev_press); } ev_press = 0; err = copy_to_user((void *)buff, (const void *)(&key_values), min(sizeof(key_values), count)); return err ? -EFAULT : min(sizeof(key_values), count); } 代码实现的功能是将设备状态数组key_values[ ]回传到用户程序的buf中。 6、设备阻塞 设备阻塞函数是用来相应用户空间的select()系统调用函数的,代码如下 static unsigned int s3c64xx_buttons_poll( struct file *file, struct poll_table_struct *wait) { unsigned int mask = 0; poll_wait(file, &button_waitq, wait); if (ev_press) mask |= POLLIN | POLLRDNORM; return mask; } 阻塞函数功能比较简单,是在没有按键按下或松开时将程序阻塞,当有按键按下或松开时退出阻塞状态。 二、测试代码分析 编写了一个简单的测试代码对按键的驱动进行测试,代码如下。 int main() { int fd_led,fd_key; fd_set read_set; int max_fd; struct timeval timeout; int ret; char buf[8]; fd_led = open("/dev/leds",0); fd_key = open("/dev/buttons",O_RDONLY); if(fd_led<0||fd_key<0) { fprintf(stderr,"can't open leds or buttons!n"); return 1; } while(1) { //清零描述符集合 FD_ZERO(&read_set); FD_SET(fd_key,&read_set); max_fd = fd_key; //设置超时时间 timeout.tv_sec=3; timeout.tv_usec=0; ret = select(max_fd+1, &read_set, 0, 0, &timeout); if(ret>0) { read(fd_key,buf,8); if(buf[0]=='1') { ioctl(fd_led,1,0); } else { ioctl(fd_led,0,0); } if(buf[1]=='1') { ioctl(fd_led,1,1); } else { ioctl(fd_led,0,1); } if(buf[2]=='1') { ioctl(fd_led,1,2); } else { ioctl(fd_led,0,2); } if(buf[3]=='1') { ioctl(fd_led,1,3); } else { ioctl(fd_led,0,3); } } } close(fd_key); close(fd_led); return 0; } 在这个代码中,通过select()函数将程序阻塞,等待按键的状态变化。当按键状态有变化时,读取按键状态,并根据按键状态对LED灯进行控制。当按键按下时,将相应的LED灯点亮;松开按键时,将相应的LED灯熄灭。
史海拾趣
|
我先说吧 我用过TI的TMS320VC5402和5502,那是第一次接触DSP,有存储器映射的概念 用过LSI的ZSP系列的DSP,发现编译器老有bug 用过ADI的BLACKFIN,编译器还不错,开发较简单,存储器有L1,L2和L3等区分,现在单位要用ADI的最底端DSP,adsp-218x ...… 查看全部问答> |
|
移动软件开发工程师 职位要求: 1、嵌入式平台(WinCE,平台),应用软件开发; 2、熟悉J2ME开发。 3、具有良好的团队精神。 4、一年以上WinCE平台开发经验。 请有意者将简历mail至 suntjl@sina.com ...… 查看全部问答> |
|
昨晚,发完贴,看了一会书后,我又拿起板子看,结果发现,有一些很小的线短路了,额滴神,还是很要命的短路。 这个是因为之前板子割了太多的线,最后补线的时候,线太小了,不小心碰上了而没有察觉。 我立马修复好,然后试图上电,发现正常了很多 ...… 查看全部问答> |
|
在百度文库花了我一二百金币给大家淘来了些TI M3的资料,希望对大家能有所帮助 [ 本帖最后由 鑫海宝贝 于 2011-4-21 09:41 编辑 ]… 查看全部问答> |




