什么是中断处理程序?编写中断处理程序时要注意哪些问题?

什么是中断处理程序?编写中断处理程序时要注意哪些问题?,第1张

发生中断时CPU在中断允许的情况下,强制跳转至中断处理程序对该中断进行响应。

中断处理程序需要注意:

若是改写系统中断,尽量保存系统中断的原地址;

如果是自定义中断,需要注意是否允许多重中断,即能否被另一个中断(包括同一个中断号的相同中断)打断,若不希望被打断,应当在中断处理程序开始时关闭中断允许位IF(用CLI指令),并且在程序结束时开启中断位(用STI指令)。

另外,中断处理程序本身也是一个过程,也有可能出错,所以尽量不要在中断处理程序中产生错误,以免程序不可控。

方法1. 用关键词interrupt和中断矢量编号定义中断函数

这种方式最简单也最直观。缺点是程序的可移植性稍差。范例如下:

void interrupt 17 sci1_Recv_ISR(void){

.......}关键词interrupt告诉编译器此函数为中断服务函数,数字17告诉连接器该中断矢量的偏移位置(以复位矢量偏移为0计)。某一个中断响应对应的矢量入口编号可以在该芯片的DataSheet中查到。

方法2. 用关键词interrupt定义中断函数,中断矢量入口由prm文件指定,仍以上面的中断服务函数为例,这时函数的定义方式为

void interrupt sci1_Recv_ISR(void){

........}然后在项目对应的prm文件中添加一行矢量位置定义:

VECTOR 17 sci1_Recv_ISR //指定的中断服务矢量入口

方法3. 用#pragma TRAP_PROC定义中断函数,中断矢量入口由prm文件指定。此类型的函数编译器在将C代码编译成汇编指令时会在代码前后增加必要的现场保护和恢复汇编代码,同时函数的最后返回用汇编指令RTI而不是针对普通函数的RTS。例如

关于按键,在DVK521上为:

我又从一份数据手册中看到,PI7,PI8,PI9是没有外部中断功能的。如下图所示:

还好,目前的按键是通过短接帽来连接PI7 PI9的,那么可以将短接帽拿掉,使用杜邦线连接PI10 PI12。

现在我将Key2连接到PI10上。那么KEY2的中断引脚为EINT22。

配置sys_config.fex文件:

现在使用的树莓派A20,是一个双核A7的芯片,而这个属于SMP架构,中断处理方式也已经和原先的理念大有不同。所以还是要知道关于linux的中断原理,可以从网络中获取相关历史性技术知识。

从A20的数据手册中,可以看到外部中断数到了EINT31。也就是说PIO中断功能有32个。

下面列出的API函数是在 \linux-sunxi\arch\arm\plat-sunxi\Sys_config.c中。

1.gpio_request_ex(),获取sys_config.fex中设置的中断IO口。

2.gpio_set_one_pin_io_status(),设置为输入状态。

3.gpio_set_one_pin_pull(),设置输入引脚的上下拉状态。

4.request_irq()注册中断函数。

request_irq()函数:

第一个参数为SW_INT_IRQNO_PIO,表示是外部端口的中断号。

第二个参数为中断处理函数名。

第三个参数为中断方式,如IRQ_TYPE_EDGE_RISING,上升沿触发,而IRQ_TYPE_EDGE_FALLING则是下降沿触发,IRQF_SHARED为共享。

第四个参数为中断名。

第五个参数为中断传递的数据。

1.获取IO中断源信息

由于内核使用的是虚拟地址寻址硬件地址,获取中断源就需要将IO硬件地址空间映射到虚拟地址上。可以使用ioremap(PIO_BASE_ADDRESS, PIO_RANGE_SIZE)进行映射。

2.屏蔽中断源

a.读取中断源寄存器的状态,可以使用readl(映射的IO地址 + PIO_INT_STAT_OFFSET)

b.判断对应的中断,使用writel(reg_val&(1<<(CTP_IRQ_NO)),映射的IO地址 + PIO_INT_STAT_OFFSET)清除状态位。

写到这里,本应该很顺利,可是,在驱动程序加载进内核的时候,明显是报错。错误我就不贴出来了,可是我可以将中断信息附上:

