SSD16XX e-Paper display driver

GDEH0154D67

E-ink display with a display driver of SSD16XX (Ex - SSD1681) are a family of similar controller set with different properties. Some with color options or with the ability to do partial refreshes.

Tested with

  • SSD1681 (W)(C)

Functionality is provided by the SSD16XX (About Modules) module, using the Graphics library.

Notes

  • The display can be read perfectly in harsh sunlight, but has no back lighting.
  • E-paper displays are not known for fast refresh cycles.
  • E-paper displays need only power for updating the display, not for keeping it up.

Wiring Up

The bare display and controller module needs to be connected with a 24pin FPC connector with 0.5mm pitch and an additional driving circuit. There are rather huge and expensive ready to use development boards available from the display manufacturer. You can even try to build the minimum circuit yourself, e.g. like Jaroslav Sýkora did.

The following infos apply only to the connection between a common display and a microcontroller, ignoring the driving circuit.

Pin overview

SSD16XX Notes
GND Ground
SDA SPI mosi pin. The SSD16XX provides no miso pin.
SCL SPI Clock pin
CS1 Chip select pin, is used to prepare the SSD16XX to receive data over SPI. Pull High before you send data over SPI.
D/C Data/Command control pin, is used to prepare the SSD16XX to receive either commands (pulled LOW) or data (pulled HIGH) over SPI.
Res Hardware Reset pin, pull LOW to reset the SSD16XX.
BU This pin is Busy state output pin When Busy is High, the operation of the chip should not be interrupted, command should not be sent.
BS1 Pin for selecting SPI wire mode, pull LOW for 4-wire mode and HIGH for 3-wire mode.
3.3v Power pin.

The SSD16XX provides two types of SPI interface modes, but the module supports 4-wire mode only.

SPI-Mode 4-wire

In 4-wire mode you need to set the D/C pin before each SPI send to signal either a command or data will be send. The module takes care of that for you.

Wiring example for SPI 4-wire mode

SSD16XX Espruino Pico Notes
GND GND
SDA B5 B5 is SPI-1 mosi on Espruino Pico, you can also use SPI-2 or SPI-3.
SCL B3 B3 is SPI-1 clock on Espruino Pico, you can also use SPI-2 or SPI-3.
CS1 B6 You can use any of the GPIO pins on the Espruino Pico.
D/C B7 You can use any of the GPIO pins on the Espruino Pico.
Res A5 You can use any of the GPIO pins on the Espruino Pico.
BU A8 You can use any of the GPIO pins on the Espruino Pico.
BS1 A6 You can use any of the GPIO pins on the Espruino Pico or connect it to either GND or 3.3v.
3.3v A7 You can use any of the GPIO pins on the Espruino Pico to have full control or connect it to 3.3v.

Software

Example

//Example using a Nordict NRF52840DK 
var screen = require("SSD16XX");

var sck  = D47;
var mosi = D45;
SPI1.setup({mosi:mosi, sck:sck, baud: 4000000,order:'msb', bits:8});

var cs   = D44;
var busyPin = D43;
var dcPin = D42; //Data/Command
var resetPin = D40;

var screenSettings  = {
  display: {
    bpp : 1,
    displaySizeX      : 200,
    displaySizeY      : 200,
    coloredDisplay    : 1
  },
  spi: SPI1,
  csPin: D44,
  busyPin: D43,
  dcPin: D42,
  resetPin: D40
};

console.log("[Program started]");

screen.fullReset().then(() => {
  console.log("[screen init]");
  return screen.init();
}).then(() => {
  screen.g.clear(0x00);
  screen.g.cw.setFontVector(100);
  screen.g.cw.setColor(1).drawString("1",75,50);
  console.log("drawing a one");
  return screen.g.flip();
}).then(()=>{
  console.log("[got here 2]");
  screen.g.clear(0x00);
  screen.g.cw.setFontVector(100);
  screen.g.cw.setColor(1).drawString("2",75,50);
  console.log("[drawing a two]");
  return screen.g.flip();
}).then(()=>{
  console.log("done");
  screen.sleep();
})

This code will only start after sending it to your device and run the save(); command on the left side of web ide.

Double Buffer

This module uses a double buffer, which means you need to call display.g.flip() before any changes take effect.

Rotation

You can rotate the display with display.g.setRotation(1);.

It might be possible to work around this with fiddling around with the gate scanning mechanism (see specification). Right now this seems to be the easiest solution.

Fast refresh rate.

When you enable display.setFastRefresh() the display will only change the changed pixels. Instead of going through then entire refresh cycle. This will increase the displays refresh rate, but might cause burn into the display. So its recommended to do a setFullRefresh to fully reset the display pixels. But if you do this. You'll have to use this SetFastRefresh to make the display only refresh partially.

Colors

Default background color

The Graphics library is used with a buffer in this module. Per default all pixels in this buffer have their color set to 0. For the SSD1606 this means black. To adjust the buffer default values, a clear(color) function is provided, use as:

Color black and white displays

Color B/W Values for using with clear() Values for using with setColor()
white decimal 255, or hexadecimal 0xFF decimal 1 or hexadecimal 0x01
black decimal 0, or hexadecimal 0x00 decimal 0 or hexadecimal 0x00

Color black and white and color (Red or Yellow) displays

Color Red/Yellow Values for using with clear() Values for using with setColor()
red decimal 255, or hexadecimal 0xFF decimal 1 or hexadecimal 0x01
white/black decimal 0, or hexadecimal 0x00 decimal 0 or hexadecimal 0x00

Pixel Colors under the hood

