Skip to content

Instantly share code, notes, and snippets.

@amolyp
Created November 10, 2017 10:21
Show Gist options
  • Save amolyp/e6a26eef97679451f276425b30e1c595 to your computer and use it in GitHub Desktop.
Save amolyp/e6a26eef97679451f276425b30e1c595 to your computer and use it in GitHub Desktop.
kernel driver for interrupt based gpio and toggle two led on output port
/*
* Filename: gpio_interrupt_led_module.c
*
* Author: Pierre LE COZ
*
* Purposet: Test and demonstrate how to use GPIOs, interrupts and timers in a linux kernel module.
*
* Date: January 2013
*
* Informations: This is a linux loadable kernel module.
* As user space cannot provide access to the GPIO, it is necessary
* to develop code for the kernel to manage interrupts and GPIO pin values.
* The cross-compiler produces a .ko file that can be loaded in the kernel using "insmod" command.
* "rmmod" removes the module from kernel.
* The module is tested on a ARM developement platform embedding a minimal linux system.
* A RS-232 to USB cable allows to controle the board from the development computer.
* The module is build using a cross-toolchaine created with Buildroot.
*
* What the module does: A small electronic circuit is connected to the GPIO.
* The circuit is made of a push button with its debouncing circuitry and 2 Leds, LED1 and LED2.
* Once the module is loaded (using "insmod"), the LED1 lights up.
* Pressing the push button makes an interrupt request. When the interrupt is received,
* the handler call a function that switches leds states: LED1 shut off and LED2 lights up.
* A new press will set the system in its original state (LED1 on, LED2 off) etc.
* A kernel timer schedules the switching function call 1 second after the button press.
* Finally, Running "cat /proc/interrupts" allows to see interrupts seen from the kernel.
*
\*
/*---- Kernel includes ----*/
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/timer.h>
// Define inputs and output pins
#define GPIO_IN 23
#define GPIO_LED1 9
#define GPIO_LED2 11
// Define the delay to postpone interrupt action
#define DELAY 1 // 1 second
// Define interrupt request number
#define BUTTON_IRQ gpio_to_irq(GPIO_IN)
// Declare a timer
static struct timer_list timer_led;
static void switch_leds_state(unsigned long unused)
{
static int pin_value = 0;
gpio_set_value(GPIO_LED1, pin_value);
pin_value = 1 - pin_value;
gpio_set_value(GPIO_LED2, pin_value);
printk(KERN_INFO "Leds state switched!");
del_timer(& timer_led);
}
// Create the interrupt handler
static irqreturn_t my_handler(int irq, void * ident)
{
printk(KERN_INFO "\nInterrupt received from GPIO pin %d", GPIO_IN);
printk(KERN_INFO "Leds state switch in %d second... ", DELAY);
// schedule action to happen in DELAY second :
init_timer(& timer_led);
timer_led.function = switch_leds_state;
//timer_led.data = 0; // non utilise
timer_led.expires = jiffies + DELAY*HZ;
add_timer(& timer_led);
return IRQ_HANDLED;
}
// Init
static int __init exemple_init (void)
{
int err;
printk(KERN_INFO "Loading GPIO module \n");
// Request GPIO for led 1 :
if ((err = gpio_request(GPIO_LED1, THIS_MODULE->name)) !=0)
{
return err;
}
// Set GPIO_LED1 to output mode :
if ((err = gpio_direction_output(GPIO_LED1, 1)) !=0)
{
gpio_free(GPIO_LED1);
return err;
}
// Request GPIO for led 2 :
if ((err = gpio_request(GPIO_LED2, THIS_MODULE->name)) !=0)
{
gpio_free(GPIO_LED1);
return err;
}
// Set GPIO_LED2 to output mode :
if ((err = gpio_direction_output(GPIO_LED2, 0)) !=0)
{
gpio_free(GPIO_LED1);
gpio_free(GPIO_LED2);
return err;
}
// Request GPIO_IN :
if ((err = gpio_request(GPIO_IN, THIS_MODULE->name)) !=0)
{
gpio_free(GPIO_LED1);
gpio_free(GPIO_LED2);
return err;
}
// Set GPIO_IN to input mode :
if ((err = gpio_direction_input(GPIO_IN)) !=0)
{
gpio_free(GPIO_LED1);
gpio_free(GPIO_LED2);
gpio_free(GPIO_IN);
return err;
}
// Request BUTTON_IRQ and setting its type to trigger rising :
printk(KERN_INFO "Requesting irq %d\n", BUTTON_IRQ);
if((err = request_irq (gpio_to_irq(GPIO_IN), my_handler, IRQF_SHARED | IRQF_TRIGGER_RISING, THIS_MODULE->name, THIS_MODULE->name)) != 0)
{
printk(KERN_INFO "Error %d: could not request irq: %d\n", err, GPIO_IN);
gpio_free(GPIO_LED1);
gpio_free(GPIO_LED2);
gpio_free(GPIO_IN);
return err;
}
printk(KERN_INFO "Waiting for interrupts ... \n");
return 0;
}
// Clean up :
static void __exit exemple_exit (void)
{
free_irq(gpio_to_irq(GPIO_IN), THIS_MODULE->name);
gpio_free(GPIO_LED1);
gpio_free(GPIO_LED2);
gpio_free(GPIO_IN);
}
module_init(exemple_init);
module_exit(exemple_exit);
MODULE_AUTHOR("Pierre LE COZ");
MODULE_DESCRIPTION("GPIO interrupt and timers test module for embedded Linux");
MODULE_LICENSE("GPL");
/*
* End of file
/*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment