world leader in high performance signal processing
Trace: » gpiokeys

ADSP-BF548 EZ-KIT Quick Start: Peripheral Demos: gpiokeys

www.analog.com_static_imported-files_images_product_descriptions_680755565image1a.jpg

What is gpiokeys

This demo program will use SDL_gfx to draw four boxes on the LCD. When a user pushes a GPIO push button it will draw the box going down as long as the user is holding it. When the user lets go of the button, the box will return to the top. The program will operate until it is terminated (Ctrl + C).

This is only a simple demo, just to show you that the push buttons can be used as a program input.

Note that the kernel option 'GPIO Buttons' must be enabled for this to work.

Device Drivers -> 
  Input device support -> 
    Keyboards ->
      [X] GPIO Buttons 

Download gpiokeys

The demo comes with the customised Ubuntu ISO and can be found in the folder /home/Blackfin/demos. Alternatively it is already installed on the demo uClinux image (demo-uclinux.img) that you can get on ADSP-BF548 EZ-KIT Quick Start: Booting uClinux.

If you just want to download the demos on their own and get their source code you can download the compressed archive (demos-R1.tar.gz) here bf548-quick-start .

How to run the gpiokeys program

  • Change directory to /demos/pushbuttons

    root:/> cd /demos/pushbuttons
  • Make sure SDL knows that there is no mouse available otherwise it won't run

    root:/> export SDL_NOMOUSE=1

    Note: You only need to do this once per uClinux boot. If you want your program to make use of the touch screen, do not run this environment variable and instead run the commands found in the touchscreen demos.

  • Run gpiokeys

    root:/> ./gpiokeys
    Loading... 
    Done!
  • Press and hold down the push buttons

  • Exit (Ctrl + C)

How the gpiokeys demo works

Note: All the drawing code has been stripped from the demo discussion. This is because it was not directly relevent to handling button pushes.

Copyright disclaimer

/*
 *  Copyright (c) 1999-2000 Vojtech Pavlik
 *  Copyright (c) 2009 Red Hat, Inc
 *
 *  Event device test program
 *
 * See INSTALL for installation details or manually compile with
 * gcc -o evtest evtest.c
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
 */

The first thing to note is the copyright disclaimer. This demo is actually just a modified version of the program event_test which is commonly used in uClinux to debug the input event interface.

Headers

#include <stdint.h>

#include <linux/input.h>

#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

// Unrelated Drawing Libraries
#include <SDL_gfxPrimitives.h>

This program uses the linux/input.h header to get important evdev constants and functions. fcntl.h is necessary for the file control handling as the input event interface appears like a file. The sdl_gfxPrimitives header is just to draw the GUI on the LCD screen and isn't related to the actual button operation.

Finding the event input device alias

device = find_event_input("gpio-keys");
if (device == NULL)
{
  fprintf(stderr, "Error: Couldn't open event buffer. Check device is correctly installed.\n");
  return 1;
}

This makes a call to a custom special helper function which scans through all the event input devices and finds one with the name “gpio-keys”. It will return that location as a string for use by this program. This special helper function can be very useful if you wish to further develop applications using the event buffers as otherwise you will have to hardcode the location which could change depending on the kernel configuration.

If you want to see how the helper function works, you will have to look at the demo code.

Opening input event interface

// Open device input event buffer
if ((fd = open(device, O_RDONLY)) < 0) 
{
  fprintf(stderr, "Error: Couldn't open event buffer. Check device is correctly installed.\n");
  return 1;
}

// Double check it's the correct input buffer
ioctl(fd, EVIOCGNAME(sizeof(name)), name);
if (strcmp(name, "gpio-keys") != 0)
{
  printf("Error: Incorrect input device binding. Check device is correctly installed.\n");
  running = 0;
}

// Set block flag to off otherwise program will pause 
// waiting for button events
flags = fcntl(fd, F_GETFL, 0); /* get current file status flags */
flags |= O_NONBLOCK; /* turn off blocking flag */
fcntl(fd, F_SETFL, flags); /* set up non-blocking read */

