Search by Tags

How to use GPIO as output on Colibri running Embedded Linux

 
Applicable for

Compare with Revision




Subscribe for this article updates

Purpose

This article describes how to build a user application to configure and use GPIOs as output on the Apalis or Colibri T20/T30 running Embedded Linux.
GPIOs can be accessed through files in the "sysfs" special file system.
Compare with kernel sources, documentation/gpio.txt, 'Sysfs Interface for Userspace (OPTIONAL)' for more details.

Note: Our implementation requires the GPIOs to be defined within the kernel, "/sys/class/gpio/export" does not work.

Hardware Setup

Linux assigns a number to each possible GPIO. The relationship between this Linux number and the name assigned by the CPU can be found here: GPIO Alphanumeric to GPIO Numeric Assignment Connect SODIMM-55 to LED13 using a jumper wire on the Colibri Evaluation Board V3.1. This article uses the pinout of a Colibri T20. The pinout for other modules might be different, refer to the relevant datasheet. We are using the SODIMM-55 to control a LED. SODIMM-55 is connected to the CPU's GPIO B6 which in Linux is GPIO 14.

Software Setup

  • Follow this article for information on setting up your environment for Embedded Linux application development.
  • Follow this article for information on how to create and cross-compile a C project.
  • We will be using Eclipse to develop this application.

Software Description

The program configures one GPIO to be output, then it outputs a pulse with 1 Hz.
The program is stopped by pressing "q".

The file "gpio_output.c" contains the main() function with the setup and control of the GPIO.

The header file "pathmacros.h" contains the paths to the used sysfs files. If the program is compiled for x86 it provides paths for stub files.
The files "getkey.h, getkey.c" contains helpers for non blocking key press access.

Procedure

  • Start Eclipse and create a new Makefile project named "gpio_samples".
  • Create a folder "gpio_output" in the project.

Write the Code

  • Create the "pathmacros.h" file and enter the following code:
#ifndef __PATHMACROS_H__
#define __PATHMACROS_H__
 
// LED via SODIMM pin 55 (Linux GPIO 14)
#ifdef __ARM_EABI__    // path when executing on ARM target
    #define PATH_LED_VALUE        "/sys/class/gpio/gpio14/value"
    #define PATH_LED_DIRECTION    "/sys/class/gpio/gpio14/direction"
#else                  // path when executing on x86 host
    #define PATH_LED_VALUE        "/tmp/gpio14/value"
    #define PATH_LED_DIRECTION    "/tmp/gpio14/direction"
#endif
#endif

Save the editor content.

  • Create the "getkey.h" header file.
    This files provide a non-blocking "GetKey" function which returns the ASCII value of the key pressed on the keyboard (No new line character aka ENTER/RETURN required).
#ifndef __GETKEY_H__
#define __GETKEY_H__
 
/// Reads keyboard input without waiting for a new line character
/// @retval     -1      No key pressed
/// @retval     >0      ASCII code received
 
int GetKey(void);
 
#endif

Save the editor content.

  • Create the "getkey.c" source file.
#include <stdio.h>
#include <string.h>
#include <termios.h>                        // terminal interface
#include "getkey.h"
 
int GetKey(void)
{
        struct termios orig_term_attr;      // holds original state of terminal
        struct termios new_term_attr;       // holds new state of terminal
        int character;
 
        // Set terminal to raw mode, to access keyboard input
        tcgetattr(fileno(stdin), &orig_term_attr);         // fileno returns the file descriptor number of stdin
 
        memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));  // copy data from orig_term_attr to new_term_attr
        new_term_attr.c_lflag &= ~ICANON;                  // non-canonical input processing --> no new line required
        new_term_attr.c_cc[VTIME] = 0;                     // wait for 0*0.01 sec input, in non-canonical state
        new_term_attr.c_cc[VMIN] = 0;                      // VMIN is min number of bytes that must be available in input queue, in Non-Canonical state
 
        tcsetattr(fileno(stdin), TCSANOW, &new_term_attr); // set new attributes to stdin
 
        character=fgetc(stdin);                            // read from stdin and return EOF(-1), if no character is available
 
        // restore terminal to its original state
        tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);// restore original terminal attributes, TCSANOW: apply changes now
 
    return(character);
}

Save the editor content.

  • Create this "gpio_output.c" file.
    This file configures a GPIO to be output and then toggles the output state every 500ms until 'q' is pressed on the keyboard.
#include <fcntl.h>                   // for open(), close(), lseek()
#include <sys/stat.h>                // for open()
#include <stdio.h>                   // standard I/O header file
#include <sys/types.h>               // for open()
#include <unistd.h>                  // for write(), open(), read(), usleep()
#include "getkey.h"                  // read keyboard input
#include "pathmacros.h"              // path for GPIO files
 
