今日为了调试ARM板上的GPIO引脚中断效果,以便在后续项目使用ARM与ZLG7290按键LED中断芯片连接中随意选择空闲的GPIO引脚来作为ZLG7290的中断信号线,特意编写了一个小的Linux GPIO中断驱动程序下载到开发板上做实验。经验证,这种软件中断方式也还差强人意。下面贴出自己编写的不成熟的代码,见笑(<-_->)。
实验的硬件电路为ARM GPIO的PB17连接一个共阴LED,PB18与PB19连接,PB18由中断驱动设置为低电平触发,PB19由GPIO驱动程序控制,上层应用程序通过驱动控制PB19高低电平变化,从而引发PB18发生中断,中断程序中控制PB17的LED亮和灭。
Linux中断驱动部分:
- /*
- * PB18_IRQTest.c
- * This is a test program for sam9260, using PB19(J5_18 pin) input a signal to PB18(J5_16 pin),
- * PB18 receive this signal as IRQ and make the LED linking on PB17((J5_14 pin)) turn on or turn off
- *
- * @Author: Cun Tian Rui
- * @Date :March.18.2011
- */
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/platform_device.h>
- #include <linux/cdev.h>
- #include <linux/ioctl.h>
- #include <linux/fs.h>
- #include <linux/gpio.h>
- #include <asm/arch/hardware.h>
- #include <asm/arch/gpio.h>
- #include <linux/interrupt.h>
- #include <asm/io.h>
- #include <asm/arch/board.h>
- #include <linux/cdev.h>
- #include <asm/arch/gpio.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #include <asm/arch/at91_pio.h>
- #include <asm/arch/at91_aic.h>
- #include <asm/arch/at91_pmc.h>
- void led_on()
- {
- at91_set_gpio_output(AT91_PIN_PB17,1);
- }
- void led_off()
- {
- at91_set_gpio_output(AT91_PIN_PB17 ,0);
- }
- struct light_dev *light_devp;
- int light_major = 200;
- struct light_dev
- {
- struct cdev cdev;
- unsigned char value;
- };
- MODULE_AUTHOR("Cun Tian Rui");
- MODULE_LICENSE("Dual BSD/GPL");
- static void io_init(void)
- {
- at91_set_gpio_input(AT91_PIN_PB18, 1);
- at91_set_deglitch(AT91_PIN_PB18, 1);
- at91_sys_write(1 + PIO_IDR, 1<<18);
- at91_sys_write(1 + PIO_IER, (~(1<<18)));
- at91_sys_write(AT91_PMC_PCER, 1 << 3);
- }
- struct gpio_irq_desc
- {
- int irq;
- unsigned long flags;
- char *name;
- };
- static struct gpio_irq_desc PB18_IRQ={AT91_PIN_PB18,AT91_AIC_SRCTYPE_LOW,"PB18"};
- static irqreturn_t PB18_intHandle(int irq, void *dev_id)
- {
- led_on();
- return IRQ_RETVAL(IRQ_HANDLED);
- }
- int light_open(struct inode *inode,struct file *filp)
- {
- int err;
- struct light_dev *dev;
- dev = container_of(inode->i_cdev,struct light_dev,cdev);
- filp->private_data = dev;
- io_init();
- err = request_irq(PB18_IRQ.irq,PB18_intHandle,PB18_IRQ.flags,PB18_IRQ.name,(void*)0);
- if(err)
- {
- free_irq(PB18_IRQ.irq,(void*)0);
- return -EBUSY;
- }
- return 0;
- }
- int light_release(struct inode *inode,struct file *filp)
- {
- free_irq(PB18_IRQ.irq,(void*)0);
- return 0;
- }
- // ioctl
- int light_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,
- unsigned long arg)
- {
- struct light_dev *dev = filp->private_data;
- switch(cmd)
- {
- case 0:
- at91_set_gpio_output(AT91_PIN_PB19,0);
- break;
- case 1:
- at91_set_gpio_output(AT91_PIN_PB19,1);
- led_off();
- break;
- default:
- return -ENOTTY;
- // break;
- }
- return 0;
- }
- struct file_operations light_fops =
- {
- .owner = THIS_MODULE,
- .ioctl = light_ioctl,
- .open = light_open,
- .release = light_release,
- };
- static void light_setup_cdev(struct light_dev *dev,int index)
- {
- int err,devno = MKDEV(light_major,index);
- cdev_init(&dev->cdev,&light_fops);
- dev->cdev.owner = THIS_MODULE;
- dev->cdev.ops = &light_fops;
- err = cdev_add(&dev->cdev,devno,1);
- if(err)
- {
- printk(KERN_NOTICE "Error %d adding LED%d",err,index);
- }
- }
- int light_init(void)
- {
- int result;
- dev_t dev = MKDEV(light_major,0);
- if(light_major)
- {
- result = register_chrdev_region(dev,1,"PB18_IRQTest");
- }
- if(result < 0)
- {
- return result;
- }
- light_devp = kmalloc(sizeof(struct light_dev),GFP_KERNEL);
- if(!light_devp)
- {
- result = - ENOMEM;
- goto fail_malloc;
- }
- memset(light_devp,0,sizeof(struct light_dev));
- light_setup_cdev(light_devp,0);
- return 0;
- fail_malloc:unregister_chrdev_region(dev,light_devp);
- return result;
- }
- void light_cleanup(void)
- {
- cdev_del(&light_devp->cdev);
- kfree(light_devp);
- unregister_chrdev_region(MKDEV(light_major,0),1);
- }
- module_init(light_init);
- module_exit(light_cleanup);
Linux上层应用程序:
- #include <stdio.h>
- //#include <conio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <linux/ioctl.h>
- #include <signal.h>
- int main(int argc ,char *argv[])
- {
- int fd;
- char input;
- fd = open("/dev/PB18_IRQTest",O_RDWR);
- if(fd < 0)
- {
- perror("open PB18_IRQTest device");
- return 0;
- }
- while(1)
- {
- printf("input 0 to trigger int/n");
- scanf("%c",&input);
- switch(input)
- {
- case '0':
- ioctl(fd,0,0);
- printf("/n");
- break;
- case '1':
- ioctl(fd,1,0);
- printf("/n");
- break;
- default:
- printf("/n");
- break;
- }
- }
- return 0;
- }