ARM-Linux下的GPIO中断程序.
嵌入式Linux下GPIO驱动程序的开发及应用

第28卷第4期增刊 2007年4月仪 器 仪 表 学 报Chinese Jour nal of Scientif ic InstrumentVol.28No.4Apr.2007 嵌入式L inux 下GPIO 驱动程序的开发及应用3何 泉,贺玉梅(北京化工大学信息科学与技术学院 北京 100029)摘 要:嵌入式Linux 是一种适用于嵌入式系统的源码开放的占先式实时多任务操作系统,是目前操作系统领域中的一个热点,其重点与难点是驱动程序的开发。
开发嵌人式Linux 下的设备驱动程序,可以更好地利用新硬件特性,提高系统访问硬件的效率,改善整个应用系统的性能。
驱动程序修改非常方便,使应用系统非常灵活。
本文简要论述了基于A TM E L 公司嵌入式ARM 处理器芯片的嵌入式Linux 的GP IO 驱动程序的开发原理及流程。
关键词:嵌入式Linux ;ARM ;驱动程序;设备文件;GPIOInvest igat ion an d a pplicat ion of GP IO dr iver in t he embedded L inuxHe Quan ,He YuMei(School of I nf orma tion Science and Tec hnology BU CT ,Beij ing 100029,China )Abstract :Embedded Linu x ,w hich i s a full y real 2time kernel and applicable to embedded syst ems ,has bec o me a hot s 2po t in t he do main of op erati ng system at present.It s out line and difficult y is to investigat e drivers.Developi ng device dri vers o n embedded Lin ux can help using t he new devices ,and imp rovi ng t he e fficiency of access to t he new devices and t he p erformance cap abilit y.As drivers can be changed easil y ,t he system is very convenient and flexi ble.Thi s p a 2p er simpl y point s o ut t he element s and flow of t he GPIO driver in t he embedded Linux based o n t he A RM proces sor of A TMEL system.Key words :embedded Li nux ;A RM ;driver ;device file ;GPIO 3基金项目国家自然科学基金(6)、北京化工大学青年教师自然科学研究基金(QN 58)资助项目1 引 言随着半导体技术的飞速发展,嵌入式产品已经广泛应用于军事、消费电子、网络通信、工业控制等各个领域,这是嵌入式系统发展的必然趋势。
Linux中断处理流程

