Embedded Artists


We are the leading providers of products and services around prototyping, evaluation and OEM platforms using NXP's ARM-based microcontrollers.

LPC4088DM Using USBHost

Warning

This documentation was written for mbed OS 2 and not mbed OS 5. There is no official USB support for LPC4088 in mbed OS 5.

The display modules can be used in either USB Host or USB Device mode.

The DMSupport library contains a fork of mbed's official USBHost library. The reason for forking the library is to make it work on the LPC4088 (the original library only works on LPC1768) as well as adapting some parts of the library to work better in an RTOS.

The USB Host stack contains support for the following USB classes:

Class NameStatus
3GModuleUntested & Unsupported
HIDTested OK with both mouse and keyboard
HubTested OK
MIDIUntested & Unsupported
MassStorageTested OK, but slow
SerialUntested & Unsupported

Using USBHost

The USB Host library has been modified to send a signal when something is added to or removed from the USB bus. This allows the user program to respond to only those events instead of endlessly polling the status of the bus and using resources while doing so.

The pseudo code for handling USB disconnect/connect looks like this:

// This identifier can be any 2^x number but must be same on sender and receiver side
#define USB_CONNECTION_EVENT   (1<<4)

// The thread:
void usbTask(void const* args) {
  // Create classes for MassStorage, Keyboard, Mouse etc...
 
  // Register as a listener for events
  USBHost* host = USBHost::getHostInst();
  host->signalOnConnections(Thread::gettid(), USB_CONNECTION_EVENT);

  while (true) {
    // wait for connect/disconnect message from USBHost
    Thread::signal_wait(USB_CONNECTION_EVENT);
 
    // something happened on the USB bus, see if it affects USB Mass Storage

    // check if a USB memory stick was inserted or removed...

    // check if a USB keyboard was inserted or removed...

    // check if a USB mouse was inserted or removed...
  }
}

void main(void) {
  // Initialize DMBoard as usual...
 
  // Start other threads...
 
  // Start the USB thread
  Thread tUSBHandler(usbTask, NULL, osPriorityNormal, 8192);
 
  // Do other stuff
  ...
}


USB Mass Storage

See this wiki page describing how to use USB MassStorage.

USB Keyboard

The USB Host stack supports the use of a USB keyboard. Once connected it is possible to attach a callback function to receive everything that is typed.

This is an example showing how print each received character:

#include "mbed.h"
#include "DMBoard.h"
#include "USBHostKeyboard.h"

// Called for each typed key 
void keyEvent(uint8_t key)
{
  DMBoard::instance().logger()->printf("Typed '%c'  (0x%02x)\n", key, key);
}

// This identifier can be any 2^x number but must be same on sender and receiver side
#define USB_CONNECTION_EVENT   (1<<4)
void usbTask(void const* args)
{
  RtosLog* log = DMBoard::instance().logger();
  bool keyboardConnected = false;
 
  // create the needed USB classes
  USBHostKeyboard* keyboard = new USBHostKeyboard();
 
  // register for events when devices are added/removed
  USBHost* host = USBHost::getHostInst();
  host->signalOnConnections(Thread::gettid(), USB_CONNECTION_EVENT);
 
  while (true) {
    // wait for connect/disconnect message from USBHost
    Thread::signal_wait(USB_CONNECTION_EVENT);
 
    // something happened on the USB bus, see if it affects USB keyboard          
    if (keyboard->connected()) {
      if (!keyboardConnected) {
        keyboardConnected = true;
        log->printf("USB Keyboard - Connected\n");
        keyboard->attach(keyEvent);
      }
    } else {
      if (keyboardConnected) {
        keyboardConnected = false;
        log->printf("USB Keyboard - Ejected\n");
      }
      if (keyboard->connect()) {
        keyboardConnected = true;
        log->printf("USB Keyboard - Connected\n");
        keyboard->attach(keyEvent);
      }
    }
  }
}
 
void main(void) {
  // Initialize DMBoard as usual...
 
  // Start other threads...
 
  // Start the USB thread
  Thread tUSBHandler(usbTask, NULL, osPriorityNormal, 8192);
 
  // Do other stuff
  ...
}

