Wednesday, April 10, 2013

Raspbery Pi gpio interrupts in kernel space C source code, kernel module


This code is from project: Raspberry pi gpio interrupts in kernel space

m_test.c


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <linux/interrupt.h>
#include <linux/gpio.h>


#define DRIVER_AUTHOR "Igor <hardware.coder@gmail.com>"
#define DRIVER_DESC   "Tnterrupt Test"

// we want GPIO_17 (pin 11 on P5 pinout raspberry pi rev. 2 board)
// to generate interrupt
#define GPIO_ANY_GPIO                17

// text below will be seen in 'cat /proc/interrupt' command
#define GPIO_ANY_GPIO_DESC           "Some gpio pin description"

// below is optional, used in more complex code, in our case, this could be
// NULL
#define GPIO_ANY_GPIO_DEVICE_DESC    "some_device"


/****************************************************************************/
/* Interrupts variables block                                               */
/****************************************************************************/
short int irq_any_gpio    = 0;


/****************************************************************************/
/* IRQ handler - fired on interrupt                                         */
/****************************************************************************/
static irqreturn_t r_irq_handler(int irq, void *dev_id, struct pt_regs *regs) {

   unsigned long flags;
  
   // disable hard interrupts (remember them in flag 'flags')
   local_irq_save(flags);

   // NOTE:
   // Anonymous Sep 17, 2013, 3:16:00 PM:
   // You are putting printk while interupt are disabled. printk can block.
   // It's not a good practice.
   // 
   // hardware.coder:
   // http://stackoverflow.com/questions/8738951/printk-inside-an-interrupt-handler-is-it-really-that-bad

   printk(KERN_NOTICE "Interrupt [%d] for device %s was triggered !.\n",
          irq, (char *) dev_id);

   // restore hard interrupts
   local_irq_restore(flags);

   return IRQ_HANDLED;
}


/****************************************************************************/
/* This function configures interrupts.                                     */
/****************************************************************************/
void r_int_config(void) {

   if (gpio_request(GPIO_ANY_GPIO, GPIO_ANY_GPIO_DESC)) {
      printk("GPIO request faiure: %s\n", GPIO_ANY_GPIO_DESC);
      return;
   }

   if ( (irq_any_gpio = gpio_to_irq(GPIO_ANY_GPIO)) < 0 ) {
      printk("GPIO to IRQ mapping faiure %s\n", GPIO_ANY_GPIO_DESC);
      return;
   }

   printk(KERN_NOTICE "Mapped int %d\n", irq_any_gpio);

   if (request_irq(irq_any_gpio,
                   (irq_handler_t ) r_irq_handler,
                   IRQF_TRIGGER_FALLING,
                   GPIO_ANY_GPIO_DESC,
                   GPIO_ANY_GPIO_DEVICE_DESC)) {
      printk("Irq Request failure\n");
      return;
   }

   return;
}


/****************************************************************************/
/* This function releases interrupts.                                       */
/****************************************************************************/
void r_int_release(void) {

   free_irq(irq_any_gpio, GPIO_ANY_GPIO_DEVICE_DESC);
   gpio_free(GPIO_ANY_GPIO);

   return;
}


/****************************************************************************/
/* Module init / cleanup block.                                             */
/****************************************************************************/
int r_init(void) {

   printk(KERN_NOTICE "Hello !\n");
   r_int_config();

   return 0;
}

void r_cleanup(void) {
   printk(KERN_NOTICE "Goodbye\n");
   r_int_release();

   return;
}


module_init(r_init);
module_exit(r_cleanup);


/****************************************************************************/
/* Module licensing/description block.                                      */
/****************************************************************************/
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

Makefile


# my optional module name
MODULE=m_test

# this two variables, depends where you have you raspberry kernel source and tools installed

CCPREFIX=/opt/raspberry_pi-kernel/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
KERNEL_SRC=/opt/raspberry_pi-kernel/linux


obj-m += ${MODULE}.o

module_upload=${MODULE}.ko

all: clean compile

compile:
    make ARCH=arm CROSS_COMPILE=${CCPREFIX} -C ${KERNEL_SRC} M=$(PWD) modules

clean:
    make -C ${KERNEL_SRC} M=$(PWD) clean


# this just copies a file to raspberry
install:
    scp ${module_upload} pi@raspberry:test/

info:
    modinfo  ${module_upload}