Linux中断处理流程1. 中断处理流程 当中断发⽣时,Linux系统会跳转到asm_do_IRQ()函数(所有中断程序的总⼊⼝函数),并且把中断号irq传进来。
根据中断号,找到中断号对应的irq_desc结构(irq_desc结构为内核中中断的描述结构,内核中有⼀个irq_desc结构的数组irq_desc_ptrs[NR_IRQS]),然后调⽤irq_desc中的handle_irq函数,即中断⼊⼝函数。
我们编写中断的驱动,即填充并注册irq_desc结构。
2. 中断处理数据结构:irq_desc Linux内核将所有的中断统⼀编号,使⽤⼀个irq_desc[NR_IRQS]的结构体数组来描述这些中断:每个数组项对应着⼀个中断源(也可能是⼀组中断源),记录中断⼊⼝函数、中断标记,并提供了中断的底层硬件访问函数(中断清除、屏蔽、使能)。
另外通过这个结构体数组项中的action,能够找到⽤户注册的中断处理函数。
struct irq_desc {unsigned int irq;irq_flow_handler_t handle_irq;struct irq_chip *chip;struct msi_desc *msi_desc;void *handler_data;void *chip_data;struct irqaction *action; /* IRQ action list */unsigned int status; /* IRQ status */unsigned int depth; /* nested irq disables */unsigned int wake_depth; /* nested wake enables */unsigned int irq_count; /* For detecting broken IRQs */unsigned long last_unhandled; /* Aging timer for unhandled count */unsigned int irqs_unhandled;spinlock_t lock;const char *name;} ____cacheline_internodealigned_in_smp;(1)handle_irq:中断的⼊⼝函数(2)chip:包含这个中断的清除、屏蔽、使能等底层函数struct irq_chip {const char *name;unsigned int (*startup)(unsigned int irq);void (*shutdown)(unsigned int irq);void (*enable)(unsigned int irq);void (*disable)(unsigned int irq);void (*ack)(unsigned int irq);void (*mask)(unsigned int irq);void (*mask_ack)(unsigned int irq);void (*unmask)(unsigned int irq);void (*eoi)(unsigned int irq);void (*end)(unsigned int irq);void (*set_affinity)(unsigned int irq,const struct cpumask *dest);int (*retrigger)(unsigned int irq);int (*set_type)(unsigned int irq, unsigned int flow_type);int (*set_wake)(unsigned int irq, unsigned int on);/* Currently used only by UML, might disappear one day.*/#ifdef CONFIG_IRQ_RELEASE_METHODvoid (*release)(unsigned int irq, void *dev_id);#endif/** For compatibility, ->typename is copied into ->name.* Will disappear.*/const char *typename;};(3)action:记录⽤户注册的中断处理函数、中断标志等内容struct irqaction {irq_handler_t handler;unsigned long flags;cpumask_t mask;const char *name;void *dev_id;struct irqaction *next;int irq;struct proc_dir_entry *dir;};3. 中断处理流程总结(1)发⽣中断后,CPU执⾏异常向量vector_irq的代码;(2)在vector_irq⾥⾯,最终会调⽤中断处理C程序总⼊⼝函数asm_do_IRQ();(3)asm_do_IRQ()根据中断号调⽤irq_des[NR_IRQS]数组中的对应数组项中的handle_irq();(4)handle_irq()会使⽤chip的成员函数来设置硬件,例如清除中断,禁⽌中断,重新开启中断等;(5)handle_irq逐个调⽤⽤户在action链表中注册的处理函数。
GPIO及外部中断实验

实验一GPIO及外部中断的使用一、实验目的1.熟悉Keil uVision5开发软件;2.学会利用固件库函数控制IO口的输入输出;二、实验原理实验原理图如上图所示,红、绿、蓝灯分别受PB5、PB0、PB1控制。
三、实验内容1. 控制红灯闪3下,然后绿灯闪4下,然后蓝灯闪2个,接着开始下一个循环;2. 闪烁间隔1S;3. 在一个循环完成后,蜂鸣器发出300ms的鸣叫;然后开始下一个循环.四、C源程序main.c#include "stm32f10x.h"#include "bsp_led.h"#include "./beep/bsp_beep.h"#define SOFT_DELAY Delay(0x0FFFFF);LED_GPIO_Config();BEEP_GPIO_Config();BASIC_TIM_Init();LED1_ON; // ÁÁSOFT_DELAY;LED1_OFF; // ÃðSOFT_DELAY;LED1_ON; // ÁÁSOFT_DELAY;LED1_OFF; // ÃðSOFT_DELAY;LED1_ON; // ÁÁSOFT_DELAY;LED1_OFF; // ÃðSOFT_DELAY;LED2_ON; // ÁÁSOFT_DELAY;LED2_OFF; // ÃðSOFT_DELAY;LED2_ON; // ÁÁSOFT_DELAY;LED2_OFF; // ÃðSOFT_DELAY;LED2_ON; // ÁÁSOFT_DELAY;LED2_OFF; // ÃðSOFT_DELAY;LED2_ON; // ÁÁSOFT_DELAY;LED2_OFF; // ÃðSOFT_DELAY;LED3_ON; // ÁÁSOFT_DELAY;LED3_OFF; // ÃðSOFT_DELAY;LED3_ON; // ÁÁSOFT_DELAY;LED3_OFF; // ÃðSOFT_DELAY;GPIO_SetBits(BEEP_GPIO_PORT,BEEP_GPIO_PIN);SOFT_DELAY;GPIO_ResetBits(BEEP_GPIO_PORT,BEEP_GPIO_PIN);stm32f10x_it.c#include "stm32f10x_it.h"#include "bsp_TiMbase.h"void BASIC_TIM_IRQHandler (void){if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET ){TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update);}}五、调试过程及问题解决1.首先看实验要求,选择合适的库原件,这里我选用了12-GPIO输出—使用固件库点亮LED灯,32-TIM—基本定时器,GPIO输出—蜂鸣器。
嵌入式Linux下使用GPIO中断功能

嵌入式Linux下使用GPIO中断功能
1).简介
GPIO应用是嵌入式设备最基本的应用之一,本文就基于EmbeddedLinux
系统演示开发GPIO中断以及输出相关的基本应用示例.
本文所采用的硬件平台来自与Toradex发布的基于NXPiMX7SoC的ColibriiMX7ARM计算机模块配合ColibriEvaBoard.
2).准备
a).ToradexColibriiMX7S(基于NXPiMX7SSoC)计算机模块配合ColibriEvaBoard开发载板.
b).EmbeddedLinux使用Toradex官方发布的LinuxreleaseV2.6.1,更新方法请见这里.
3).软硬件安装
a).本文所实现的GPIO应用原理为使用两个GPIO接口,一个作为按键输
入使用,另外一个作为输出驱动载板上面的LED.每次按键后,会将LED状态翻转,也就是点亮和熄灭交替.
b).硬件连接,将ColibriEva载板X3连接器C19和X21连接器SW6连
接,作为按键输入端;将X3连接器A19和X21连接器LED1连接,用于驱动
LED1.
c).在Ubuntu14.04开发主机配置开发环境,这里使用Eclipse作为开发IDE,具体配置可以参考这里的Linux开发上手指南.
4).GPIO应用示例
a).运行Eclipse,创建一个新项目,命名”gpiointtest”,配置为”EmptyProject”
和“CrossGCC”.。
gpio中断触发方式

