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
- Kernel Module 2 - Char Device and call
gpio_get_value
from themy_read
function - Kernel Module 4 - Timer for periodic polling.
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
- https://community.freescale.com/message/499554
- http://derekmolloy.ie/kernel-gpio-programming-buttons-and-leds/
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
- Studio Kosagi "iMX6 Definitive GPIO Guide": http://www.kosagi.com/w/index.php?title=Definitive_GPIO_guide
- GPIO Zugriff mit C Code: http://falsinsoft.blogspot.de/2012/11/access-gpio-from-linux-user-space.html
- Mochel, Patrick; "The sysfs Filesystem"; https://www.kernel.org/pub/linux/kernel/people/mochel/doc/papers/ols-2005/mochel.pdf