1, Fundamentals of interruption
1. What is interruption
Interrupt means that the CPU needs to stop the execution of the current program, turn to deal with emergencies, and return to the original program after processing.
2. Hardware interrupt and software interrupt
Hardware interrupt generally refers to the interrupt request sent by the peripheral and the interrupt generated by the internal hardware (calculation overflow, divisor 0, power failure, etc.)
Software interrupt, typically the lower half of the interrupt handler
3. Interrupt priority
According to the importance and urgency of interrupt events, the system divides interrupt sources into several levels, and the one with high priority shall be executed first.
2, Hardware connection of key
There are five independent buttons on the base plate. Take HOME and BACK as examples. Let's take a look at the schematic diagram, as shown in the figure below.
It can be seen from the hardware connection that the IO interrupt in the default state is high. Therefore, it can be judged that the following interrupt triggering mode should be falling edge triggering.
Two network UARTS_ Ring and SIM_DET.
The corresponding GPIO is "EXYNOS4_GPX1(1)" and the interrupt number is "XEINT9"
The corresponding GPIO is "EXYNOS4_GPX1(2)" and the interrupt number is "XEINT10"
You can see that the pin configuration for external interrupt mode needs to be set to 0xF.
Finally, let's take a look at another part. In Chapter 56 of the Datasheet, find Debouncing Filter, which is the part of 4412 for automatic anti shake of keys. As shown in the figure below, you can see that there is its own anti shake.
3, Interrupt correlation function
1.request_irq
Linux interrupts need to be applied before use. The interrupt application function is "request_irq", which is in the header file "include/linux/interrupt.h", as shown in the following figure.
Interrupt request function_ irq(unsigned int irq, irq_handler_t handler,
unsigned long flags,const char *name, void *dev) have the following parameters.
Parameter unsigned int irq: irq is the interrupt number
Parameter irq_handler_t handler: handler is the processing function registered with the system
Parameter unsigned long flags: irqflags is the trigger flag bit
Parameter const char *name: devname is the interrupt name, which can be viewed through "cat/proc/interrupts" after registration
Parameter void *dev: dev_id is the device
2. free_irq
Corresponding to the above interrupt application function is the interrupt release function free_irq, which needs to be called when unloading the driver, as shown in the following figure, is also in the header file "include/linux/interrupt.h".
Interrupt release function extern void free_irq(unsigned int, void *); The parameters are as follows.
Parameter 1: irq is the interrupt number
Parameter 2: dev_id is the device
3.irqreturn_t
After an interrupt is generated, the interrupt handler irqreturn will be called_ t. This function is also in the header file
"include/linux/interrupt.h" is shown in the following figure.
This function is extern irqreturn_t no_action(int cpl, void *dev_id);
The interrupt function type is irqreturn_t
Parameter int cpl: interrupt number
Parameter void *dev_id: device
4. Interrupt number
In the initialization file "drivers / GPIO / GPIO exynos4. C", as shown in the following figure
vim drivers/gpio/gpio-exynos4.c
The two interrupt pins selected belong to "GPX1", so as shown in the above figure, the basic value of interrupt number is IRQ_EINT(8), then GPX1CON[0] and GPX1CON[1] correspond to the interrupt number IRQ_EINT(9) and IRQ_EINT(10).
If you want to call other external interrupts, you can also check the interrupt number in this way, but only if the interrupt is not occupied.
4, Experimental operation
The actual application of external interrupts is generally integrated in some similar sound cards, graphics cards and other bus devices. The actual application is to call the header files and functions mentioned above, apply for interrupts during driver initialization, and then write interrupt function processing functions for specific drivers. For example, the volume button in the sound card is integrated into the sound card of the key part code, and the key can be adjusted to turn up the volume accordingly.
A simple character driver is registered here. In this way, it will be easy for everyone to understand. The function to be completed is to print data after the key interrupt is generated.
1. Registered equipment
As shown in the figure below, add the code for registering the device in the platform file "arch / arm / Mach exynos / Mach itop4412. C".
vim arch/arm/mach-exynos/mach-itop4412.c
For simplicity, you can force the registration of devices without defining macro variables. (not written #ifdef)
2. Add the code called by the device
It's still in the last file
3.menuconfig configuration
Then open the menuconfig configuration file and uninstall the drivers that use these two interrupts.
Device Drivers —>
Input device support —>
Keyboards —>
Cancel GPIO Buttons - >
After the reset, recompile the kernel, and burn the generated binary zImage file to the development board to replace the original kernel.
4. Write driver
1. Drive fixed header file
As shown in the figure below, for the header file part, the driver who writes 4412 in the future can add these header files to the front of the code.
/* Later, the write driver can load the header file in front of the code */ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/miscdevice.h> #include <linux/platform_device.h> #include <mach/regs-gpio.h> #include <asm/io.h> #include <linux/regulator/consumer.h> #include <linux/delay.h> /* Interrupt function header file */ #include <linux/interrupt.h> #include <linux/irq.h>
2. Application function irq_probe
First of all, interrupt IO is detected, whether it is occupied or not. The way of processing is usually to apply for IO to see if it is successful. After the application is successful, GPIO is configured as a pull up mode, and then gpio_ is called. Free release it.
The parameter "irq_type_edge_failing" is used, which represents falling edge triggering. This macro is defined in the header file "include/linux/irq.h", as shown in the following figure.
3.Makefile
The omission is the same as the previous one
4.itop4412_irq.c
/* Later, the write driver can load the header file in front of the code */ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/miscdevice.h> #include <linux/platform_device.h> #include <mach/regs-gpio.h> #include <asm/io.h> #include <linux/regulator/consumer.h> #include <linux/delay.h> /* Interrupt function header file */ #include <linux/interrupt.h> #include <linux/irq.h> #define IRQ_DEBUG #ifndef IRQ_DEBUG #define DPRINTK(x...) printk("IRQ_CTL DEBUG:" x) #else #define DPRINTK(x...) #endif #define DRIVER_NAME "irq_test" MODULE_LICENSE("Dual BSD/GPL"); /* Define interrupt handling functions */ static irqreturn_t eint9_interrupt(int irq,void *dev_id) { printk("%s(%d)\n",__FUNCTION__,__LINE__); return IRQ_HANDLED; } static irqreturn_t eint10_interrupt(int irq,void *dev_id) { printk("%s(%d)\n",__FUNCTION__,__LINE__); /*The above uses a special code "printk" ("% s (% d) \ n", _function _, _line); "This code is very useful in debugging, that is, print the current function and the corresponding line, The effect can be seen in the later test.*/ return IRQ_HANDLED; } static int irq_probe(struct platform_device *pdev) { int ret; char *banner = "irq_test Initialize!\n"; printk(banner); /* First IO */ ret = gpio_request(EXYNOS4_GPX1(1),"EINT9"); if(ret) { printk("%s:request GPIO %d for EINT9 failed,ret = %d!\n",DRIVER_NAME,EXYNOS4_GPX1(1),ret); return ret; } s3c_gpio_cfgpin(EXYNOS4_GPX1(1),S3C_GPIO_SFN(0xF)); s3c_gpio_setpull(EXYNOS4_GPX1(1),S3C_GPIO_PULL_UP); gpio_free(EXYNOS4_GPX1(1)); /* Second IO*/ ret = gpio_request(EXYNOS4_GPX1(2),"EINT10"); if(ret) { printk("%s:request GPIO %d for EINT10 failed,ret = %d!\n",DRIVER_NAME,EXYNOS4_GPX1(2),ret); return ret; } s3c_gpio_cfgpin(EXYNOS4_GPX1(2),S3C_GPIO_SFN(0xF)); s3c_gpio_setpull(EXYNOS4_GPX1(2),S3C_GPIO_PULL_UP); gpio_free(EXYNOS4_GPX1(2)); /* interrupt */ ret = request_irq(IRQ_EINT(9),eint9_interrupt,IRQ_TYPE_EDGE_FALLING,"eint9",pdev); if(ret < 0) { printk("Request IRQ %d failed,%d\n",IRQ_EINT(9),ret); goto exit; } ret = request_irq(IRQ_EINT(10),eint10_interrupt,IRQ_TYPE_EDGE_FALLING,"eint10",pdev); if(ret < 0) { printk("Request IRQ %d failed,%d\n",IRQ_EINT(10),ret); goto exit; } return 0; exit: return ret; } static int irq_remove(struct platform_device *pdev) { free_irq(IRQ_EINT(9),pdev); // Release interrupt free_irq(IRQ_EINT(10),pdev); // Release interrupt return 0; } static int irq_suspend(struct platform_device *pdev,pm_message_t state) { DPRINTK("irq suspend:power off!\n"); return 0; } static int irq_resume(struct platform_device *pdev) { DPRINTK("irq resume:power on!\n"); return 0; } /* Entry function and exit function of driver module */ static struct platform_driver irq_driver = { .probe = irq_probe, .remove = irq_remove, .suspend = irq_suspend, .resume = irq_resume, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, }, }; static void __exit irq_test_exit(void) { platform_driver_unregister(&irq_driver); // Unload driver } static int __init irq_test_init(void) { return platform_driver_register(&irq_driver); // Register driver } module_init(irq_test_init); module_exit(irq_test_exit);
5. Compilation
New folder
mkdir irq_test
compile;
6. Development board operation
1. Load drive
insmod itop4412_irq.ko
2. View the interruption of the application
cat /proc/interrupts
3. Test
Press the HOME and BACK buttons a few times, and the following printing information will appear
Finally, use the command "cat /proc/interrupts" to view the applied interrupts, as shown in the figure below. It has been detected that the two interrupts have been triggered several times respectively.