gpio中断触发方式在嵌入式系统开发中,GPIO(General Purpose Input/Output)是常见的接口模块之一。
它通过控制电平的高低来与外部电路进行通信。
在实际应用中,我们经常需要通过检测GPIO输入信号来触发相应的操作,而不是周期性地轮询输入信号。
这就引出了GPIO中断触发方式。
一、中断的基本概念中断是计算机系统中用于处理紧急事件和优先事件的一种机制。
当某个事件发生时,它会打断CPU当前的工作,转而执行相应的中断服务程序,待中断服务程序执行完毕后再恢复CPU原来的工作。
二、GPIO中断触发方式的概述GPIO中断触发方式是指通过配置GPIO引脚的中断触发条件,当满足设定条件时,触发相应的中断信号并执行中断服务程序。
常见的中断触发方式包括边沿触发和电平触发。
1. 边沿触发方式边沿触发方式是通过检测GPIO输入引脚输入信号的上升沿(从低电平到高电平)或下降沿(从高电平到低电平)来触发中断。
这种方式适用于需要监测一些特定瞬态事件的场景。
例如,在某个系统中,需要检测按键的按下事件。
当按键被按下时,GPIO引脚的输入信号会从低电平突变到高电平,此时可以通过配置GPIO中断触发为上升沿触发,来触发中断并执行相应的按键处理函数。
同样地,当按键松开时,GPIO 引脚的输入信号会从高电平突变到低电平,可以通过配置GPIO中断触发为下降沿触发来实现对按键松开事件的检测。
2. 电平触发方式电平触发方式是通过检测GPIO输入引脚输入信号的高电平或低电平来触发中断。
当输入信号保持在设定的电平状态时触发中断。
例如,在某个系统中,需要检测外部传感器的状态变化。
传感器的输出信号一旦达到设定的电平,可以通过配置GPIO中断触发为高电平触发或低电平触发来触发中断,并执行相应的处理函数。
三、GPIO中断触发方式的配置GPIO中断触发方式的配置可以通过软件编程来实现。
以下是一个示例代码(使用C语言)的片段,演示了如何配置GPIO引脚的中断触发方式。
实验 8-2 键盘中断驱动实验