从这里,可以看出来,PIO中断号60已经注册进内核了。我们现在使用的一个IO中断是被包含在里面的。所以,需要在内核中找到sunxi-gpio是怎么去注册中断,而我们就需要将我们的中断程序内容附加到已经注册的中断上去。

在 marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\gpio\Gpio-sunxi.c中我们可以找到函数:

里面最重要的函数是:

最终调用的是:

然而,它又被赋值了:

在一定程度的意义上,gpio-sunxi.c已经将中断基本处理做好了,我们要做的只是和它共享中断。

sys_config.fex文件配置如下:

从上面的实验中,已经发现在request_irq中设置边沿等等触发,在安装ko文件的时候,都会报错,从这里看出,在共享中断的时候,是不允许设置其他的内容的。那么,只能去找A20寄存器中关于io口中断的设置。在这些设置已经设置好的情况下,中断应该就能响应了。这里贴出一个比较简单的驱动程序:

int main(int argc,char *argv[])

{

int fd

int val

fd = open("/dev/key_device",O_RDWR)

if(fd <0){

printf("---open file error----\r\n")

return -1

}

}

ifeq ($(KERNELRELEASE),)

KERNEL_DIR=/home/wityuan/Downloads/MarsBoard-A20-Linux-SDK-V1.2/linux-sunxi

PWD=$(shell pwd)

modules:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules

arm-linux-gnueabihf-gcc -o key key.c

modules_install:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install

clean:

rm -rf *.ko *.o .tmp_versions .mod.c modules.order Module.symvers . .cmd

else

obj-m:=key.o

endif

root@marsboard:~# ./key_test

---script.bin key get ok,value:1----

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

key irq Interrupt

==IRQ_EINT22=

^Ckey irq Interrupt

Other Interrupt

----key close----

root@marsboard:~#

root@marsboard:~#

/* EINT type PIO controller registers */

/* EINT type defines */

static int int_cfg_addr[] = {PIO_INT_CFG0_OFFSET,

PIO_INT_CFG1_OFFSET,

PIO_INT_CFG2_OFFSET,

PIO_INT_CFG3_OFFSET}

/* Setup GPIO irq mode (FALLING, RISING, BOTH, etc */

})

/* Enable GPIO interrupt for pin */

})

/* Disable GPIO interrupt for pin */

})

/* Set GPIO pin mode (input, output, etc) /

/ GPIO port has 4 cfg 32bit registers (8 pins each) /

/ First port cfg register addr = port_num * 0x24*/

})

static script_gpio_set_t info

static unsigned key_handler1

static unsigned key_handler2

static struct class *key_class

static struct device *key_device

static unsigned int key_major

static unsigned int key_value

static void *__iomem gpio_addr = NULL

static int key_open(struct inode *inode, struct file *filp)

static ssize_t key_read (struct file *, char __user *, size_t, loff_t *)

static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off)

static int key_close(struct inode *inode, struct file *filp)

struct file_operations key_operations = {

.owner = THIS_MODULE,

.open= key_open,

.read= key_read,

.write = key_write,

.release = key_close,

}

struct key_str{

char *name

int val

}

struct key_str g_key_str[2]={{"key1",0x1},{"key2",2}}

static irqreturn_t key_irq_handler1(int irq, void *dev_id)

{

int err

int reg_val = 0

int ret_val = 0

}

static irqreturn_t key_irq_handler2(int irq, void *dev_id)

{

}

static ssize_t key_read (struct file *file, char __user *buf, size_t len, loff_t *off)

{

unsigned int value = 0

value = copy_to_user(buf,&key_value,4)

}

static int key_open(struct inode *inode, struct file *filp)

{

int err = 0

int key_test_enabled = 0

int ret = 0

}

static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off)

{

}

static int key_close(struct inode *inode, struct file *filp)

{

SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT22)

SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT23)

}

static int __init key_init(void)

{

key_major = register_chrdev(0, "key_chrdev", &key_operations)

}

static void __exit key_exit(void)

{

if (gpio_addr) {

iounmap(gpio_addr)

}

}

