world leader in high performance signal processing
Trace: » usb-keyboard

ADSP-BF548 EZ-KIT Quick Start: Peripheral Demos: usb-keyboard

www.analog.com_static_imported-files_images_product_descriptions_680755565image1a.jpg

What is usb_keyboard

An application that uses the linux gadget drivers to make the BF548 EZ-KIT appear to be a USB keyboard. This is a good sample application to demonstrate using the gadget USB drivers that come with linux. USB HID is a common application use, and for fast prototyping the uClinux kernel is perfect for this.

Note that the kernel option 'Device Drivers > USB support > USB Gadget Support > USB Peripheral Controller' must be set to 'Inventra HDRC USB Peripheral (TI, ADI, …)' and 'Device Drivers > USB support > USB Gadget Support > USB Gadget Drivers > HID Gadget' must be enabled as a maybe (dot instead of tick).

Device Drivers ->
  USB support ->
    USB Gadget Support ->
      USB Peripheral Controller
      [X] Inventra HDRC USB Peripheral (TI, ADI, ...)
      USB Gadget Drivers
      [X] HID Gadget

If you cannot select Inventra as an option, make sure you have the driver mode set as 'USB Peripheral'.

Device Drivers ->
  USB support ->
    Inventra Highspeed Dual Role Controller (TI, ADI, ...)
      Driver Mode
      [X] USB Peripheral

If you are not using the blackfin distribution on the customised Ubuntu ISO then you also have to add the hidg function descriptor into the board configuration. Modify the file “blackfin-linux-dist/linux-2.6.x/arch/blackfin/mach-bf548/boards/ezkit.c” to contain the following code segments:

#if defined(CONFIG_USB_G_HID) || defined(CONFIG_USB_G_HID_MODULE)
#include 
#include 

/* hid descriptor for a keyboard */
static struct hidg_func_descriptor my_hid_data = {
  .subclass	 = 0, /* No subclass */
  .protocol	 = 1, /* Keyboard */
  .report_length	 = 8,
  .report_desc_length	= 63,
  .report_desc	 = {
    0x05, 0x01,	/* USAGE_PAGE (Generic Desktop)	 */
    0x09, 0x06,	/* USAGE (Keyboard) */
    0xa1, 0x01,	/* COLLECTION (Application) */
    0x05, 0x07,	/* USAGE_PAGE (Keyboard) */
    0x19, 0xe0,	/* USAGE_MINIMUM (Keyboard LeftControl) */
    0x29, 0xe7,	/* USAGE_MAXIMUM (Keyboard Right GUI) */
    0x15, 0x00,	/* LOGICAL_MINIMUM (0) */
    0x25, 0x01,	/* LOGICAL_MAXIMUM (1) */
    0x75, 0x01,	/* REPORT_SIZE (1) */
    0x95, 0x08,	/* REPORT_COUNT (8) */
    0x81, 0x02,	/* INPUT (Data,Var,Abs) */
    0x95, 0x01,	/* REPORT_COUNT (1) */
    0x75, 0x08,	/* REPORT_SIZE (8) */
    0x81, 0x03,	/* INPUT (Cnst,Var,Abs) */
    0x95, 0x05,	/* REPORT_COUNT (5) */
    0x75, 0x01,	/* REPORT_SIZE (1) */
    0x05, 0x08,	/* USAGE_PAGE (LEDs) */
    0x19, 0x01,	/* USAGE_MINIMUM (Num Lock) */
    0x29, 0x05,	/* USAGE_MAXIMUM (Kana) */
    0x91, 0x02,	/* OUTPUT (Data,Var,Abs) */
    0x95, 0x01,	/* REPORT_COUNT (1) */
    0x75, 0x03,	/* REPORT_SIZE (3) */
    0x91, 0x03,	/* OUTPUT (Cnst,Var,Abs) */
    0x95, 0x06,	/* REPORT_COUNT (6) */
    0x75, 0x08,	/* REPORT_SIZE (8) */
    0x15, 0x00,	/* LOGICAL_MINIMUM (0) */
    0x25, 0x65,	/* LOGICAL_MAXIMUM (101) */
    0x05, 0x07,	/* USAGE_PAGE (Keyboard) */
    0x19, 0x00,	/* USAGE_MINIMUM (Reserved) */
    0x29, 0x65,	/* USAGE_MAXIMUM (Keyboard Application) */
    0x81, 0x00,	/* INPUT (Data,Ary,Abs) */
    0xc0	 /* END_COLLECTION */
  }
};

static struct platform_device my_hid = {
  .name	 = "hidg",
  .id	 = 0,
  .num_resources	 = 0,
  .resource	 = 0,
  .dev.platform_data	= &my_hid_data,
};
#endif
static struct platform_device *ezkit_devices[] __initdata = {

#if defined(CONFIG_USB_G_HID) || defined(CONFIG_USB_G_HID_MODULE)
  &my_hid,
#endif

Download usb_keyboard

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

