world leader in high performance signal processing
Trace: » keypad

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

www.analog.com_static_imported-files_images_product_descriptions_680755565image1a.jpg

What is keypad

This demo program will use SDL_gfx and SDL_ttf to draw the buttons character being pressed on the keypad onto LCD screen. When the user pushes a button on the keypad, it will appear on the LCD. When the user lets go of the button, it will disappear from the LCD. If the user pushes the red 2nd button it will toggle the alternative characters and a symbol will appear on the LCD screen. When the user pushes the red 2nd button again, it will go back to normal. The program will operate until it is terminated (Ctrl + C).

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

Note that the kernel option 'Blackfin BF54x keypad support' must be enabled for this to work.

Device Drivers ->
  Input device support ->
    Keyboards ->
      [X] Blackfin BF54x keypad support

Download keypad

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 keypad program

  • Change directory to /demos/keypad

    root:/> cd /demos/keypad
  • 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 keypad

    root:/> ./keypad
    Waiting for input. Interrupt to exit.
  • Press the keys on the keypad

  • Exit (Ctrl + C)

How the keypad demo works

Required header files

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Necessary for this demo
#include <SDL.h>

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

// Optional Font Libraries
#include <SDL_ttf.h>

As you can see, this program needs the SDL library and the SDL_ttf library to draw text to the screen. It also grabs the SDL_gfx library to draw the red box for the “2nd” toggle (when pushing the 2nd key).

Key symbol to User string converter

#define KEYCHAR_DESC_LENGTH 10

char* convert_sym_to_keychar(int symbol, int alt)
{
  char* keychar = malloc(sizeof(char) * KEYCHAR_DESC_LENGTH);
  strcpy(keychar, "UNKNOWN");

  if (alt == 0)
  {
    switch(symbol)
    {
      case 49:
        strcpy(keychar, "1");
        break;
      case 50:
        strcpy(keychar, "2");
        break;
      case 51:
        strcpy(keychar, "3");
        break;
      case 273:
        strcpy(keychar, "UP");
        break;
      case 52:
        strcpy(keychar, "4");
        break;
      case 53:
        strcpy(keychar, "5");
        break;
      case 54:
        strcpy(keychar, "6");
        break;
      case 274:
        strcpy(keychar, "DOWN");
        break;
      case 55:
        strcpy(keychar, "7");
        break;
      case 56:
        strcpy(keychar, "8");
        break;
      case 57:
        strcpy(keychar, "9");
        break;
      case 9:
        strcpy(keychar, "2ND");
        break;
      case 8:
        strcpy(keychar, "CLEAR");
        break;
      case 48:
        strcpy(keychar, "0");
        break;
      case 0:
        strcpy(keychar, "HELP");
        break;
      case 13:
        strcpy(keychar, "ENTER");
        break;
      default:
        break;
    }
  }
  else
  {
    switch(symbol)
    {
      case 49:
        strcpy(keychar, "A");
        break;
      case 50:
        strcpy(keychar, "B");
        break;
      case 51:
        strcpy(keychar, "C");
        break;
      case 273:
        strcpy(keychar, "LEFT");
        break;
      case 52:
        strcpy(keychar, "D");
        break;
      case 53:
        strcpy(keychar, "E");
        break;
      case 54:
        strcpy(keychar, "F");
        break;
      case 274:
        strcpy(keychar, "RIGHT");
        break;
      case 55:
        strcpy(keychar, "G");
        break;
      case 56:
        strcpy(keychar, "H");
        break;
      case 57:
        strcpy(keychar, "I");
        break;
      case 9:
        strcpy(keychar, "2ND");
        break;
      case 8:
        strcpy(keychar, "CLEAR");
        break;
      case 48:
        strcpy(keychar, "J");
        break;
      case 0:
        strcpy(keychar, "HELP");
        break;
      case 13:
        strcpy(keychar, "ENTER");
        break;
      default:
        break;
    }
  }
  return keychar;
}

