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 Display

The display modules can be ordered with different display options. The displays may have different capabilities, sizes and touch controllers.

The DMSupport library handles the different displays and presents a common interface:

Import library

Public Member Functions

virtual DisplayError init ()=0
Initialize the display.
virtual DisplayError powerUp (void *framebuffer, Resolution res=Resolution_16bit_rgb565, FrameRate_t rate=FrameRate_Normal)=0
Turns the display on with the specified framebuffer showing.
virtual DisplayError powerDown ()=0
Turns the display off.
virtual DisplayError backlight (int percent)=0
Sets the backlight level.
virtual uint16_t width ()=0
Returns the width (in pixels) of the display.
virtual uint16_t height ()=0
Returns the height (in pixels) of the display.
virtual uint16_t bytesPerPixel ()=0
Returns the number of bytes used by each pixel.
virtual uint32_t fbSize ()=0
Returns the number of bytes used for each frame buffer.
virtual bool landscape ()=0
Returns the display orientation.
virtual bool isSupported (Resolution res)=0
Returns true if the specified resolution can be used.
virtual Resolution currentResolution ()=0
Returns the current resolution.
virtual void setFramebuffer (void *buff)=0
Replaces the current framebuffer.
virtual void * swapFramebuffer (void *buff)=0
Replaces the current framebuffer with the specified one.
virtual void * allocateFramebuffer (Resolution res=Resolution_16bit_rgb565)=0
Allocate enough memory for one framebuffer.
virtual void * allocateFramebuffers (uint32_t num=1, Resolution res=Resolution_16bit_rgb565)=0
Allocate enough memory for one or more consequtive framebuffers.

Using the Display

To use the display it must first be enabled in the dm_board_config.h file:

#define DM_BOARD_USE_DISPLAY


The initialization of the display is done in the init() function in DMBoard.

After initialization the display is powered down and nothing is shown. The final step is to create a frame buffer to draw on and then power up the display:

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

