Using GPIO - FrankBau/meta-marsboard-bsp GitHub Wiki

GPIO (general purpose input and output)

Prerequisites

  • a running Linux image on MarS Board
  • a terminal connection from the build host to the MarS Board
  • MarS Board schematics

General Purpose Output - Procedure

Most iMX6 / extension header pins can be configured as GPIO.

Lets use pin 4 on header J10 which is next to pin 2, a GND pin. So we can easily connect a LED with a serial resistor to check the GPIO function.

From the schematics you learn that pin 4 of header J10 is connected to a signal NANDF_CS0. If you follow that signal you see that it is connected to pad NANDF_CS0 of the i.MX6.

The i.MX6 technical reference manual (IMX6DQRM.pdf) shows two associated registers, the Pad Mux Register (IOMUXC_SW_MUX_CTL_PAD_NAND_CS0_B) and the Pad Control Register (IOMUXC_SW_PAD_CTL_PAD_NAND_CS0_B). Note that the postfix NAND_CS0_B is quite similar, but unfortunately not identical to the schematics NANDF_CS0. You may check the iMX6 pad index F15 in the schematics and compare that to the ball description in the datasheet (IMX6DQCEC.pdf) which is indeed NANDF_CS0.

Pad Mux Register

The MUX_MODE bit field shows the different pin functions which can be selected. We are interested in GPIO, so ALT5 — Select signal GPIO6_IO11 is the important line. GPIOs are organized in groups of 32. So our GPIO pin is (bit) number 11 in group 6.

Linux has a linear numbering of all GPIO pins

linux_gpio_number = 32 * (group_number-1) + pin_number_in-group 

which, in our case, yields linux gpio number 32*(6-1) + 11 = 171.

Pad Control Register

The various fields show how the electrical function of the pin can be set and fine tuned like: open-drain, internal pull-up/pull-down, driver strength etc..

Setting the GPIO from the command line

Directly writing to the above registers is possible, but not recommended, because the operating system is in charge to access the hardware resources.

In the terminal window enter ls -lL /sys/class/gpio/

root@marsboard:~# ls -lL /sys/class/gpio/
total 0
--w------- 1 root root 4096 May 15 14:54 export
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip0
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip128
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip160
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip192
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip32
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip64
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip96
--w------- 1 root root 4096 May 15 14:54 unexport

Besides the GPIO groups (gpiochip*) there is the export entry. This is used to export individual GPIOs. Enter echo 171 > /sys/class/gpio/export. This makes our pin available for user mode access. When you re-enter the ls command you see that a new entry GPIO was created:

root@marsboard:~# echo 171 > /sys/class/gpio/export 
root@marsboard:~# ls -lL /sys/class/gpio/
total 0
--w------- 1 root root 4096 May 15 14:54 export
drwxr-xr-x 3 root root    0 May 15 14:55 gpio171
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip0
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip128
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip160
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip192
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip32
drwxr-xr-x 3 root root    0 Apr 17 13:57 gpiochip64

drwxr-xr-x 3 root root 0 Apr 17 13:57 gpiochip96 --w------- 1 root root 4096 May 15 14:54 unexport

Lets take a closer look at it:

root@marsboard:~# ls -lL /sys/class/gpio/gpio171
total 0
-rw-r--r-- 1 root root 4096 May 15 14:56 active_low
drwxr-xr-x 4 root root    0 Apr 17 13:57 device
-rw-r--r-- 1 root root 4096 May 15 14:56 direction
-rw-r--r-- 1 root root 4096 May 15 14:56 edge
drwxr-xr-x 2 root root    0 May 15 14:56 power
drwxr-xr-x 2 root root    0 Apr 17 13:57 subsystem
-rw-r--r-- 1 root root 4096 May 15 14:56 uevent
-rw-r--r-- 1 root root 4096 May 15 14:56 value

Setting the direction will put the GPIO in output mode and setting the value will switch it on (high) and off (low) again.

root@marsboard:~# echo out > /sys/class/gpio/gpio171/direction
root@marsboard:~# echo 1 > /sys/class/gpio/gpio171/value
root@marsboard:~# echo 0 > /sys/class/gpio/gpio171/value 

Finally, you should unexport the GPIO pin to free the kernel resources:

root@marsboard:~# echo 171 > /sys/class/gpio/unexport 

If you want to modulate the LED brightness, see Using PWM.

General Purpose Input - Procedure

Get GPIO From the Command line

We use Pin 39 of Header J10 which is GPIO1_IO01 (group 1 pin 1 -> linux GPIO number (1-1)

echo 1 > /sys/class/gpio/gpio
echo 1 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio1/direction

# leave pin open
cat /sys/class/gpio/gpio1/value
1

# connect pin to GND using a resistor
cat /sys/class/gpio/gpio1/value
0

Finally, you should unexport the GPIO pin to free the kernel resources:

root@marsboard:~# echo 171 > /sys/class/gpio/unexport 

Get GPIO value from a kernel module

By Polling

In this simple example, the GPIO value is queried only once during my_init.

You could combine this example with

Note that polling has its drawbacks. Below you find interrupt drive code.

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h> 
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>

static const int gpio_pin = 32*(6-1) + 11; // GPIO6_11 Mars Board pin 4 on header J10

static int __init my_init(void)
{
    int rc;
    printk(KERN_INFO "my module: init\n");

    rc = gpio_request( gpio_pin, "my gpio pin" );
    if( rc < 0 ) {
	printk(KERN_ERR "my module: gpio_request failed with error %d\n", rc );
	return rc;
    }

    rc = gpio_direction_input( gpio_pin );
    if( rc < 0 ) {
	printk(KERN_ERR "my module: gpio_direction_input failed with error %d\n", rc );
	gpio_free(gpio_pin);
	return rc;
    }

    if( gpio_get_value(gpio_pin) == 0 ) {
	 printk(KERN_ERR "my module: gpio is lo" );
    }
    else {
	 printk(KERN_ERR "my module: gpio is hi" );
    }

    return 0;
}

static void __exit my_exit(void)
{
    printk(KERN_INFO "my module: exit\n" );
    gpio_free(gpio_pin);
}

module_init(my_init);
module_exit(my_exit);

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("F.B.");
MODULE_DESCRIPTION("My GPIO Polling Driver");

By Interrupt

Writing proper interrupt handler is more involved and error prone. But, the resulting code is more efficient compared to polling.

Further reading

Get/Set GPIO from a user application (C Code)

see http://falsinsoft.blogspot.de/2012/11/access-gpio-from-linux-user-space.html

Further reading