int main(int argc, char **argv)
{
        char key = -1;               // default : No key pressed
        unsigned char led = '0';     // low(0) for Output, ASCII(48d), DEC(0d), HEX(0x30)
        int retVal;                  // for debugging purpose
        int fdLedValue;              // holds file descriptor for the value file
        int fdLedDirection;          // holds file descriptor for direction file
        char outputString[] = "out"; // string which sets GPIO direction to OUTPUT
 
        //  Configure GPIO direction as Output
        fdLedDirection = open(PATH_LED_DIRECTION, O_RDWR);     // open file PATH_LED_DIRECTION in read/write mode
                                                               // parameter: open(filepath, read-write permissions),
                                                               // returns: file descriptor or -1 if an error occurred.
        retVal = write(fdLedDirection, &outputString[0], sizeof(outputString));   // write into file to configure GPIO as output
                                                               // parameter: write(file_Descriptor, data_buffer, no_of_bytes),
                                                               // returns: No. of bytes written or -1 if an error occurred.
        retVal = close(fdLedDirection);                        // close file with file descriptor
                                                               // parameter: open(filepath, read-write permissions),
                                                               // returns: 0 on success or -1 if an error occurred.
 
        fdLedValue = open(PATH_LED_VALUE, O_RDWR);             // Open file PATH_LED_VALUE in read/write mode
                                                               // parameter: open(filepath, read-write permissions),
                                                               // returns: file descriptor or -1 if an error occurred.
 
        //  Blink LED, by writing the I/O state value into the file: PATH_LED_VALUE
        do {
            led = (led == '1') ? '0' : '1' ;                   // Toggle led value, ASCII: '1' <----> '0'
 
            retVal = write(fdLedValue, &led, 1);               // write into file to update LED value - Low('0') or High ('1')
            usleep(500000);                                    // create a delay of 500 milliseconds
 
            key = GetKey();                                    // get user input from keyboard
        } while(key != 'q');                                   // exit if keyboard input is 'q'
 
        retVal = close(fdLedValue);                            // close file with file descriptor
 
    printf("\nExiting.... \n");
 
    return(0);
}

Save the editor content.

Write the Makefile

Create the "Makefile" file.
Note: The Makefile syntax requires that the indentation MUST start with a <TAB> character for the commands after a make target (all, clean ...); and not with a SPACE character. If you copy/paste from the article, the <TAB> may be converted to <SPACE> and you will have to change them back to <TAB>.

CROSS_COMPILE ?= ~/gcc-linaro/bin/arm-linux-gnueabihf-
CC = $(CROSS_COMPILE)gcc

all: gpio_output.o getkey.o
    $(CC) -g -o gpio_output gpio_output.o getkey.o

gpio_output.o: gpio_output.c pathmacros.h
    $(CC) -g -c gpio_output.c

getkey.o: getkey.c getkey.h
    $(CC) -g -c getkey.c

clean:
    rm -rf *.o
    rm -rf gpio_output

Save the editor content.

Note: For a more elaborate Makefile refer to this article
Note: To use Makefiles automatically generated by the Eclipse IDE refer to this article for more details.

Cross Compile and Execute

Provide access to make from within Eclipse.
For cross compiling:
- In the 'Make Target' view, right click the gpio_samples->gpio_output folder and choose 'New...' - Add 'all' as the 'Target name' and keep all checkboxes ticked. Click OK. - Similarly for the target 'clean'. For native compiling:
- In the 'Make Target' view, right click the gpio_samples->gpio_output folder and choose 'New...' - Add 'x86 all' as the 'Target name', untick 'Same as the target name' and type 'CROSS_COMPILE= all' into the 'Make target' box. Click OK. - Similarly for the target 'x86 clean'.
Double clicking one of the target symbols in Eclipse executes make with the defined target. The console output can be seen in Eclipse's Console View. Alternatively you could open a terminal and run make from the command line.

cd
cd workspace/gpio_samples/gpio_output
make clean
make all
make clean
make CROSS_COMPILE=  all
make CROSS_COMPILE=  clean


Copy the binary to the target, refer to this article.

  • Start the LXTerminal on the target device.


  • Run the "gpio_output" application to target device.

With LXTerminal:

./gpio_output

Press 'q' on keyboard to stop the application.


  • Waveform at SODIMM-55/GPIO-14.
    Frequency: 1Hz
    Duty-Cycle: 50%


Compile Natively and Execute on x86 Host

On the development host the GPIO is emulated by ordinary files which must exist before the application is started.

Note: You have to 'make clean' every time you change between host and target compilation.
Use the 'file' command to check the current version.

At development host terminal:

mkdir /tmp/gpio14
touch /tmp/gpio14/value /tmp/gpio14/direction
make clean
CROSS_COMPILE="" make
file gpio_output
./gpio_output

Download

The source files are described above. The zip file can be directly imported into Eclipse or can be used on its own. Click here to download "gpio_output.zip".

See also

  • Features