int main()
{
  DMBoard::BoardError err;
  DMBoard* board = &DMBoard::instance();
  RtosLog* log = board->logger();
  Display* disp = board->display();
  
  do {
    err = board->init();
    if (err != DMBoard::Ok) {
      log->printf("Failed to initialize the board, got error %d\r\n", err);
      break;
    }

    // allocate a frame buffer to draw on
    void* fb = disp->allocateFramebuffer();
    if (fb == NULL) {
      log->printf("Failed to allocate memory for a frame buffer\r\n");
      err = DMBoard::MemoryError;
      break;
    }
    
    // power up the display using the new frame buffer
    Display::DisplayError disperr = disp->powerUp(fb);
    if (disperr != Display::DisplayError_Ok) {
      log->printf("Failed to initialize the display, got error %d\r\n", disperr);
      break;
    }
  } while(false);

  ...


The code above will show the uninitialized frame buffer which could be any pattern depending on what was in the memory when it was allocated. A quick fix is to use memset to clear the buffer before the call to powerUp:

    ...
    // initialize the frame buffer
    memset(fb, 0x00, display->fbSize()); // BLACK
    //memset(fb, 0xff, display->fbSize()); // WHITE
    //memset(fb, 0xe0, display->fbSize()); // RED

    // power up the display using the new frame buffer
    Display::DisplayError disperr = disp->powerUp(fb);
    ...


Frame Rate

The displays mounted on the display modules are configured to have a frame rate that works in most cases. The frame rate can be changed between Low, Normal and High by passing the appropriate value to the powerUp() function.

A high frame rate should result in less flickering of the image as it is redrawn more often. The disadvantage is that the memory bus is used more which could starve other memory intensive operations. The time between screen updates is shorter meaning that there is less time to update the back buffer before it is time to switch.

A low frame rate could result in flickering on the screen as it is not redrawn often enough. The advantage is that there is more time to update the back buffers before it is time to switch and the memory bus is not used as much as when a high frame rate is used.

Note

When using a display with 800x480 (or more) in combination with 18-bit or 24-bit resolutions the frame rate must be set to FrameRate_Low. Higher frame rates will cause the display to just show noice.

Resolutions

The default resolution for all displays is 16-bit in RGB565 format, meaning that each pixel uses 5 bits for red and blue colors and 6 bits for green for a total of 16 bits per pixel.

Some displays may support other, higher, resolutions. Exactly which are supported can be tested like this:

  Display* disp = DMBoard::instance().display();
  if (disp->isSupported(Display::Resolution_16bit_rgb565)) {
    // supports 16-bit in RGB565 format
  }
  if (disp->isSupported(Display::Resolution_18bit_rgb666)) {
    // supports 18-bit in RGB666 format
  }
  if (disp->isSupported(Display::Resolution_24bit_rgb888)) {
    // supports 24-bit in RGB888 format
  }


Altough switching to a higher resolution means that the image looks better, it comes with several disadvantages:

  • The memory requirements are higher. A 16-bit RGB565 resolution uses 2 bytes per pixel. The 18-bit and 24-bit formats use 4 bytes per pixel. For a 480x272 display this means 255Kbytes vs 510Kbytes of RAM will be used for each frame buffer.
  • A larger frame buffer size means slower full-screen processing
  • Images stored in a higher resolution will take up more storage space and will take longer to decode

Note

Selecting what resolution to use must be done while the display is powered down.

Note

The DMBasicGUI library is currently only supporting 16-bit format.

The example below starts the display in 24-bit mode and then switches to 16-bit after 5 seconds:

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

int main()
{
  DMBoard::BoardError err;
  DMBoard* board = &DMBoard::instance();
  RtosLog* log = board->logger();
  Display* disp = board->display();
  
  do {
    err = board->init();
    if (err != DMBoard::Ok) {
      log->printf("Failed to initialize the board, got error %d\r\n", err);
      break;
    }

    // allocate a frame buffer to draw on
    void* fb = disp->allocateFramebuffer(Display::Resolution_24bit_rgb888);
    if (fb == NULL) {
      log->printf("Failed to allocate memory for a frame buffer\r\n");
      err = DMBoard::MemoryError;
      break;
    }

    // initialize the frame buffer to be WHITE
    memset(fb, 0xff, disp->fbSize();
    
    // power up the display using the new frame buffer
    Display::DisplayError disperr = disp->powerUp(fb, Display::Resolution_24bit_rgb888);
    if (disperr != Display::DisplayError_Ok) {
      log->printf("Failed to initialize the display, got error %d\r\n", disperr);
      break;
    }

    // wait before switching to 16-bit mode...
    wait(5);

    // power down before a switch
    Display::DisplayError disperr = disp->powerDown();
    if (disperr != Display::DisplayError_Ok) {
      log->printf("Failed to power down the display, got error %d\r\n", disperr);
      break;
    }

    // free the old frame buffer and allocate a new one (the sizes will differ)
    free(fb);
    fb = disp->allocateFramebuffer(Resolution_16bit_rgb565);
    if (fb == NULL) {
      log->printf("Failed to allocate memory for a frame buffer\r\n");
      err = DMBoard::MemoryError;
      break;
    }

    // initialize the frame buffer to be BLACK
    memset(fb, 0x00, disp->fbSize();
    
    // power up the display using the new frame buffer
    Display::DisplayError disperr = disp->powerUp(fb, Resolution_16bit_rgb565);
    if (disperr != Display::DisplayError_Ok) {
      log->printf("Failed to initialize the display, got error %d\r\n", disperr);
      break;
    }
  } while(false);

  ...

Double Buffering

One common technique when drawing on a frame buffer is to keep a back buffer to draw on and then change buffer when it is completed. This way the shown buffer (or image) is flicker free. The following examples show what it looks without double buffering:

#include "mbed.h"
#include "DMBoard.h"
void drawWithout()
{
  DMBoard* board = &DMBoard::instance();
  Display* disp = board->display();
  RtosLog* log = board->logger();
  void* fb = disp->allocateFramebuffer();
  if (fb == NULL) {
    log->printf(“Failed to allocate memory!\n”);
    mbed_die();
  }
  
  // power up the display
  … = disp->powerUp(fb1);
  …
  
  // do "fading" over and over again
  bool fb1Active = true;
  while(true) {
    for (int i = 0; i < 255; i++) {
      memset(fb, i, disp->fbSize());
    }
  }
  
  // add code to cleanup and power down
}


.. and with double buffering:

void drawBuffered()
{
  DMBoard* board = &DMBoard::instance();
  Display* disp = board->display();
  RtosLog* log = board->logger();
  void* fb1 = disp->allocateFramebuffer();
  void* fb2 = disp->allocateFramebuffer();
  if (fb1 == NULL) || (fb2 == NULL) {
    log->printf(“Failed to allocate memory!\n”);
    mbed_die();
  }
  memset(fb1, 0, disp->fbSize());
  memset(fb2, 0, disp->fbSize());
  
  // power up the display
  … = disp->powerUp(fb1);
  …
  
  // Double Buffering Alternative 1: variable keeps track
  // of which buffer to draw on and which to show
  bool fb1Active = true;
  while(true) {
    for (int i = 0; i < 255; i++) {
      if (fb1Active) {
        memset(fb2, i, disp->fbSize());
        disp->setFramebuffer(fb2);
      } else {
        memset(fb1, i, disp->fbSize());
        disp->setFramebuffer(fb1);
      }
      fb1Active = !fb1Active;
    }
  }
  
  // Double Buffering Alternative 2: use swapFramebuffer() which
  // returns the old buffer. Reduces code complexity.
  void* fbInactive = fb2;
  while(true) {
    for (int i = 0; i < 255; i++) {
      memset(fbInactive, i, disp->fbSize());
      fbInactive = disp->swapFramebuffer(fbInactive);
    }
  }
  
  // add code to cleanup and power down
}


In some cases it is even better to use tripple-buffering and that is easily done with the same interface.

Graphical Libraries

Drawing directly on the frame buffer without support functions is very inefficient. There are several manufacturers of graphical libraries with support functions ranging from drawing basic shapes to full-fledged window managers.

The following libraries are available today:


All wikipages