The keypad driver does not give the program the actual key characters, but instead their key code equivalents. This function just converts the code to a string that textually describes the button pushed.

Main function

int main(int argc, char* argv[])
{
  int screen_width = 480;
  int screen_height = 272;
  int screen_bitdepth = 24;

  SDL_Surface *screen;
  TTF_Font* text_font;
  TTF_Font* text_font_tiny;
  SDL_Event input_event;

  int running = 0;
  int alt_key_status = 0;
  char tuffy_font[100] = "Tuffy.ttf";

  printf("Loading... \n");

This section highlights how the programs run are just like normal C programs on your desktop machine. You have your normal main function, and some variable declarations at the top of the function. The screen dimensions provided match up with the LCD on the BF548 EZ-KIT. It also creates the definition of the two boxes to be drawn on the screen. The alt_key_status flag is a flag that is used in this program to set whether the key pushed is the normal button or the alternative value (in red). This is built into the demo as the alternative value isn't actually available in the default keypad driver.

Initializing the video subsystem

if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
  fprintf(stderr, "Error: Unable to init SDL: %s\n", SDL_GetError());
  exit(1);
}
atexit(SDL_Quit);
SDL_ShowCursor(SDL_DISABLE);

screen = SDL_SetVideoMode(screen_width, screen_height, screen_bitdepth, SDL_HWSURFACE | SDL_DOUBLEBUF);
if (screen == NULL)
{
  fprintf(stderr, "Error: Unable to grab screen\n");
  SDL_Quit();
  exit(1);
}

printf("Done!\n");

This section of code will initialise the video subsystem of SDL so that SDL knows it will have a graphics buffer to write to. If it fails, it will abort the program. The atexit call is added so that when the program closes, SDL will clean itself up.

It also grabs the screen to write to by making a call to SDL_SetVideoMode and provides the screen details, note that width, height and depth are provided at the start of this program and are set to the LCD screens actual dimensions so this creates a full screen window. If this fails, the program will abort.

This section will be quite common for any SDL program using the LCD and the SDL_Init call might have to OR other subsystems as well if you're using things like audio.

Initializing the ttf font subsystem

if(TTF_Init() == -1) 
{ 
  fprintf(stderr, "Error: Unable to init TTF: %s\n", SDL_GetError());
  SDL_Quit();
  exit(1);
}

text_font = TTF_OpenFont(tuffy_font, 28); 
if(text_font == NULL) 
{ 
  fprintf(stderr, "Error: Unable to open font file!\n");
  SDL_Quit();
  exit(1);
}

text_font_tiny = TTF_OpenFont(tuffy_font, 10); 
if(text_font == NULL) 
{ 
  fprintf(stderr, "Error: Unable to open font file!\n");
  SDL_Quit();
  exit(1);
}

This section of code will initialise the font subsystem (SDL_ttf) and get it ready for use. It also opens the Tuffy font file and loads it as the true type font for drawing, aborting the program if the font file cannot be opened. Note this program loads the font twice, one at normal font size, and one for the tiny “2nd” button flag graphics.

Drawing Screen

// Draw a red bar at half width
SDL_Rect rect0 = {0, 0, screen_width, screen_height};
SDL_FillRect(screen, &rect0, 0xFFFFFF);

// Drawing text
SDL_Color color = {0, 0, 0};
SDL_Rect text_box = {200, 90, 150, 50};
SDL_Surface *text_surface = TTF_RenderText_Solid(text_font, "Waiting..", color);
SDL_BlitSurface(text_surface, NULL, screen, &text_box);
SDL_FreeSurface(text_surface);

SDL_Flip(screen);

This section merely draws a full screen white rectangle to the screen, then calls the text rendering function to write “Waiting…” to the screen. For further information on how the drawing works, look at the LCD demos pages, especially shapes and animated and text.

Input handling loop

