Search by Tags

How to use GPIO as output on Colibri running Embedded Linux


Article updated at 01 Apr 2019
Compare with Revision

Subscribe for this article updates


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.


  • 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:

    # <a id="ifndef_PATHMACROS_H" name="ifndef_PATHMACROS_H" href="#ifndef_PATHMACROS_H">ifndef PATHMACROSH</a>
    # <a id="define_PATHMACROS_H" name="define_PATHMACROS_H" href="#define_PATHMACROS_H">define PATHMACROSH</a>
    // LED via SODIMM pin 55 (Linux GPIO 14)
    # <a id="ifdef_ARM_EABI_path_when_executing_on_ARM_target" name="ifdef_ARM_EABI_path_when_executing_on_ARM_target" href="#ifdef_ARM_EABI_path_when_executing_on_ARM_target">ifdef ARMEABI    // path when executing on ARM target</a>
    	#define PATH_LED_VALUE		"/sys/class/gpio/gpio14/value"
    	#define PATH_LED_DIRECTION	"/sys/class/gpio/gpio14/direction"
    # <a id="else_path_when_executing_on_x86_host" name="else_path_when_executing_on_x86_host" href="#else_path_when_executing_on_x86_host">else                  // path when executing on x86 host</a>
    	#define PATH_LED_VALUE		"/tmp/gpio14/value"
    	#define PATH_LED_DIRECTION	"/tmp/gpio14/direction"
    # <a id="endif" name="endif" href="#endif">endif</a>
    # <a id="endif-2" name="endif-2" href="#endif-2">endif</a>
    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).

    # <a id="ifndef_GETKEY_H" name="ifndef_GETKEY_H" href="#ifndef_GETKEY_H">ifndef GETKEYH</a>
    # <a id="define_GETKEY_H" name="define_GETKEY_H" href="#define_GETKEY_H">define GETKEYH</a>
    /// Reads keyboard input without waiting for a new line character
    /// @retval     -1      No key pressed
    /// @retval     >0      ASCII code received
    int GetKey(void);
    # <a id="endif-3" name="endif-3" href="#endif-3">endif</a>
    Save the editor content.

  • Create the "getkey.c" source file.

    # <a id="include_stdioh" name="include_stdioh" href="#include_stdioh">include &lt;stdio.h&gt;</a>
    # <a id="include_stringh" name="include_stringh" href="#include_stringh">include &lt;string.h&gt;</a>
    # <a id="include_termiosh_terminal_interface" name="include_termiosh_terminal_interface" href="#include_termiosh_terminal_interface">include &lt;termios.h&gt;                        // terminal interface</a>
    # <a id="include_getkeyh" name="include_getkeyh" href="#include_getkeyh">include &quot;getkey.h&quot;</a>
    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
    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.

# <a id="include_fcntlh_for_open_close_lseek" name="include_fcntlh_for_open_close_lseek" href="#include_fcntlh_for_open_close_lseek">include &lt;fcntl.h&gt;                   // for open(), close(), lseek()</a>
# <a id="include_sysstath_for_open" name="include_sysstath_for_open" href="#include_sysstath_for_open">include &lt;sys/stat.h&gt;                // for open()</a>
# <a id="include_stdioh_standard_IO_header_file" name="include_stdioh_standard_IO_header_file" href="#include_stdioh_standard_IO_header_file">include &lt;stdio.h&gt;                   // standard I/O header file</a>
# <a id="include_systypesh_for_open" name="include_systypesh_for_open" href="#include_systypesh_for_open">include &lt;sys/types.h&gt;               // for open()</a>
# <a id="include_unistdh_for_write_open_read_usleep" name="include_unistdh_for_write_open_read_usleep" href="#include_unistdh_for_write_open_read_usleep">include &lt;unistd.h&gt;                  // for write(), open(), read(), usleep()</a>
# <a id="include_getkeyh_read_keyboard_input" name="include_getkeyh_read_keyboard_input" href="#include_getkeyh_read_keyboard_input">include &quot;getkey.h&quot;                  // read keyboard input</a>
# <a id="include_pathmacrosh_path_for_GPIO_files" name="include_pathmacrosh_path_for_GPIO_files" href="#include_pathmacrosh_path_for_GPIO_files">include &quot;pathmacros.h&quot;              // path for GPIO files</a>
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");
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-

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

    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 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:


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
file gpio_output


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 "".

See also