目录
Linux内核中断
Linux内核定时器
Linux内核中断
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
功能:注册中断
参数:
@irq : 软中断号 gpio的软中断号 软中断号 = gpio_to_irq(gpio号);
gpio = m*32+n m:那一组 A B C D E → 0 1 2 3 4
n:组内的序号
gpioa28 = 0*32+28 (按键)gpiob8 = 1*32+8
gpiob8 =1*32+8 (按键) gpiob16 = 1*32+16
b24 => n=241
控制器中断号(如ADC):
find -name irqs.h ./arch/arm/mach-s5p6818/include/mach/irqs.h
find -name s5p6818_irq.h ./arch/arm/mach-s5p6818/include/mach/s5p6818_irq.h
#define IRQ_PHY_ADC (41 + 32) //IRQ_PHY_ADC软中断号
@handler: 中断的处理函数
irqreturn_t (*irq_handler_t)(int irqno, void *dev);
IRQ_NONE //中断没有处理完成
IRQ_HANDLED //中断正常处理完成
@flags :中断的触发方式
#define IRQF_DISABLED 0x00000020 //快速中断
#define IRQF_SHARED 0x00000080 //共享中断
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004
#define IRQF_TRIGGER_LOW 0x00000008
@name :名字 cat /proc/interrupts
@dev :向中断处理函数中传递参数 ,如果不想传写个NULL就行
返回值:成功0,失败返回错误码
void free_irq(unsigned int irq, void *dev_id)
功能:注销中断
参数:
@irq :软中断号
@dev_id:向中断处理函数中传递的参数 ,如果上面写的NULL,这里就写NULL
问题解决方法
[root@farsight]#insmod farsight_irq.ko
[ 21.262000] request irq146 error
insmod: can't insert 'farsight_irq.ko': Device or resource busy
通过 cat /proc/interrupts
146: GPIO nxp-keypad
154: GPIO nxp-keypad
说明中断号已经被占用了
解决办法:在内核中将这个驱动删掉
如果确定驱动文件的名字是谁?
grep "nxp-keypad" * -nR
arch/arm/mach-s5p6818/include/mach/devices.h:48:
#define DEV_NAME_KEYPAD "nxp-keypad"
grep "DEV_NAME_KEYPAD" * -nR
drivers/input/keyboard/nxp_io_key.c:324: .name = DEV_NAME_KEYPAD,
驱动文件的名字是nxp_io_key.c
如何从内核中将他去掉?
选项菜单的名字?Kconfig
config KEYBOARD_NXP_KEY
tristate "SLsiAP push Keypad support"
make menuconfig
<>SLsiAP push Keypad support
make uImage 重新编译内核
cp arch/arm/boot/uImage ~/tftpboot
计算gpio号
v
Linux内核定时器
1.定时器的当前时间如何获取?
jiffies:内核时钟节拍数
jiffies是在板子上电这一刻开始计数,只要
板子不断电,这个值一直在增加(64位)。在
驱动代码中直接使用即可。
2.定时器加1代表走了多长时间?
在内核顶层目录下有.config
CONFIG_HZ=1000 → 时钟频率1000HZ
周期 = 1/CONFIG_HZ
周期是1ms;
1.分配的对象
struct timer_list mytimer;
2.对象的初始化
struct timer_list
{
unsigned long expires; //定时的时间
void (*function)(unsigned long); //定时器的处理函数
unsigned long data; //向定时器处理函数中填写的值 一般添0
};
void timer_function(unsigned long data) //定时器的处理函数
{
}
mytimer.expries = jiffies + 1000; //中断时间1s
mytimer.function = timer_function; //timer_function中断处理函数
mytimer.data = 0;
init_timer(&mytimer); //内核帮你填充你未填充的对象
3.对象的添加定时器
void add_timer(struct timer_list *timer);
//同一个定时器只能被添加一次,
//在你添加定时器的时候定时器就启动了,只会执行一次
int mod_timer(struct timer_list *timer, unsigned long expires)
//再次启动定时器 jiffies+1000
4.对象的删除
int del_timer(struct timer_list *timer)//删除定时器
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#define GPIONO(m,n) m*32+n //计算软中断号
#define GPIO_B8 (GPIONO(1,8))//计算按键gpiob8软中断号
#define GPIO_B16 (GPIONO(1,16)) //计算按键gpiob16软中断号
struct timer_list mytimer;//声明结构体
int gpiono[] = {GPIO_B8,GPIO_B16};//数组内存入两个按键的软中断号
char *irqname[] = {"interrupt-b8","interrupt-b16"};//中断的名字
void key_irq_timer_handle(unsigned long data)//定时器中断处理函数
{
int status_b8 = gpio_get_value(GPIO_B8);//读取gpiob8数值
int status_b16 = gpio_get_value(GPIO_B16);//读取gpiob16数值
if(status_b8 == 0){//如果等于0表示按下,执行打印函数
printk("left button down............\n");
}
if(status_b16 == 0){//如果等于0表示按下,执行打印函数
printk("right button down#############\n");
}
}
irqreturn_t farsight_irq_handle(int num, void *dev)//按键产生的中断处理函数
{
mod_timer(&mytimer,jiffies+10);//开启定时器。只要触发就重新赋值,用来消抖
return IRQ_HANDLED;
}
static int __init farsigt_irq_init(void)//入口
{
int ret,i;
//1.定时器的申请
mytimer.expires = jiffies + 10;//时间
mytimer.function = key_irq_timer_handle;//定时器中断处理函数
mytimer.data = 0;//参数
init_timer(&mytimer);//将定时器信息写入进行初始化
add_timer(&mytimer);//开启一次定时器
//2.中断的申请
for(i=0;i<ARRAY_SIZE(gpiono); i++){//这里用for主要目的之申请两个中断
ret = request_irq(gpio_to_irq(gpiono[i]),farsight_irq_handle,IRQF_TRIGGER_FALLING
,irqname[i],NULL);//中断申请 参数:软中断号 中断执行函数 下降沿触发 中断的名字
if(ret){
printk("request irq%d error\n",gpio_to_irq(gpiono[i]));//申请失败提示
return ret;
}
}
return 0;
}
static void __exit farsight_irq_exit(void)出口
{
int i;
for(i=0;i<ARRAY_SIZE(gpiono); i++){//注销掉中断
free_irq(gpio_to_irq(gpiono[i]),NULL);
}
del_timer(&mytimer);//注销掉定时器
}
module_init(farsigt_irq_init);
module_exit(farsight_irq_exit);
MODULE_LICENSE("GPL");