USB Mouse

The USB Host stack supports the use of a USB mouse. Once connected it is possible to attach a callback function to receive everything that is typed.

This is an example showing how print each received character:

#include "mbed.h"
#include "DMBoard.h"
#include "USBHostMouse.h"

// Called for each mouse action (click and/or move)
void mouseEvent(uint8_t buttons, int8_t x, int8_t y, int8_t z)
{
  DMBoard::instance().logger()->printf("Mouse: buttons 0x%02x,  x,y,z = %d,%d,%d\n", buttons, x, y, z);
}

// This identifier can be any 2^x number but must be same on sender and receiver side
#define USB_CONNECTION_EVENT   (1<<4)
void usbTask(void const* args)
{
  RtosLog* log = DMBoard::instance().logger();
  bool mouseConnected = false;
 
  // create the needed USB classes
  USBHostMouse* mouse = new USBHostMouse();
 
  // register for events when devices are added/removed
  USBHost* host = USBHost::getHostInst();
  host->signalOnConnections(Thread::gettid(), USB_CONNECTION_EVENT);
 
  while (true) {
    // wait for connect/disconnect message from USBHost
    Thread::signal_wait(USB_CONNECTION_EVENT);
 
    // something happened on the USB bus, see if it affects USB mouse
    if (mouse->connected()) {
      if (!mouseConnected) {
        mouseConnected = true;
        log->printf("USB Mouse - Connected\n");
        mouse->attachEvent(mouseEvent);
      }
    } else {
      if (mouseConnected) {
        mouseConnected = false;
        log->printf("USB Mouse - Ejected\n");
      }
      if (mouse->connect()) {
        mouseConnected = true;
        log->printf("USB Mouse - Connected\n");
        mouse->attachEvent(mouseEvent);
      }
    }
  }
}
 
void main(void) {
  // Initialize DMBoard as usual...
 
  // Start other threads...
 
  // Start the USB thread
  Thread tUSBHandler(usbTask, NULL, osPriorityNormal, 8192);
 
  // Do other stuff
  ...
}


The LPC4088 comes with support for a cursor on the display. You can read more about it in the LPC4088 User Manual which can be downloaded from lpcware.

To use that instead of just printing the coordinates:

#include "mbed.h"
#include "DMBoard.h"
#include "USBHostMouse.h"

// Variables to keep track of the latest received data (to be printed in another thread maybe?)
static volatile int8_t mouse_button, mouse_x, mouse_y, mouse_z;

// As all movements are relative, these two variables contains the absolute position
static uint16_t cursor_x=0, cursor_y=0;

// Called for each mouse action (click and/or move)
void mouseEvent(uint8_t buttons, int8_t x, int8_t y, int8_t z)
{
    mouse_button = buttons;
    mouse_x = x;
    mouse_y = y;
    mouse_z = z;
    
    if (x < 0) {
        if (cursor_x > -x) {
            cursor_x += x;
        } else {
            cursor_x = 0;
        }
    } else {
        if ((cursor_x + x) >= 480) {
            cursor_x = 479;
        } else {
            cursor_x += x;
        }
    }
    y = y/8;
    if (y < 0) {
        if (cursor_y > -y) {
            cursor_y += y;
        } else {
            cursor_y = 0;
        }
    } else {
        if ((cursor_y + y) >= 272) {
            cursor_y = 271;
        } else {
            cursor_y += y;
        }
    }
    
    //Chip_LCD_Cursor_SetPos(LPC_LCD, cursor_x, cursor_y);
    LPC_LCD->CRSR_XY = (cursor_x & 0x3FF) | ((cursor_y & 0x3FF) << 16);
}

// Data about the cursor to show
#define LCD_CURSOR_32x32 0
#define LCD_CURSOR_64x64 1
#define CURSOR_SIZE  LCD_CURSOR_32x32
#define CURSOR_H_SIZE 32
#define CURSOR_V_SIZE 32
#define CURSOR_NUM   0    
#define CURSOR_H_OFS (10)
#define CURSOR_V_OFS (6)

