[vc_row][vc_column width=”1/1″][vc_column_text]The key usually has both polling and interrupt methods in the single chip microcomputers we have studied before, no need to mention polling, which needs CPU to scan it all the time, and is not recommended in most cases. The general practice of interrupt method is as following:
- Configure interrupt pins
- Set the interrupt mode(such as low volts, high volts..)
- Clear all interrupt
- Power up interrupt
In interrupt function:
- Clear all interrupt
- Interrupt task
- Interrupt task
It’s pretty much the same practice with pcDuino, but some Linux driving structure is added.
[/vc_column_text][vc_tour][vc_tab title=”Key Driver” tab_id=”1388481714-1-23″][vc_column_text]Compared to LED driver, we only need to add three functions for interrupt key driver.
1. int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
Irq means the hardware interrupt we are going to request.(we use number 28 interrupt for all external interrupt for A10 chip.
Handler is the interrupt handling function registered from system, which is a call-back function, when interrupt happens, system calls this fucntiona, and dev_id parameters will be passed to it.
Irqflags means the attributes of interrupt handling, if you set IRQF_DISABLED, it means the interrupt handling program is fast handling program, all interrupt are shielded when fast handling interrupt is called, slow handling program still works; if you set IRQF_SHARED, it means multi devices can share the interrupt; if you set IRQF_SAMPLE_RANDOM, it means it contributes to system’s entropy, helping system get random number.
Devname is used to set the name for interrupt, which is usually the name of driver program for the device, you can check the name in cat /proc/interrupts.
dev_id can be used in interrupt sharing, which can be usually set as device’s structure of NULL.
If request_irq()returns a 0, which means success, returns –INVAL meaning interrupt number is invalid or the pointer of handling function is NULL, returns –EBUSY meaning interrupt is occupied and can’t be shared.
2. free_irq, corresponding request_irq, releases interrupt
3. Interrupt handling function, in this post:
static irqreturn_t key_irq(int irq, void *dev_id)
Irq is the interrupt number(external interrupt 28)
dev_id will be used during interrupt sharing, which can be set as device structure or NULL.
In order to lower the complexity to handle the shift register, we will introduce you two amazing functions.
Header file: #include <asm/io.h>
Original: void writel (unsigned char data , unsigned short addr )
A little explanation: writel() writes data in I/O’s space of RAM mapping, we write 32 bits(4KB) data into wirtel() I/O
Header file: #include <asm/io.h>
Original: unsigned char readl (unsigned int addr )
A little explanation:Readl() reads the date from I/O’s space of RAM mapping, reading 32 bits(4KB) data.
/*
*实验目的:演示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_IRQ 28
#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”);
[/vc_column_text][/vc_tab][vc_tab title=”Testing” tab_id=”1388481714-2-23″][vc_column_text]pcDuino has integrated the external interrupt into udev because of Arduino platform. So we need to delete Arduino’s driver in order not to conflict with Arduino’s external interrupt.
sudo rmmod sw_interrupt
Our interrupt function requests printk printing information, we need to configure the printing level of system’s printk to show up the information in time.
echo “8 4 1 7″>/proc/sys/kernel/printk
Now we can test key driver after the above preparations.
sudo insmod key.ko
exec 5</dev/key #打开设备开始中断
#需要在串口调试中执行,打印也是在调试串口中出来的
Now press the MEMU button for few times, it will show up in the terminal as below:
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
Testing finished.
exec 5<&- #shut down the device
[/vc_column_text][/vc_tab][vc_tab title=”Explanation” tab_id=”1388482200428-2-10″][vc_column_text]We only explained the external interrupt in this post, but haven’t talked much about key handling, please follow up the upcoming posts to see more tutorials about keys.[/vc_column_text][/vc_tab][/vc_tour][/vc_column][/vc_row]
Leave a Reply
You must be logged in to post a comment.