This code section opens the input event buffer for reading only. It then runs a call to get the name of the device associated to this event buffer and compares it to gpio-keys. You can find out a devices name using the event_test program.

If the event buffer is openable and presents the correct device, it will set the file buffer to be non-blocking so that way if there are no events, it won't halt the program during a read. Note that this is quite inefficient and there are better ways such as using select and fd_set so you can wait on input from multiple inpts, this is documented in the glibc documentation http://www.delorie.com/gnu/docs/glibc/libc_248.html.

Loop to scan for events

while (running == 1) 
{
  rd = read(fd, ev, sizeof(struct input_event) * 64);

  // Check there are actually any events to handle before 
  // handling them
  if (rd >= (int) sizeof(struct input_event)) 
  {
    // Handle all events read in to buffer
    for (i = 0; i < rd / sizeof(struct input_event); i++)
    {
      if (ev[i].type == EV_KEY) 
      {
        if (ev[i].code == BTN_0)
        {
          // PB1 event
          if (ev[i].value == 0)
          {
            // Pushed Down
            printf("PB1-DOWN\n");
            pb1_state = 0;
          }
          else if (ev[i].value == 1)
          {
            // Released
            printf("PB1-RELEASED\n");
            pb1_state = 1;
          }
        }
        else if (ev[i].code == BTN_1)
        {
          // PB2 event
          if (ev[i].value == 0)
          {
            // Pushed Down
            printf("PB2-DOWN\n");
            pb2_state = 0;
          }
          else if (ev[i].value == 1)
          {
            // Released
            printf("PB2-RELEASED\n");
            pb2_state = 1;
          }
        }
        else if (ev[i].code == BTN_2)
        {
          // PB3 event
          if (ev[i].value == 0)
          {
            // Pushed Down
            printf("PB3-DOWN\n");
            pb3_state = 0;
          }
          else if (ev[i].value == 1)
          {
            // Released
            printf("PB3-RELEASED\n");
            pb3_state = 1;
          }
        }
        else if (ev[i].code == BTN_3)
        {
          // PB4 event
          if (ev[i].value == 0)
          {
            // Pushed Down
            printf("PB4-DOWN\n");
            pb4_state = 0;
          }
          else if (ev[i].value == 1)
          {
            // Released
            printf("PB4-RELEASED\n");
            pb4_state = 1;
          }
        }
      }
    }
  }
}

This code section makes a continuous loop and reads in any events in the events buffer file. If there are any events, it will sort through them (could be many) and determine what button, and the event (pushed or let go). The constants are from linux/input.h in case you were wondering.

Compiling gpiokeys

First make sure that your kernel has the libraries libSDL and SDL_gfx enabled.

Secondly, make sure your vendor staging install is complete (ADSP-BF548 EZ-KIT Quick Start: Compiling uClinux).

root:/> make vendor_staging_install

Run the following compile command in the same directory as the source code:

root:/> bfin-linux-uclibc-gcc -O2 \
$(~/Blackfin/blackfin-linux-dist/staging/usr/bin/sdl-config --cflags) \
$(~/Blackfin/blackfin-linux-dist/staging/usr/bin/sdl-config --libs) \ 
-lSDL_gfx \ 
gpiokeys.c -o gpiokeys

What this compile command is doing is it is calling the uclibc cross compiler that is set up from the Blackfin toolchains to compile our application.

The calls to sdl-config are a special case for SDL because SDL places its header & library files in non-root locations so this will load them properly.

The parameters prefixed with -l are to indicate we need to load that library, so in this case the library SDL_gfx is loaded. Without these library, our program would not have access to the required graphical functions.

The final parameters match up to standard gcc compiling; “gpiokeys.c” is the source file while ”-o gpiokeys” indicates the output file is gpiokeys.

A standard make file is accompanies this demo and you can run that by simply calling

root:/> make gpiokeys

Further Reading

The wiki page gpio-keys has details on GPIO push buttons as well as information about how the input event interface works. It also details driver configuration as well, and points to the Key symbol list.

You can look up event device node for further information about this approach.