The way color is handle is with black and white is with a single buffer, but to have color it requires 2 buffers. One for black and white and one that either enables or disables the given (red/yellow) color in that given pixel. Its structured this way because thats how hardware registers hold the data.

The reverse order of pixels to concrete bits is taken care of by the module with a suitable Graphics configuration.

Graphics.createArrayBuffer(
            displaySizeX,
            displaySizeY,
            bpp,
            {msb: true} // this does the magic for the reverse part
);

The clear() function works with setting a complete byte for 4 pixels at once. All other function set individual pixels.

Pin Configurations

For the module to work you need to provide:

  • resetPin
  • dcPin
  • busyPin
  • csPin
  • a configured SPI without miso pin.

Notes on the optional power pin

If you do not provide a power pin, the on(); and off(); functions do not work.

Notes for the optional bs1 pin

The module can set the SPI wire mode independently for you, just provide the BS1 pin.

Example with provided BS1 pin:

  var display = require('SSD16XX').connect({
    // other configurations
    dcPin      : a Espruino GPIO pin,
    bs1Pin     : a Espruino GPIO pin
  });

Example without provided BS1 pin, D/C pin is still needed:

  var display = require('SSD16XX').connect({
    // other configurations
    dcPin      : a Espruino GPIO pin
  });

Display Configuration

This module needs a concrete display configuration.

If you want to use another display, you can provide its configuration with:

  var display = require('SSD16XX').connect({
    display: {
      bpp               : 1 or 2 or 4,
      displaySizeX      : int,
      displaySizeY      : int,
      lutRegisterData   : new Uint8Array(),
      coloredDisplay    : boolean
    },
    ... other configurations
  });

Developing notes - helpful resources

Reference

/* Power on the display, using the provided powerPin.
 */
SSD16xx.prototype.on = function () { ... }

/* Power off the display, using the provided powerPin.
 */
SSD16xx.prototype.off = function () { ... }

/* Enters deep sleep and needs a hwReset to enable it again
 */
SSD16xx.prototype.sleep = function () { ... }

/* Use resetPin to make a hardware reset.
 * @param {Function} callback - callback function
 */
SSD16xx.prototype.hwReset = function () { ... }

/* Send command to the controller.
 * @param command - the command int
 */
SSD16xx.prototype.sc = function (command) { ... }

/* Send data to the controller.
 * @param data - the data
 */
SSD16xx.prototype.sd = function (data) { ... }

/* Send command and data to the controller.
 * @param command - the command
 * @param data - the data
 */
SSD16xx.prototype.scd = function (command, data) { ... }

/* Does hardware reset and then does a software reset.
 * @param {Function} callback - callback function
 */
SSD16xx.prototype.fullReset = function () { ... }

/* Send a cmd and optional data.  Then waits for the device to be ready
 * @param {Function} callback - callback function
 */
SSD16xx.prototype.waitCmd = function (command, data) { ... }

/* Sends the refresh dispaly command and then waits
 */
SSD16xx.prototype.refreshDisplay = function (command) { ... }

/* Initialize display.
 * If set it uses the provided bs1Pin to configure the SPI mode between to use 4 lines.
 * Initializing sequence:
 * <ol>
 * <li>Exit deep sleep mode</li>
 * <li>Set region of the display to full and increment in positive both in Y and X</li>
 * <li>[optional] LUT init</li>
 * </ol>
 * @param {Object} options - provided options, useBs1Pin and clearScreenColor
 * @param {Function} callback - callback function
 */
SSD16xx.prototype.init = function () { ... }

/* Sets a partial region of the display.
 * @param {Function} x,y w=width and h=height
 */
SSD16xx.prototype.setPartialRegion = function (x, y, w, h) { ... }

/* Sets display to do full refreshes
 */
SSD16xx.prototype.setFullRefresh = function () { ... }

/* SetFastRefresh - is used make the device refresh the display in only the changed pixels.  
 * This will increase the displays refresh rate, but might cause burn into the display.
 * So its recommended to do a (setFullRefresh) to fully reset the display pixels.  But if you do this.
 * You'll have to use this SetFastRefresh to make the display only refresh partiaily.
 */
SSD16xx.prototype.setFastRefresh = function () { ... }

/* flip - Sets up to wrights the full buffer to the display and then waits for a refresh.
 */
SSD16xx.prototype.flip = function () { ... }

/* Clear the buffer based on a specific color. 
 * @param {clearColor} - The color will be in byte size.  So properly duplicate bit colors to a byte.
 */
SSD16xx.prototype.clear = function (clearColor) { ... }

/* Rotates the buffer
 * @param {rotation} - Rotation in 0-3 with each being a 90 degree rotation.
 */
SSD16xx.prototype.setRotation = function (rotation) { ... }

/* Black and white display buffer.  
 * Creates the Graphics object with Graphics.createArrayBuffer(...).
 * Sets the display x size, y size, bits per pixel and msb:true.
 * Provides a clear function to fill in-memory buffer with one color for each pixel.
 */
SSD16xx.prototype.grfxBlackWhite = function () { ... }

/* Red or yellow display buffer for screen that support it.  a
 * Creates the Graphics object with Graphics.createArrayBuffer(...).
 * Sets the display x size, y size, bits per pixel and msb:true.
 * Provides a clear function to fill in-memory buffer with one color for each pixel.
 */
SSD16xx.prototype.grfxColorWhite = function () { ... }

// Export the module.
exports.connect = function (options) { ... }

This page is auto-generated from GitHub. If you see any mistakes or have suggestions, please let us know.