  • Change directory to /demos/usb

    root:/> cd /demos/usb
  • Install gadget hid driver

    root:/> modprobe g_hid
    g_hid gadget: HID Gadget, version: 2010/03/16
    g_hid gadget: g_hid ready
    root:/> 
  • Plug USB OTG port into PC

    g_hid gadget: high speed config #1: HID Gadget
  • Run usb_keyboard

    root:/> ./usb_keyboard
    Loaded. Try pressing the keypad buttons. Interrupt to exit (Ctrl + C).
  • Open gedit on PC
  • Press keys on Blackfin keypad
  • Exit (Ctrl + C)

How the usb_keyboard demo works

The USB keyboard demo works by opening up the keypad event buffer and the USB device buffer. It then continuously polls the keypad buffer for events, if it finds any key presses it will handle them by sending the corresponding keystroke via the USB device buffer. When it detects the key being released, it will also do the same via the USB device buffer.

Note that there are cleaner ways to do this demo than this code however this is the simplest to understand. Much of the keypad code explanation is omitted, if you are interested in learning more about how the event buffer is being read and interpreted, you can look into the gpiokeys demo.

Set Up

// Predetermined usb hid buffer location
filename = "/dev/hidg0";

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

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

// Open usb hid device buffer
if ((fd_usb = open(filename, O_RDWR, 0666)) == -1) {
  perror(filename);
  return 3;
}

As you can see, the program opens the event input buffer and the usb device buffer as standard I/O. In this case, the usb device is hard coded to /dev/hidg0 however this could differ depending on the set up. You can check the /dev folder on your Blackfin to see which device alias it is using.

The keypad event input buffer location is not hard coded, and a special helper function called find_event_input is used. This function scans through all the event buffers it can find for a matching device name. This function is in the hid_keyboard.c file if you wish to also use it.

Main Input Loop

// Main loop
while (running == 1) 
{
  rd = read(fd_keypad, 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 && ev[i].code == KEY_TAB &&         ev[i].value == 1) 
      {
        altkey ^= 1;
      }

      if (ev[i].type == EV_KEY && altkey == 0) 
      {
        // Handle keypad event
        handleKeypadEvent(ev[i].code, ev[i].value, fd_usb);
      }
      else if (ev[i].type == EV_KEY && altkey == 1) 
      {
        // Handle keypad event
        handleAltKeypadEvent(ev[i].code, ev[i].value, fd_usb);
      }
    }
  }
}

The program then runs its main loop where it continuously scans the keypad buffer for events. If it detects a 2ND key press (KEY_TAB) it will toggle the altkey variable. If it detects a key press from another key, it will call the appropriate key handling subroutine (depending on whether altkey is toggled or not).

The key handling subroutines will merely check what key was pushed, and then call the appropriate usb message sending function, some of which are described next.

Alpha Key Commands

void sendAlphaKey(int fd, char key, int capitals)
{
  // Set string to blank first
  memset(report, 0x0, to_send);

  // Check if letter should be capitals
  if (capitals > 0)
  {
    report[0] = 0x02; // Set left shift to active
  }

  // Send string down to host
  // According to usb hid conventions, shift alpha keys to start from 0x04
  report[2] = key - ('a' - 0x04); // a = 0x04, b = 0x05, etc..
  write(fd, report, to_send);
}

This function will traslate and write a character to the usb device buffer according to the usb keyboard hid protocol.

Numeric Key Command

void sendNumericKey(int fd, int no)
{
  // Set string to blank first
  memset(report, 0x0, to_send);

  // Send string down to host
  // Shift numerical values to start from 0x1E for usb hid
  report[2] = no + 0x1D;
  if (report[2] == 0x1D) { report[2] = 0x27; } // 0 = 0x27
  write(fd, report, to_send);
}

This function will traslate and write a numeric character to the usb device buffer according to the usb keyboard hid protocol.

Key Release Command

void sendCleanup(int fd)
{
  // Set string to blank first
  memset(report, 0x0, to_send);

  // Send string down to host
  write(fd, report, to_send);
}

This function will clear the usb device buffer so it appears the key has stopped being pushed. These three usb key functions are just several available in the demo program.

This demo shows that by making use of pre-existing linux libraries and tools, you can build simple yet functional applications. The event handling was fairly simple while managing the usb device buffer was quite simple also. Do note this demo did not show reading from the usb device buffer, as sometimes events do come back down to the board such as when a keyboard led needs to be toggled.

Compiling usb_keyboard

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 hid_keyboard.c keytools.c -o usb_keyboard

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 final parameters match up to standard gcc compiling; “hid_keyboard.c” and “keytools.c” are the source files and ”-o usb_keyboard” indicates the output file is “usb_keyboard”.

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

root:/> make usb_keyboard

Further Reading

The usb gadget drivers are discussed on the USB Gadget API Framework page.

You can research more about USB HID on pages such as www.usb.org/developers/devclass_docs/HID1_11.pdf.