// Cursor image
const unsigned char __attribute__ ((aligned(4))) Cursor[(CURSOR_H_SIZE / 4) * CURSOR_V_SIZE] =
{
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xFA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFE, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFE, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFE, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFE, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xEA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xFF, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xFF, 0xFA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xFF, 0xFE, 0xAA, 0xAA,
	0xAA, 0xAB, 0xFB, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAB, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAB, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAA, 0xBF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAA, 0xBF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAF, 0xFF, 0xFF, 0xFE, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xFF, 0xFE, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xFF, 0xFE, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
};

// Code to enable/disable the cursor
void prepareCursor(bool enable) {
  //Chip_LCD_Cursor_Disable(LPC_LCD, 0);
  LPC_LCD->CRSR_CTRL = (CURSOR_NUM << 4);
    
  if (enable) {
    //Chip_LCD_Cursor_Config(LPC_LCD, LCD_CURSOR_32x32, true);
    LPC_LCD->CRSR_CFG = ((true ? 1 : 0) << 1) | CURSOR_SIZE;
    
    //Chip_LCD_Cursor_WriteImage(LPC_LCD, 0, (void *) Cursor);
    {
      int i, j;
      uint32_t *fifoptr, *crsr_ptr = (uint32_t *) Cursor;

      /* Check if Cursor Size was configured as 32x32 or 64x64*/
      if (CURSOR_SIZE == LCD_CURSOR_32x32) {
        i = CURSOR_NUM * 64;
        j = i + 64;
      }
      else {
        i = 0;
        j = 256;
      }
      fifoptr = (uint32_t *) &(LPC_LCD->CRSR_IMG[0]);

      /* Copy Cursor Image content to FIFO */
      for (; i < j; i++) {
        *fifoptr = *crsr_ptr;
        crsr_ptr++;
        fifoptr++;
      }
    }
    
    //Chip_LCD_Cursor_SetClip(LPC_LCD, CURSOR_H_OFS, CURSOR_V_OFS);
    LPC_LCD->CRSR_CLIP = (CURSOR_H_OFS & 0x3F) | ((CURSOR_V_OFS & 0x3F) << 8);
    
    //Chip_LCD_Cursor_SetPos(LPC_LCD, cursor_x, cursor_y);
    
    //Chip_LCD_Cursor_Enable(LPC_LCD, 0);
    LPC_LCD->CRSR_CTRL = (CURSOR_NUM << 4) | 1;
  }
}

// This identifier can be any 2^x number but must be same on sender and receiver side
#define USB_CONNECTION_EVENT   (1<<4)
void usbTask(void const* args)
{
  RtosLog* log = DMBoard::instance().logger();
  bool mouseConnected = false;
 
  // create the needed USB classes
  USBHostMouse* mouse = new USBHostMouse();
 
  // register for events when devices are added/removed
  USBHost* host = USBHost::getHostInst();
  host->signalOnConnections(Thread::gettid(), USB_CONNECTION_EVENT);
 
  // make sure that the cursor is not shown until a mouse is connected
  prepareCursor(false);

  while (true) {
    // wait for connect/disconnect message from USBHost
    Thread::signal_wait(USB_CONNECTION_EVENT);
 
    // something happened on the USB bus, see if it affects USB mouse
    if (mouse->connected()) {
      if (!mouseConnected) {
        mouseConnected = true;
        log->printf("USB Mouse - Connected\n");
        mouse->attachEvent(mouseEvent);
        prepareCursor(true);
      }
    } else {
      if (mouseConnected) {
        prepareCursor(false);
        mouseConnected = false;
        log->printf("USB Mouse - Ejected\n");
      }
      if (mouse->connect()) {
        mouseConnected = true;
        log->printf("USB Mouse - Connected\n");
        mouse->attachEvent(mouseEvent);
        prepareCursor(true);
      }
    }
  }
}
 
void main(void) {
  // Initialize DMBoard as usual...
 
  // Start other threads...
 
  // Start the USB thread
  Thread tUSBHandler(usbTask, NULL, osPriorityNormal, 8192);
 
  // Do other stuff
  ...
}

All wikipages