In order to debug the GPIO pin interrupt effect on the ARM board, so that in the subsequent project, when using ARM and the ZLG7290 key LED interrupt chip to connect, I can arbitrarily select the idle GPIO pin as the interrupt signal line of the ZLG7290. I specially wrote a small Linux GPIO interrupt driver and downloaded it to the development board for experiment. It has been verified that this software interrupt method is also not satisfactory. The following is the immature code I wrote, please forgive me (
The hardware circuit of the experiment is that PB17 of ARM GPIO is connected to a common cathode LED, PB18 is connected to PB19, PB18 is set to low level trigger by interrupt driver, PB19 is controlled by GPIO driver, and the upper-level application controls the high and low level changes of PB19 by driving, thereby triggering an interrupt of PB18, and the LED of PB17 is controlled to turn on and off in the interrupt program.
Linux interrupt driver part:
/*
* PB18_IRQTest.c
* This is a test program for sam9260, using PB19(J5_18 pin) input a signal to PB18(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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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_desc PB18_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();
err = request_irq(PB18_IRQ.irq,PB18_intHandle,PB18_IRQ.flags,PB18_IRQ.name,(void*)0);
if(err)
{
free_irq(PB18_IRQ.irq,(void*)0);
return -BUSY;
}
return 0;
}
int light_release(struct inode *inode,struct file *filp)
{
free_irq(PB18_IRQ.irq,(void*)0);
return 0;
}
// ioctl
int 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 upper layer applications:
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}
As can be seen from the above code, the Linux kernel has made a lot of abstractions in interrupt program processing. Driver writers only need to implement certain control functions according to the kernel interrupt architecture. In the future, I will write a special article to analyze and restore the abstractions of interrupt implementation in the Linux kernel.
Previous article:How to determine the address space used by peripherals
Next article:Solution to LPC2378 serial port query and send lost data
Recommended ReadingLatest update time:2024-11-15 15:23
- Popular Resources
- Popular amplifiers
- Learn ARM development(14)
- Learn ARM development(15)
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Learn ARM development(14)
- Learn ARM development(15)
- Analysis of the application of several common contact parts in high-voltage connectors of new energy vehicles
- Wiring harness durability test and contact voltage drop test method
- From probes to power supplies, Tektronix is leading the way in comprehensive innovation in power electronics testing
- From probes to power supplies, Tektronix is leading the way in comprehensive innovation in power electronics testing
- Sn-doped CuO nanostructure-based ethanol gas sensor for real-time drunk driving detection in vehicles
- Design considerations for automotive battery wiring harness
- Do you know all the various motors commonly used in automotive electronics?
- What are the functions of the Internet of Vehicles? What are the uses and benefits of the Internet of Vehicles?
- CC2640R2F Battery Fuel Measurement
- 【AT-START-F425 Review】Use of GPIO port and OLED screen display driver
- How to dynamically open the Bluetooth kernel log for the Allwinner V853 chip?
- Regarding the problem of leakage current when the MOS tube is not completely turned off
- Detailed explanation: ground wire and power wire
- EEWORLD University - Introducing the SimpleLink? MCU Platform
- In a battery-powered low-power product, the ADS/DIR/open-drain/pull-up/pull-down settings of each port pin
- Introduction on how to encapsulate functions into libraries
- Basic principles of PCB anti-interference design
- TI Action Camera and Handheld Stabilizer Solutions