Skip to content

Kernel Module 3 GPIO

Frank Bauernöppel edited this page Mar 19, 2017 · 3 revisions

We use SoC pin 18 (which is pin 14 on the expansion header) as an example and connect a LED to it as in GPIO.

Note, that this pin must be in GPIO mode, not in alternate mode. See device tree and expansion header how to test or set this.

Now, we want to switch the LED on and off from a kernel module. Kernel Module 2 - Char Device is used as a starting point.

Add the following lines to my_module.c at global scope:

#include <linux/gpio.h>

const int my_gpio = 18;
int my_value = 0;

Extend my_init function:

    int rc;

    rc = gpio_request( my_gpio, "my_gpio" );
    if(rc < 0)
    {
        printk(KERN_ERR "gpio_request failed, error %d\n", rc );
        return rc;
    }

    rc = gpio_direction_output( my_gpio, 0 );
    if(rc < 0)
    {
        printk(KERN_ERR "gpio_direction_output failed, error %d\n", rc );
        return rc;
    }

Extend the my_write function such that the LED is switched:

    ...
    case '1':
        gpio_set_value( my_gpio, 1 );
        ...
    case '0':
        gpio_set_value( my_gpio, 0 );
        ...

Extend the my_exit function such that the kernel resources are freed and the module can be loaded again:

static void __exit my_exit(void)
{
  gpio_free( my_gpio );
  ...
}

Cross-compile the kernel module, copy it to the target and load the module on the target:

root@raspberrypi:~$ insmod my_module.ko

accessing the module from a shell

Now, you can set and clear the LED using the device /dev/my_dev exposed by the module:

root@raspberrypi:~$ echo 1 > /dev/my_dev 
root@raspberrypi:~$ echo 0 > /dev/my_dev 

You may also read the response from your module:

root@raspberrypi:~$     cat /dev/my_dev 

The response should start with OK when you issued a valid command and with ERROR else. Each response is only given once per command.

Accessing the module form a C program

Use the device /dev/my_dev exposed by your loaded module my_module.ko with the usual Posix IO functions:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    int i;
    int f = open( "/dev/my_dev", O_RDWR );
    for(i=0;i<100;++i) {
        write( f, "1", 1 );
        sleep(1);
        write( f, "0", 1 );
        sleep(1);
    }
    close(f);
}

Checking of return codes of all IO functions is omitted here for simplicity but should be present in your code! You might also read the response produced by the module and print it out for debugging.

Note, the the printk output from your module does not appear here. It is usually added to the kernel log and printed on the Linux console. The kernel log can be retrieved and configured in a shell by using the dmesg command.

You may only use the IO functions that you have implemented. In advanced scenarios you might want to implement ioctl to communicate to your module via customized C data structures (struct) instead of the simple char based IO.

What's next

Kernel Module 4 - Timer shows how to add a timer to the kernel module and execute periodic tasks.