world leader in high performance signal processing
Trace: » rotary

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

www.analog.com_static_imported-files_images_product_descriptions_680755565image1a.jpg

What is rotary

This demo program will use SDL_gfx to draw a bar on the LCD screen. When the user spins the rotary left or right, it will shrink or grow the bar respectively. When the user pushes the rotary down it will change the bars colour. The program will operate until it is terminated (Ctrl + C).

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

This demo only works if the rotary driver is set up to provide +/- keystroke events rather than relative events. This is disabled by default in the kernel, but you can enable it by editing the file 'blackfin-linux-dist/linux-2.6.x/arch/blackfin/mach-bf548/boards/ezkit.c' and uncommenting '.rotary_up_key = KEY_UP,' and '.rotary_down_key = KEY_DOWN,'. You could also change what key the rotary button reports, if you need to make sure it doesn't conflict with the keypad.

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

Device Drivers ->
  Input device support ->
    Miscellaneous devices ->
      [X] Blackfin Rotary support

Download rotary

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

  • Change directory to /demos/rotary

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

    root:/> ./rotary
    Waiting for input. Interrupt to exit.
  • Turn rotary dial left or right or push it down

  • Exit (Ctrl + C)

How the rotary demo works

Required header files

#include <stdio.h>

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

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

As you can see, this program only grabs SDL_gfxPrimitives.h really for the low level drawing API. The SDL.h grab is left in just to show that it would be necessary to read the rotary input.

Main function

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

  SDL_Surface *screen;
  SDL_Event input_event;

  int running = 0;
  int bar_y1 = 120;
  int bar_y2 = 160;
  int bar_width = 10;
  int bar_color = 0xFF0000FF;

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.

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.

Drawing Screen

SDL_Rect rect0 = {0, 0, screen_width, screen_height};
SDL_FillRect(screen, &rect0, 0xFFFFFF);

boxColor(screen, 0, bar_y1, bar_width, bar_y2, bar_color);

SDL_Flip(screen);

This section merely draws a white rectangle to fill the screen, then calls the draws a box with the bar dimensions previously specified. These dimensions will be edited whenever the rotary is turned in a later section. For further information on how the drawing works, look at the LCD demos pages, especially shapes and animated.

Input handling loop

memset(&input_event, 0, sizeof(input_event));
while (running == 0)
{
  if (SDL_PollEvent(&input_event))
  {
    if (input_event.type == SDL_QUIT)
    {
      running = 1;
    }
    // Read for ROTARY input (only works when rotary encoder 
    // configured to report as key events, not relative events)
    else if (input_event.type == SDL_KEYDOWN)
    {
      if (input_event.key.keysym.sym == 273)
      {
        // Rotated Right
        // Increase bar length for visual effect
        if (bar_width < 478) 
        {
          bar_width++;
        }

        SDL_Rect rect0 = {0,0,480,272};
        SDL_FillRect(screen, &rect0, 0xFFFFFF);

        boxColor(screen, 0, 120, bar_width, 160, bar_color);

        SDL_Flip(screen);
      }
      else if (input_event.key.keysym.sym == 274)
      {
        // Rotated Left
        // Decrease bar length for visual effect
        if (bar_width > 2) 
        {
          bar_width--;
        }
        SDL_Rect rect0 = {0,0,480,272};
        SDL_FillRect(screen, &rect0, 0xFFFFFF);

        boxColor(screen, 0, 120, bar_width, 160, bar_color);

        SDL_Flip(screen);
      }
      else if (input_event.key.keysym.sym == 13)
      {
        // Rotary pushed
        // Change bar colour for visual effect
        if (bar_color == 0xFF0000FF)
        {
          bar_color = 0x00FF00FF;
        }
        else if (bar_color == 0x00FF00FF)
        {
          bar_color = 0x0000FFFF;
        }
        else if (bar_color == 0x0000FFFF)
        {
          bar_color = 0x000000FF;
        }
        else if (bar_color == 0x000000FF)
        {
          bar_color = 0xFF0000FF;
        }

        SDL_Rect rect0 = {0,0,480,272};
        SDL_FillRect(screen, &rect0, 0xFFFFFF);
        boxColor(screen, 0, 120, bar_width, 160, bar_color);

        SDL_Flip(screen);
      }
    }
  }
}

This main loop performs the rotary input detection. The rotary input will come in as key strokes, 274 (PGUP) will be when the rotary is turned left, 273 (PGDOWN) will be when the rotary is turned right, and 13 (ENTER) will be when the rotary is pushed. Now, in your default distribution of uClinux-2011R1-RC3, the rotary encoder does not normally provide left and right keystrokes but instead relative events in the event buffer. SDL does not have a built in way to handle those, but viewing the gpiokeys demo will show you an approach to handling the event buffer directly. This may be a good alternative to using SDL for input handling as there is no overhead, however it is much more complex.

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

Exiting

SDL_Quit();
return 0;

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

Compiling rotary

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 \ 
rotary.c -o rotary

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 this library, our program would not have access to the required graphics rendering functions.

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

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

root:/> make rotary

Further Reading

The information on the rotary can be found on the wiki page Blackfin Rotary/Thumbwheel Input Device Driver.

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.

This demo only works if the rotary driver is set up to provide +/- keystroke events rather than relative events. This is disabled by default in the kernel, but you can enable it by editing the file 'blackfin-linux-dist/linux-2.6.x/arch/blackfin/mach-bf548/boards/ezkit.c' and uncommenting '.rotary_up_key = KEY_UP,' and '.rotary_down_key = KEY_DOWN,'. This has already been done on the custom Ubuntu ISO. You could also change what key the rotary button reports, if you need to make sure it doesn't conflict with the keypad.