module_init(key_init)

module_exit(key_exit)

MODULE_DESCRIPTION("Driver for key")

MODULE_AUTHOR("wit_yuan")

MODULE_LICENSE("GPL")

ifeq ($(KERNELRELEASE),)

KERNEL_DIR=/home/wityuan/Downloads/MarsBoard-A20-Linux-SDK-V1.2/linux-sunxi

PWD=$(shell pwd)

modules:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules

arm-linux-gnueabihf-gcc -o key key.c

modules_install:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install

clean:

rm -rf *.ko *.o .tmp_versions .mod.c modules.order Module.symvers . .cmd

else

obj-m:=key.o

endif

int main(int argc,char *argv[])

{

int fd

int val

fd = open("/dev/key_device",O_RDWR)

if(fd <0){

printf("---open file error----\r\n")

return -1

}

}

/* EINT type PIO controller registers */

/* EINT type defines */

static wait_queue_head_tkey_data_avail

static unsigned int key_done = 0

static int int_cfg_addr[] = {PIO_INT_CFG0_OFFSET,

PIO_INT_CFG1_OFFSET,

PIO_INT_CFG2_OFFSET,

PIO_INT_CFG3_OFFSET}

/* Setup GPIO irq mode (FALLING, RISING, BOTH, etc */

})

/* Enable GPIO interrupt for pin */

})

/* Disable GPIO interrupt for pin */

})

/* Set GPIO pin mode (input, output, etc) /

/ GPIO port has 4 cfg 32bit registers (8 pins each) /

/ First port cfg register addr = port_num * 0x24*/

})

static script_gpio_set_t info

static unsigned key_handler1

static unsigned key_handler2

static struct class *key_class

static struct device *key_device

static unsigned int key_major

static unsigned int key_value

static void *__iomem gpio_addr = NULL

static int key_open(struct inode *inode, struct file *filp)

static ssize_t key_read (struct file *, char __user *, size_t, loff_t *)

static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off)

static int key_close(struct inode *inode, struct file *filp)

struct file_operations key_operations = {

.owner = THIS_MODULE,

.open= key_open,

.read= key_read,

.write = key_write,

.release = key_close,

}

struct key_str{

char *name

int val

}

struct key_str g_key_str[2]={{"key1",0x1},{"key2",2}}

static irqreturn_t key_irq_handler1(int irq, void *dev_id)

{

int err

int reg_val = 0

int ret_val = 0

}

static irqreturn_t key_irq_handler2(int irq, void *dev_id)

{

}

static ssize_t key_read (struct file *file, char __user *buf, size_t len, loff_t *off)

{

unsigned int value = 0

}

static int key_open(struct inode *inode, struct file *filp)

{

int err = 0

int key_test_enabled = 0

int ret = 0

}

static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off)

{

}

static int key_close(struct inode *inode, struct file *filp)

{

SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT22)

SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT23)

}

static int __init key_test_init(void)

{

key_major = register_chrdev(0, "key_chrdev", &key_operations)

}

static void __exit key_test_exit(void)

{

if (gpio_addr) {

iounmap(gpio_addr)

}

}

module_init(key_test_init)

module_exit(key_test_exit)

MODULE_DESCRIPTION("Driver for key")

MODULE_AUTHOR("wit_yuan")

MODULE_LICENSE("GPL")

ifeq ($(KERNELRELEASE),)

KERNEL_DIR=/home/wityuan/Downloads/MarsBoard-A20-Linux-SDK-V1.2/linux-sunxi

PWD=$(shell pwd)

modules:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules

arm-linux-gnueabihf-gcc -o key key.c

modules_install:

$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install

clean:

rm -rf *.ko *.o .tmp_versions .mod.c modules.order Module.symvers . .cmd

else

obj-m:=key.o

endif

int main(int argc,char *argv[])

{

int fd

int val

fd = open("/dev/key_device",O_RDWR)

if(fd <0){

printf("---open file error----\r\n")

return -1

}

}


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/7721998.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-09
下一篇 2023-04-09

发表评论

登录后才能评论

评论列表(0条)

保存