13 comments:

  1. Hi,
    i want do the one project..that is when the push button is presses it gives interupt to gpio and the camera is opened and capture the pictures on the raspberry pi...r u have any idea about this....or r u have any source code for this....


    Thanks&Regards

    K.Arungopal

    ReplyDelete
  2. Hi,

    It depends.

    If you have USB camera, then don't bother to mess in kernel. Use bash instead http://elinux.org/RPi_Low-level_peripherals#Bash_shell_script.2C_using_sysfs.2C_part_of_the_raspbian_operating_system

    Create a script which would do something like this:

    while(1) {

    check_value_on_gpio;

    if_pin_value_changed
    run_program_to_take_photo_from_camera;

    sleep_some_time;
    }

    To GPIO pin connect push-button and resistor to supply or ground like here: http://www.raspberrypi.org/phpBB3/viewtopic.php?t=23485&p=222146

    If you have 8bit camera, and you plan to connect it to GPIO pins (PixClock, Href,Vsync, 8 wires of IO data), then you could think about kernel and interrupts.
    I'm doing something like this right now, but it's a pain in the ass, because I've got some sync problems and not all data is read from data pins, besides my camera clock is about 16Mhz and interrupts are generated so fast that sometimes, they block whole system :).

    Personally I think, that my first tip with bash script will help you enough.

    Please let me know if you have any doubts.

    Regards,
    Igor.

    ReplyDelete
  3. Iam new to this type of Drivers..So Please Give me entire code or give me Some Sample code with makefile....Actually iam new to drivers..So thats why iam asking entire code...Please give me Entire code or Some Sample Code for reference this to code..S iam understood u r comment...But direct pin accessing is Correct method?i want do the accessing the pin through the address value of raspberry pi gpio pins...So please give me Some Sample code or entire code like above u r tutorial....



    Thanks&Regards,
    K.Arungopal

    ReplyDelete
    Replies
    1. Hi,

      My current project is to write a very simple driver to ov7670 camera. Camera is connected to raspberry gpio pins, and I use interrupts to get timing and data from camera. I bought ov7670 without fifo buffer (al422), so my task is more difficult because raspberry must directly follow ov7670 pixel clock to get valid data.

      As a result I'll get frame from camera (picture) just by reading data from my device in '/dev/' directory.

      This is not universal solution, I'm writing it mostly for fun.

      I'm planing to post code and schematics at end of this or next week, so please be patient. I do this only in my free time.

      Back to your project:
      1. What kind of camera do you have, USB or ov7670(directly connected to GPIO) or maybe other one ?
      2. What is purpose of your project ? - you will write whole driver to camera or only part of code which will get picture (for already supported camera) by pressing some button connected to GPIO.
      3. If you don't have to write a kernel module, consider to use a wiringPi library, it's easy and have good examples on the web.

      Regards,
      Igor.

      Delete
  4. Hi,

    u r Doing great project..iam also interest in doing such type of projects...If u like Send u r code after comletion of u r project..Try to Send Code At the end of this week please....
    Coming to my project:
    Iam using web camera(logitech hd)
    I want two codes that is driver code and camera application code...when we are inserting a driver code as a module in the kernel and we executing a camera aplication in the user level...when push button is pressed it calls to driver module and in user level we are execute the camera application....
    Is Any alternate method to doing this project?
    The Purpose of My project is till now we are accessing the gpio pins using wiring pi like this only..My intension is to access the gpio through kernel module driver thats it...
    Yes iam used wiring pi s iam got the output but my intension is to access the gpio use the driver module...that is my intension and project..


    Thanks&Regards,
    K.Arungopal

    ReplyDelete
    Replies
    1. Hi,

      Please check http://morethanuser.blogspot.com/2013/05/raspberry-pi-interrupt-to-signal_2575.html

      I wrote it just right now and it could resolve your problem. You could only do signal implementation in your camera app, and when you will be pressing button, signal arrives and your function would get picture from camera.

      I don't know if I publish whole code of ov7670-to-gpio at end of this week, because I have really small amount of time for doing this, I'll try my best.

      Regards,
      Igor.

      Delete
  5. Thank you very much for posting this, beautiful, clean and complete example on GPIO IRQs in kernel space. "I'm bookmarking your article for later reference" may sound like a spam message, but this time I really mean it.
    Cheers!
    Joonas

    ReplyDelete
    Replies
    1. Hi,
      It doesn't sound like spam :). I'm glad, that you found something interesting on my blog.

      Regards,
      Igor.

      Delete
  6. Hi,

    Thanks for this example and clarifications. I try to understand bcm2708_gpio.c code regarding GPIO interrupts and I've some problems with it. When I check BCM2835 ARM peripherial specification specification it says that GPIO have 3 interrupt lines (1,2: for first and second bank and 3: common). In the same specification I can see ARM peripherals interrupt table which specify 4 interrups (49-52) - what is consistent with Linux code (arch/arm/mach-bcm2708/include/mach/irqs.h) containing 4 defines for each interrupt. Even more confusing for me is function for interrupt initialization:

    static void bcm2708_gpio_irq_init(struct bcm2708_gpio *ucb)
    {
    unsigned irq;

    printk("%s not empty \n", __func__);
    ucb->gc.to_irq = bcm2708_gpio_to_irq;

    for (irq = GPIO_IRQ_START; irq < (GPIO_IRQ_START + GPIO_IRQS); irq++)
    {
    irq_set_chip_data(irq, ucb);
    irq_set_chip(irq, &bcm2708_irqchip);
    set_irq_flags(irq, IRQF_VALID);
    enable_irq(irq);
    }
    setup_irq(IRQ_GPIO3, &bcm2708_gpio_irq);
    }

    which calls 'for' loop 5*32 times - why so many times? Maybe by accident you also tried to understand this code and have some conclusions that you could share?

    Regards

    ReplyDelete
  7. I've also some problem with running your example on raspberry pi. Module loads correctly:
    [ 376.406877] Hello !
    [ 376.418686] Mapped int 187
    But then I cannot see ISR called when I press switch attached to GPIO17. I check gpio input state by gpio application and it shows state change from Low to High and vice versa. When I check /proc/interrupts then number of interrupts from 'Some gpio pin description' is still '0'. Did you change something in kernel source to make it working?

    ReplyDelete
  8. How do we cut and paste your source on Windows?

    ReplyDelete
  9. Sorry. Use google chrome, not IE

    ReplyDelete
  10. Line 6 in the Makefile seems to be truncated. Am I wrong?

    ReplyDelete