手把手教你使用pcDuino的外部中断
本帖最后由 Lily 于 2013-12-17 09:00 编辑在我们之前学习单片机的是按键一般有轮询和中断两种方式,轮询就不用说了,需要CPU不断的去扫描,一般是不会采用这种方式的。而中断方式在单片机的一般的操作方法如下:1,配置中断引脚;2,设置中断模式(如,上升沿,下降沿,低电平,高电平。。。。。。。);3,清除所有中断4,开中断电在中断函数里面:1,读中断状态2,中断操作任务3,任务结束,清中断在我们的pcDuino里面操作方法是一样的,只不过添加了一些linux驱动框架。篇文章里面需要用到的linux驱动框架在http://cnlearn.linksprite.com/?p=1556,这篇文章里面已经讲过,这里不再赘述。
一、按键驱动其实相比LED驱动,中断按键驱动,只是多添加了三个函数。
1,intrequest_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char*devname, void *dev_id)
irq是要申请的硬件中断号。(A10芯片所有外部中断都用28号中断)
handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。
irqflags是中断处理的属性,若设置了IRQF_DISABLED,则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED,则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM,表示对系统熵有贡献,对系统获取随机数有好处。
devname设置中断名称,通常是设备驱动程序的名称在cat /proc/interrupts中可以看到此名称。
dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。
request_irq()返回0表示成功,返回-INVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用且不能共享。
2,free_irq,对应request_irq,释放中断
3,中断处理函数,本例中
static irqreturn_t key_irq(int irq, void*dev_id)
irq即为中断号,(外部中断28)
dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。
大家可能看到三星等其他的一些学习开发板中只需要用到这两个函数,不需要之前说的单片机里面的一些配置,那是因为开发板厂商为了降低学习难度,去掉了中断的配置。
为了降低操作寄存器的复杂度,这里给大家介绍两个很好的函数。
头文件:#include <asm/io.h>
原型:void writel (unsigned char data , unsigned short addr )
说明:writel() 往内存映射的 I/O 空间上写数据,wirtel() I/O 上写入 32 位数据 (4字节)。
头文件:#include <asm/io.h>
原型:unsigned char readl (unsigned int addr )
说明:readl() 从内存映射的 I/O 空间读取数据,readl 从 I/O 读取 32 位数据 ( 4 字节 )。
废话用多说,下面是代码。
/*
*实验目的:演示linux系统中外部中断功能
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <asm/io.h>
#include <linux/platform_device.h>
//#include <mach/gpio.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/syscalls.h>
#include <linux/reboot.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/completion.h>
#include <asm/uaccess.h>
#include <mach/irqs.h>
#include <mach/system.h>
#include <mach/hardware.h>
#include <plat/sys_config.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#define GPIO_IRQ28
#define GPIO_TEST_BASE 0xf1c20800
#define PH_CFG2 (GPIO_TEST_BASE + 0×104)
#define PIO_INT_CFG2 (GPIO_TEST_BASE + 0×208)
#define PIO_INT_CTL (GPIO_TEST_BASE + 0×210)
#define PH18_SELECT (6 << 8)
static struct class *keydrv_class;
static irqreturn_t key_irq(int irq, void*dev_id)
{
unsigned int status;
status = readl(GPIO_TEST_BASE + 0×214 ) ;
printk(“irq = %d \n”,irq);
writel(status, GPIO_TEST_BASE + 0×214);
return IRQ_HANDLED;
}
static int key_drv_open(struct inode*inode, struct file *file)
{
int error;
int irq_ctl;
/*1,设置中断位*/
irq_ctl = readl(PH_CFG2);
writel(PH18_SELECT | irq_ctl ,PH_CFG2);
/*2,设置中断方式*/
irq_ctl = readl(PIO_INT_CFG2);
writel((0×1 <<(2*4)) | irq_ctl,PIO_INT_CFG2);
/*3,开中断*/
irq_ctl = readl(PIO_INT_CTL);
writel((1 << 18)|irq_ctl,PIO_INT_CTL);
error = request_irq(GPIO_IRQ, key_irq,0, “button”, 1);
if (error) {
printk(“failed to register keypad interrupt\n”);
}
printk(KERN_ALERT”key openi\n”);
return 0;
}
static ssize_t key_drv_write(struct file*file, const char __user *buf, size_t count, loff_t * ppos)
{
printk(KERN_ALERT”key write\n”);
return 0;
}
int key_drv_close(struct inode *inode,struct file *file)
{
free_irq(GPIO_IRQ,1);
return 0;
}
static struct file_operations key_drv_fops= {
.owner= THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = key_drv_open,
.write= key_drv_write,
.release =key_drv_close,
};
int major;
static int key_drv_init(void)
{
major = register_chrdev(0, “key_drv”, &key_drv_fops);
keydrv_class = class_create(THIS_MODULE,”key_drv”);
device_create(keydrv_class,NULL,MKDEV(major,0),NULL,”key”);
printk(KERN_ALERT”register\n”);
return 0;
}
static void key_drv_exit(void)
{
unregister_chrdev(major, “key_drv”); // 卸载
device_destroy(keydrv_class,MKDEV(major,0));
class_destroy(keydrv_class);
printk(KERN_ALERT”unregister\n”);
}
module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE(“GPL”);二、测试由于pcDuino要做arduino平台,所以pcDuino将外部中断做到了udev里面,这里为了避和arduino的外部中断有冲突,需要先删掉原来arduino的驱动。 sudo rmmod sw_interrupt另外我们的中断函数需要printk打印信息,为了让信息及时显示出来,我们需要对系统进行的printk的打印等级进行配置。 echo “8 4 1 7″>/proc/sys/kernel/printk通过上面准备就可以测试按键驱动了。 sudo insmod key.ko exec 5</dev/key #打开设备开始中断 #需要在串口调试中执行,打印也是在调试串口中出来的现在按几下板子上面的MENU建,终端上个就会不断有下面信息出现。 root@ubuntu:~# exec 5</dev/key [ 6693.380000] key openi root@ubuntu:~# [ 6701.890000] irq = 28 [ 6702.650000] irq = 28 [ 6703.280000] irq = 28 [ 6703.870000] irq = 28 [ 6704.340000] irq = 28 [ 6704.820000] irq = 28 [ 6705.270000] irq = 28 [ 6706.220000] irq = 28 [ 6707.080000] irq = 28 [ 6707.850000] irq = 28 [ 6708.330000] irq = 28 [ 6708.750000] irq = 28 [ 6713.920000] irq = 28 [ 6714.400000] irq = 28 [ 6714.830000] irq = 28测试结束 exec 5<&- #关闭设备三、说明这个例子只是对外部中断进行说明,并没有对按键操作进行完善,后面的几章教程将对按键进行一步完善,请关注后面内容。
学习中,长知识了:) :victory:楼主分享很细腻,按照这个步骤做了一遍,不错! :D谢谢夸奖,我会再接再厉 我是个完全的菜鸟,这个学起来是不是很复杂???:o 本帖最后由 岽东 于 2013-12-17 09:57 编辑
{:soso_e100:} ;PpcDuino就是为非工程师设计的,使用起来非常简单 乍看有点复杂,细看还是能懂的 我对它的了解就是一款Mini PC + Arduino:dizzy: pcDuino是一种高性能,高性价比的迷你PC的平台,能够运行PC操作系统,如Ubuntu和Android的ICS等。它可以通过内置HDMI接口输出视频到电视或显示器屏幕。
页:
[1]
2