实验8-2 键盘中断驱动实验【实验目的】掌握键盘原理。
熟悉驱动的中断机制。
【实验步骤】第一步:利用vi编辑器,编写一个Keypad.c驱动代码;1、增加驱动所需的头文件和变量#include<linux/module.h>#include<linux/kernel.h>#include<linux/init.h>#include<linux/delay.h>#include<linux/poll.h>#include<linux/spinlock.h>#include<asm/hardware.h>#include<asm/arch-pxa/pxa-regs.h>MODULE_LICENSE("GPL");#define DEVICE_NAME "emdoor_kbd"#define KEYVALUE_HAVE 1#define KEYVALUE_NO 0#define KPC_DIR 1<<5#define KPC_MAT 1<<22static int Emdoor_kbd_fasync(int, struct file* ,int); typedef unsigned char KBD_RET;struct fasync_struct * fasync;//键盘结构体定义typedef struct {KBD_RET kbd_buff; /* protect against overrun */ unsigned int kbd_status;wait_queue_head_t wq;spinlock_t lock;} KBD_DEV;2、实现键盘驱动读操作函数static ssize_t Emdoor_kbd_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){KBD_DEV * kbd=filp->private_data;KBD_RET kbd_ret;while(1){if(kbd->kbd_status==KEYVALUE_HAVE){kbd_ret = kbd->kbd_buff;copy_to_user(buffer, &kbd_ret, sizeof(KBD_RET));kbd->kbd_status=KEYVALUE_NO;return sizeof(KBD_RET);}else{if (filp->f_flags & O_NONBLOCK)return -EAGAIN;interruptible_sleep_on(&(kbd->wq));if (signal_pending(current))return -ERESTARTSYS;}}return sizeof(KBD_RET);}3、实现键盘驱动中断服务例程static void Emdoor_isr_kbd(int irq, void *dev_id, struct pt_regs *reg){printk(KERN_EMERG"Emdoor_isr_kbd,Interrupt\n");int kpc_value;KBD_DEV * kbd = (KBD_DEV *) dev_id;spin_lock_irq(&(kbd->lock));kpc_value=KPC;if(kpc_value&KPC_MAT) {kbd->kbd_buff=KPAS&0xFF;if(kbd->kbd_buff!=0xFF){switch(kbd->kbd_buff){case 0x0: kbd->kbd_buff=5; break;case 0x1: kbd->kbd_buff=6; break;case 0x2: kbd->kbd_buff=7; break;case 0x5: kbd->kbd_buff=8; break;case 0x10: kbd->kbd_buff=9; break;case 0x11: kbd->kbd_buff=10; break;case 0x12: kbd->kbd_buff=11; break;case 0x15: kbd->kbd_buff=12; break;case 0x20: kbd->kbd_buff=13; break;case 0x21: kbd->kbd_buff=14; break;case 0x22: kbd->kbd_buff=15; break;case 0x25: kbd->kbd_buff=16; break;default: break;}kbd->kbd_status=KEYVALUE_HAVE;}}else if(kpc_value&KPC_DIR){kbd->kbd_buff=KPDK&0xFF;if(kbd->kbd_buff!=0x0){switch(kbd->kbd_buff){case 0x40: kbd->kbd_buff=1; break;case 0x2: kbd->kbd_buff=2; break;case 0x4: kbd->kbd_buff=3; break;case 0x20: kbd->kbd_buff=4; break;default: break;}kbd->kbd_status=KEYVALUE_HAVE;}}if ( fasync )kill_fasync( &(fasync), SIGIO, POLL_IN );wake_up_interruptible(&(kbd->wq));spin_unlock_irq(&(kbd->lock));}4、实现键盘驱动设备打开操作函数static int Emdoor_kbd_open(struct inode *inode, struct file *filp) {int ret;printk(KERN_EMERG " Emdoor_kbd_open!\n");KBD_DEV * kbd;kbd =(KBD_DEV *) kmalloc(sizeof(KBD_DEV ), GFP_KERNEL);KPC=KPC_ASACT | (3<<26) | (7<<23 ) | KPC_IMKP | KPC_MS6 |KPC_MS5 |KPC_MS4 | KPC_MS3 | KPC_MS2 | KPC_MS1 | KPC_MS0 | KPC_ME |KPC_MIE | (7<<6) | KPC_DE | KPC_DIE;init_waitqueue_head(&(kbd->wq));pxa_gpio_mode(94 | GPIO_ALT_FN_1_IN);//KP_DKIN<1>pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN);//KP_DKIN<2>pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN);pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN);pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN);pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN);pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN);pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT);//KP_MKOUT<0>pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT);//KP_MKOUT<1>pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT);//KP_MKOUT<2>pxa_gpio_mode(108 | GPIO_ALT_FN_2_OUT);//KP_MKOUT<5>kbd->kbd_status=KEYVALUE_NO;filp->private_data=kbd;ret = request_irq(IRQ_KEYPAD, Emdoor_isr_kbd, SA_INTERRUPT, DEVICE_NAME, kbd);if (ret){printk(KERN_EMERG " Interrupt init=%x!!!!\n",ret);return ret;}return 0;}5、实现键盘驱动select和poll操作函数static unsigned int Emdoor_kbd_poll(struct file *filp,struct poll_table_struct *wait){printk(KERN_EMERG " Emdoor_kbd_poll!\n");KBD_DEV * kbd=filp->private_data;poll_wait(filp,&(kbd->wq),wait);return (kbd->kbd_status==KEYVALUE_HAVE) ? (POLLIN|POLLRDNORM): 0 ;}static int Emdoor_kbd_release(struct inode *inode, struct file *filp){printk(KERN_EMERG " Emdoor_kbd_release!\n");KBD_DEV * kbd = filp->private_data;KPC=0x0;Emdoor_kbd_fasync(-1, filp, 0);kfree(kbd );free_irq(IRQ_KEYPAD, kbd);return 0;}6、实现键盘驱动非阻塞访问操作函数static int Emdoor_kbd_fasync(int fd, struct file * file, int mode) {return fasync_helper(fd, file, mode, &(fasync) );}7、键盘驱动文件结构体定义static struct file_operations Keypad_fops = {open: Emdoor_kbd_open,read: Emdoor_kbd_read,release: Emdoor_kbd_release,poll: Emdoor_kbd_poll,fasync: Emdoor_kbd_fasync,owner: THIS_MODULE,};8、键盘驱动初始化函数定义static int __init Emdoor_kbd_init(void){printk(KERN_EMERG " Emdoor_kpd initialized\n");int ret;ret = register_chrdev(62, DEVICE_NAME, &Keypad_fops);if (ret < 0) {printk(DEVICE_NAME " can't get major number\n");return ret;}free_irq(IRQ_KEYPAD,NULL);udelay(10);return 0;}9、键盘驱动退出函数定义static void __exit Emdoor_kbd_exit(void){printk(KERN_EMERG " Emdoor_kpd exit\n");unregister_chrdev(62, DEVICE_NAME);}module_init(Emdoor_kbd_init);module_exit(Emdoor_kbd_exit);MODULE_AUTHOR("Ben.li@");MODULE_DESCRIPTION("This is a Keypad driver demo");第二步: 利用vi编辑器,编写一个用于编译Keypad驱动的Makefile# Makefile for the Keypad. #CFLAGS +=$(DEBFLAGS) -Wallifneq ($(KERNELRELEASE),)obj-m :=Keypad.oelseKERNELDIR ?=/root/work/linux-2.6.9PWD :=$(shell pwd)ALL:$(MAKE) $(CFLAGS) -C $(KERNELDIR) M=$(PWD) modulesendifclean:rm -fr *.o *.ko *~ core .depend .*.cmd *.mod.c .tmp_versions第三步:运行make编译命令,用ls命令查看编译后的结果,在该目录中应生成Keypad.ko模块文件,利用file命令查看Keypad.ko文件的格式,应为ARM 格式的ELF文件。
linux gpio中断应用实例