printf("Waiting for input. Interrupt to exit\n"); 
memset(&input_event, 0, sizeof(input_event));
while (running == 0)
{
  if (SDL_PollEvent(&input_event))
  {
    if (input_event.type == SDL_QUIT)
    {
      running = 1;
    }
    else if (input_event.type == SDL_KEYDOWN)
    {
      char* keychar = convert_sym_to_keychar(input_event.key.keysym.sym, alt_key_status);
      printf("%d, %s\n", input_event.key.keysym.sym, keychar);

      // Drawing key press on screen
      SDL_Rect rect0 = {0, 0, screen_width, screen_height};
      SDL_FillRect(screen, &rect0, 0xFFFFFF);

      SDL_Surface *text_surface = TTF_RenderText_Solid(text_font, keychar, color);
      SDL_BlitSurface(text_surface, NULL, screen, &text_box);
      SDL_FreeSurface(text_surface);

      // Update 2nd key status
      if (strcmp(keychar, "2ND") == 0)
      {
        alt_key_status ^= 1;
      }

      // Draw 2nd key status box
      if (alt_key_status == 1)
      {
        rectangleColor(screen, 199, 199, 281, 221, 0xB45F04FF);
        boxColor(screen, 200, 200, 280, 220, 0xFF8000FF);
        SDL_Rect tiny_text_box = {204, 204, 80, 20};
        SDL_Surface *text_surface = TTF_RenderText_Solid(text_font_tiny, "2nd", color);
        SDL_BlitSurface(text_surface, NULL, screen, &tiny_text_box);
        SDL_FreeSurface(text_surface);
      }

      SDL_Flip(screen);

      free(keychar);
    }
    else if (input_event.type == SDL_KEYUP)
    {
      SDL_Rect rect0 = {0, 0, screen_width, screen_height};
      SDL_FillRect(screen, &rect0, 0xFFFFFF);

      // Clear text
      SDL_Surface *text_surface = TTF_RenderText_Solid(text_font, "", color);
      SDL_BlitSurface(text_surface, NULL, screen, &text_box);
      SDL_FreeSurface(text_surface);

      // Draw 2nd key status box
      if (alt_key_status == 1)
      {
        rectangleColor(screen, 199, 199, 281, 221, 0xB45F04FF);
        boxColor(screen, 200, 200, 280, 220, 0xFF8000FF);
        SDL_Rect tiny_text_box = {204, 204, 80, 20};
        SDL_Surface *text_surface = TTF_RenderText_Solid(&bsp;text_font_tiny, "2nd", color);
        SDL_BlitSurface(text_surface, NULL, screen, &tiny_text_box);
        SDL_FreeSurface(text_surface);
      }

      SDL_Flip(screen);
    }
  }
}

This main loop performs the key detection. Whenever a key is pushed (SDL_KeyDown) it will render that character on the screen using the ttf drawing library. When that key is released, it will clear the screen. It also looks for any “2nd” key pushes and activates the alternative keys. This is not a feature of the keypad driver and if you wish to do something similar, you will have to code a wrapping function to do the conversion like this demo.

This section also performs the common input loop that will continuously check for any program input. This one is looking for an SDL_Quit call (from program termination) to perform an exit.

Exiting

SDL_Quit();
return 0;

This section just does some basic clean up and exits the program.

Compiling keypad

First make sure that your kernel has the libraries libSDL, SDL_ttf 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 -lSDL_ttf \ 
keypad.c -o keypad

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 libraries SDL_gfx & SDL_ttf are loaded. Without these library, our program would not have access to the required graphical functions.

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

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

root:/> make keypad

Further Reading

The keypad driver page on the wiki is bf54x-keys

The keypad enter key provides the same response as pushing down the rotary key, so if you are using both in an application, you should look at reading directly from the event device node for event inputs. This is demonstrated in the gpiokeys demo. You can look up event device node for further information about this approach.