在之前的单片机入门的时候也是hello world,然后led,然后按键中断。
下面我们要开始中中断部分的学习。,在之前的裸机开发中,我们已经了解了中断的开发步骤,在内核中使用按键触发中断,会变的更容易一些,因为内核已经帮我们完成了很多工作,我们只需要理解整个调用及修改过程。
soc中有很多的中断,我们通过中断号进行区分是哪个中断,然后写对应的中断处理函数。
如何获取中断号?
1, 宏定义(中断相关的头文件)
IRQ_EINT(号码)
2,设备树文件中
arch/arm/boot/dts/exynos4412-fs4412.dts
一.怎么将按键中断添加到内核
在内核中,通过设备树对外设进行修改,关联。
1.
打开我们的设备树文件arch/arm/boot/dts/exynos4412-origen.dts
可以看到包含#include “exynos4412.dtsi”文件。打开这个文件。可以看到这个文件又包含
#include “exynos4x12.dtsi”,里面又包含#include “exynos4.dtsi”, “exynos4x12-pinctrl.dtsi”
我们打开exynos4x12-pinctrl.dtsi,
找到gpx1。
假如现在通过K3进行中断的相应,管脚对应EINT10,
在编程过程中,需要定义自己的节点--描述当前设备用的中断号
arch/arm/boot/dts/exynos4412-origen.dts //文件的64行添加自己的设备树节点。
key_int_node{
compatible = "test_key";
interrupt-parent = <&gpx1>;
interrupts = <2 4>;//ENIT10 数据手册上标注是26,从设备树文件gpx1进行继承中我们
数是在第二组上,4是触发方式。
};
2.
编译设备树文件:
make dtbs
更新dtbs文件:
cp -raf arch/arm/boot/dts/exynos4412- origen.dtb /tftpboot/
3.
然后在串口终端中 /proc/device-tree/key
查看中断是否已经添加进来。
发现已经添加进来了。但是此时我们按按键,还是不会有任何反应的。
4.编写驱动
开始编写驱动之前先知道怎么通过程序获取中断号码?
(1)获取到设备树中到节点
struct device_node *np = of_find_node_by_path("/key_int_node");
(2)通过节点去获取到中断号码
int irqno = irq_of_parse_and_map(np, 0);
如何申请中断?
函数(申请中断) | int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char * name, void * dev) |
参数 | 参数1: 设备对应的中断号 参数2: 中断的处理函数 typedef irqreturn_t (*irq_handler_t)(int, void *); 参数3:触发方式 #define IRQF_TRIGGER_NONE 0x00000000 //内部控制器触发中断的时候的标志 #define IRQF_TRIGGER_RISING 0x00000001 //上升沿 #define IRQF_TRIGGER_FALLING 0x00000002 //下降沿 #define IRQF_TRIGGER_HIGH 0x00000004 // 高点平 #define IRQF_TRIGGER_LOW 0x00000008 //低电平触发 参数4:中断的描述,自定义,主要是给用户查看的 /proc/interrupts 参数5:传递给参数2中函数指针的值 返回值: 正确为0,错误非0 |
返回值: | 正确为0,错误非0 |
函数(释放中断) | void free_irq(unsigned int irq, void *dev_id) |
参数 | 参数1: 设备对应的中断号 参数2:与request_irq中第5个参数保持一致 |
代码实例:
key_dev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
int irqno;
int get_irqno_from_node(void)
{
// 获取到设备树中到节点
struct device_node *np = of_find_node_by_path("/key_int_node");
if(np){
printk("find node ok\n");
}else{
printk("find node failed\n");
}
// 通过节点去获取到中断号码
int irqno = irq_of_parse_and_map(np, 0);
printk("irqno = %d\n", irqno);
return irqno;
}
irqreturn_t key_irq_handler(int irqno, void *devid)
{
printk("-------%s-------------\n", __FUNCTION__);
return IRQ_HANDLED;
}
static int __init key_init(void)
{
int ret;
//获取中断号
irqno = get_irqno_from_node();
//申请中断
ret = request_irq(irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
"key3_eint10", NULL);
if(ret != 0)
{
printk("request_irq error\n");
return ret;
}
return 0;
}
static void __exit key_exit(void)
{
free_irq(irqno, NULL);
}
module_init(key_init);
module_exit(key_exit);
MODULE_LICENSE("GPL");
Makefile
ROOTFS_DIR = /nfs/rootfs
#APP_NAME = chr_test
CROSS_COMPILE = /home/linux/Desktop/gcc-4.6.4/bin/arm-none-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc
ifeq ($(KERNELRELEASE), )
KERNEL_DIR = /home/linux/mytest/linux-3.14
CUR_DIR = $(shell pwd)
all :
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
# $(CC) $(APP_NAME).c -o $(APP_NAME)
clean :
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
install:
cp -raf *.ko $(ROOTFS_DIR)/drv_module
else
obj-m += key_dev.o
endif
make 编译出ko文件
sudo make install //ko拷贝到nfs下
打开终端。
按下K3键
现在已经可以触发中断了,但是应用层想调用还是不行的,需要实现open read等函数。