linux gpio中断应用实例Linux GPIO(General Purpose Input/Output,通用输入输出)中断是一种用于处理外部设备事件的方式。
当外部设备产生一个事件时,它会向CPU发送一个信号,这个信号被称为中断。
CPU在接收到中断信号后,会暂停当前的任务,转而去处理这个中断事件。
处理完中断事件后,CPU会返回到被暂停的任务继续执行。
这种机制使得CPU 可以高效地处理多个任务,而不会被某个任务阻塞。
在Linux系统中,GPIO中断主要应用于以下场景:1. 按键事件处理:当用户按下或松开一个按键时,会产生一个中断事件。
通过配置GPIO中断,可以实现对按键事件的实时响应。
2. 传感器数据采集:许多传感器设备(如温度传感器、湿度传感器等)会周期性地产生数据。
通过配置GPIO中断,可以实现对这些数据的实时采集和处理。
3. 马达控制:通过配置GPIO中断,可以实现对马达的启动、停止和速度控制。
下面是一个使用Linux GPIO中断的简单实例:实现一个LED灯的闪烁控制。
首先,我们需要配置GPIO中断。
在这个例子中,我们将使用GPIO 4作为中断引脚,连接到一个按钮开关。
当按下按钮时,LED灯会闪烁。
1. 配置GPIO 4为输入模式:bashecho "4" > /sys/class/gpio/exportecho "in" > /sys/class/gpio/gpio4/direction2. 配置GPIO中断:bashecho "4" > /sys/class/gpio/gpio4/irqecho "1000" > /sys/class/gpio/gpio4/edgeecho "1" > /sys/class/gpio/gpio4/debounce这里,我们设置了GPIO 4的中断触发方式为上升沿触发(edge),并设置了去抖动时间(debounce)。
linux中断处理流程

linux中断处理流程Linux中断处理流程Linux中断处理是操作系统中的一个重要组成部分,用于响应硬件设备的事件。
在Linux中,中断可以是外部中断,如硬件设备发送的中断信号,也可以是内部中断,如软件产生的异常或系统调用。
中断处理的目的是及时响应硬件设备的事件,并采取相应的措施来处理这些事件。
一、中断的触发中断是由硬件设备发送的一个信号,用于通知操作系统某个事件的发生。
这个信号可以是一个电平的变化,一个特定的数据包,或者一个指定的硬件寄存器的变化。
当硬件设备检测到某个事件发生时,它会向处理器发送一个中断信号,处理器会立即停止当前正在执行的任务,保存当前的上下文,并跳转到中断处理程序的入口点。
二、中断处理程序的执行中断处理程序是一个特殊的函数,负责处理中断事件。
当中断发生时,处理器会跳转到中断处理程序的入口点,并执行相应的代码。
中断处理程序的执行过程可以分为以下几个步骤:1. 保存上下文:在执行中断处理程序之前,处理器需要保存当前任务的上下文,包括程序计数器、寄存器和堆栈指针等。
这样可以确保在中断处理程序执行完成后,能够正确地返回到原来的任务。
2. 中断处理程序的执行:一旦保存了上下文,处理器就会执行中断处理程序的代码。
中断处理程序根据中断的类型,执行相应的操作。
例如,对于外部中断,中断处理程序可能需要读取硬件设备的状态,处理数据包或执行特定的操作。
对于内部中断,中断处理程序可能需要处理异常或系统调用。
3. 中断处理程序的结束:当中断处理程序执行完成后,处理器会恢复之前保存的上下文,并将控制权返回给原来的任务。
这样原来的任务就可以继续执行,而不会受到中断的影响。
三、中断处理的优先级在Linux中,中断处理有不同的优先级。
这是为了确保对于紧急事件的及时处理。
中断的优先级由硬件设备决定,通常是通过一个优先级编码器来实现的。
当多个中断同时发生时,处理器会按照优先级的顺序来处理中断。
高优先级的中断会立即被处理,而低优先级的中断则会被推迟到稍后处理。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
ARM-Linux下的GPIO中断程序[日期:2011-03-22] 来源:Linux社区作者:cskywit今日为了调试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 toPB18(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_descPB18_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();errrequest_irq(PB18_IRQ.irq,PB18_intHandle,PB18_IRQ.flags,PB18_,(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;}// ioctlint 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;}由上面的代码可以看出,Linux内核在中断程序处理方面已经做了很多抽象,对于驱动程序编写者只需要按照内核中断构架去实现一定的控制函数就可以,以后有时间会专门撰文剖析还原Linux内核里那些对中断实现的抽象。