Port of the Adafruit PCD8544 Driver @ https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library for use in MBED Inital version only supports hardware SPI, and has been tested on a Nucleo test board. BSD license

Requires http://developer.mbed.org/users/infotech1/code/Adafruit_GFX_MBED/ to provide drawing capabilities.

Revision:
0:4d2abaa4de64
Child:
1:03227e59446f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Adafruit_PCD8544.cpp	Sun Nov 02 07:10:44 2014 +0000
@@ -0,0 +1,382 @@
+/*********************************************************************
+This is a library for our Monochrome Nokia 5110 LCD Displays
+
+  Pick one up today in the adafruit shop!
+  ------> http://www.adafruit.com/products/338
+
+These displays use SPI to communicate, 4 or 5 pins are required to  
+interface
+
+Adafruit invests time and resources providing this open source code, 
+please support Adafruit and open-source hardware by purchasing 
+products from Adafruit!
+
+Written by Limor Fried/Ladyada  for Adafruit Industries.  
+BSD license, check license.txt for more information
+All text above, and the splash screen below must be included in any redistribution
+
+
+Modified for MBED usage and tested with STM32F411RE on a Nucleo board.
+Hardware SPI only, tested using default arduino pin out D11/D13 for MOSI/SCLK, Support provided for different pin layouts
+by James Kidd 2014
+*********************************************************************/
+
+#ifndef _BV
+#define _BV( bit ) ( 1<<(bit) )
+#endif
+//#include <Wire.h>
+#include <stdint.h>
+//#include <Adafruit_GFX.h>
+#include "Adafruit_GFX.h"
+#include "Adafruit_PCD8544.h"
+
+// the memory buffer for the LCD
+uint8_t pcd8544_buffer[LCDWIDTH * LCDHEIGHT / 8] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 0xFC, 0xE0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
+0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0xC0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x7F,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x87, 0x8F, 0x9F, 0x9F, 0xFF, 0xFF, 0xFF,
+0xC1, 0xC0, 0xE0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE,
+0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x80, 0xC0, 0xE0, 0xF1, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x87,
+0xE7, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x3F, 0xF9, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFD, 0xFF,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+0x7E, 0x3F, 0x3F, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0xE0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF,
+0xFF, 0xFC, 0xF0, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01,
+0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x7F, 0x7F,
+0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x1F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+};
+
+
+// reduces how much is refreshed, which speeds it up!
+// originally derived from Steve Evans/JCW's mod but cleaned up and
+// optimized
+//#define enablePartialUpdate
+
+#ifdef enablePartialUpdate
+static uint8_t xUpdateMin, xUpdateMax, yUpdateMin, yUpdateMax;
+#endif
+
+
+
+static void updateBoundingBox(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) {
+#ifdef enablePartialUpdate
+  if (xmin < xUpdateMin) xUpdateMin = xmin;
+  if (xmax > xUpdateMax) xUpdateMax = xmax;
+  if (ymin < yUpdateMin) yUpdateMin = ymin;
+  if (ymax > yUpdateMax) yUpdateMax = ymax;
+#endif
+}
+
+
+/*
+ * 3,4,5 by default with D13(sclk)/D11(mosi) used by default for SPI
+ */
+Adafruit_PCD8544::Adafruit_PCD8544(PinName RST, PinName CS,PinName DC,PinName MOSI,PinName SCLK ): Adafruit_GFX(LCDWIDTH,LCDHEIGHT) {
+      _din = -1;
+      _sclk = -1;
+      _dc = 1;
+      _rst = 1;
+      _cs = 1;
+    myPins.rst  = RST;
+    myPins.sce  = CS;
+    myPins.dc   = DC;
+    myPins.mosi = MOSI;
+    myPins.miso = NC;
+    myPins.sclk = SCLK;
+}
+/*
+ * 3,4,5 by default with D13(sclk)/D11(mosi) used by default for SPI
+ */
+Adafruit_PCD8544::Adafruit_PCD8544(PinName RST, PinName CS,PinName DC ): Adafruit_GFX(LCDWIDTH,LCDHEIGHT) {
+      _din = -1;
+      _sclk = -1;
+      _dc = 1;
+      _rst = 1;
+      _cs = 1;
+    myPins.rst  = RST;
+    myPins.sce  = CS;
+    myPins.dc   = DC;
+    myPins.mosi = D11;
+    myPins.miso = NC;
+    myPins.sclk = D13;
+}
+
+
+// the most basic function, set a single pixel
+void Adafruit_PCD8544::drawPixel(int16_t x, int16_t y, uint16_t color) {
+  if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height))
+    return;
+
+  int16_t t;
+  switch(rotation){
+    case 1:
+      t = x;
+      x = y;
+      y =  LCDHEIGHT - 1 - t;
+      break;
+    case 2:
+      x = LCDWIDTH - 1 - x;
+      y = LCDHEIGHT - 1 - y;
+      break;
+    case 3:
+      t = x;
+      x = LCDWIDTH - 1 - y;
+      y = t;
+      break;
+  }
+
+  if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT))
+    return;
+
+  // x is which column
+  if (color) 
+    pcd8544_buffer[x+ (y/8)*LCDWIDTH] |= _BV(y%8);  
+  else
+    pcd8544_buffer[x+ (y/8)*LCDWIDTH] &= ~_BV(y%8); 
+
+  updateBoundingBox(x,y,x,y);
+}
+
+
+// the most basic function, get a single pixel
+uint8_t Adafruit_PCD8544::getPixel(int8_t x, int8_t y) {
+  if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT))
+    return 0;
+
+  return (pcd8544_buffer[x+ (y/8)*LCDWIDTH] >> (y%8)) & 0x1;  
+}
+
+
+void Adafruit_PCD8544::begin(uint8_t contrast, uint8_t bias) {
+
+
+  if (isHardwareSPI()) {
+    // Setup hardware SPI.
+        LcdSPI = new SPI(D11,NC,D13);
+        LcdSPI->format(LCD_SPI_BITS, LCD_SPI_MODE);
+        LcdSPI->frequency(LCD_FREQ);
+    //SPI.begin();
+    //SPI.setClockDivider(PCD8544_SPI_CLOCK_DIV);
+    //SPI.setDataMode(SPI_MODE0);
+    //SPI.setBitOrder(MSBFIRST);
+  }
+  else {
+    // Setup software SPI.
+
+    // Set software SPI specific pin outputs.
+   /* pinMode(_din, OUTPUT);
+    pinMode(_sclk, OUTPUT);
+
+    // Set software SPI ports and masks.
+    clkport     = portOutputRegister(digitalPinToPort(_sclk));
+    clkpinmask  = digitalPinToBitMask(_sclk);
+    mosiport    = portOutputRegister(digitalPinToPort(_din));
+    mosipinmask = digitalPinToBitMask(_din);*/
+  }
+  Pins = new DigitalOut*[3];
+   Pins[PIN_RST]   = new DigitalOut(myPins.rst);
+     Pins[PIN_SCE]   = new DigitalOut(myPins.sce);
+     Pins[PIN_DC]    = new DigitalOut(myPins.dc);
+
+
+  // Set common pin outputs.
+  /*pinMode(_dc, OUTPUT);
+  if (_rst > 0)
+      pinMode(_rst, OUTPUT);
+  if (_cs > 0)
+      pinMode(_cs, OUTPUT);*/
+
+  // toggle RST low to reset
+  if (_rst > 0) {
+      Pins[PIN_RST]->write(0);
+      wait_ms(500);
+      Pins[PIN_RST]->write(1);
+    //digitalWrite(_rst, LOW);
+    //_delay_ms(500);
+    //digitalWrite(_rst, HIGH);
+  }
+
+  // get into the EXTENDED mode!
+  command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION );
+
+  // LCD bias select (4 is optimal?)
+  command(PCD8544_SETBIAS | bias);
+
+  // set VOP
+  if (contrast > 0x7f)
+    contrast = 0x7f;
+
+  command( PCD8544_SETVOP | contrast); // Experimentally determined
+
+
+  // normal mode
+  command(PCD8544_FUNCTIONSET);
+
+  // Set display to Normal
+  command(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL);
+
+  // initial display line
+  // set page address
+  // set column address
+  // write display data
+
+  // set up a bounding box for screen updates
+
+  updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
+  // Push out pcd8544_buffer to the Display (will show the AFI logo)
+  display();
+}
+
+
+inline void Adafruit_PCD8544::spiWrite(uint8_t d) {
+  if (isHardwareSPI()) {
+    // Hardware SPI write.
+      LcdSPI->write(d);
+    //SPI.transfer(d);
+  }
+  else {
+    // Software SPI write with bit banging.
+    for(uint8_t bit = 0x80; bit; bit >>= 1) {
+      *clkport &= ~clkpinmask;
+      if(d & bit) *mosiport |=  mosipinmask;
+      else        *mosiport &= ~mosipinmask;
+      *clkport |=  clkpinmask;
+    }
+  }
+}
+
+bool Adafruit_PCD8544::isHardwareSPI() {
+  return (_din == -1 && _sclk == -1);
+}
+
+void Adafruit_PCD8544::command(uint8_t c) {
+    Pins[PIN_DC]->write(0);
+  //digitalWrite(_dc, LOW);
+  if (_cs > 0)
+      Pins[PIN_SCE]->write(0);
+    //digitalWrite(_cs, LOW);
+  spiWrite(c);
+  if (_cs > 0)
+      Pins[PIN_SCE]->write(1);
+    //digitalWrite(_cs, HIGH);
+}
+
+void Adafruit_PCD8544::data(uint8_t c) {
+    Pins[PIN_DC]->write(1);
+  //digitalWrite(_dc, HIGH);
+  if (_cs > 0)
+      Pins[PIN_SCE]->write(0);//digitalWrite(_cs, LOW);
+  spiWrite(c);
+  if (_cs > 0)
+      Pins[PIN_SCE]->write(1);//digitalWrite(_cs, HIGH);
+}
+
+void Adafruit_PCD8544::setContrast(uint8_t val) {
+  if (val > 0x7f) {
+    val = 0x7f;
+  }
+  command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION );
+  command( PCD8544_SETVOP | val); 
+  command(PCD8544_FUNCTIONSET);
+  
+ }
+
+
+
+void Adafruit_PCD8544::display(void) {
+  uint8_t col, maxcol, p;
+  
+  for(p = 0; p < 6; p++) {
+#ifdef enablePartialUpdate
+    // check if this page is part of update
+    if ( yUpdateMin >= ((p+1)*8) ) {
+      continue;   // nope, skip it!
+    }
+    if (yUpdateMax < p*8) {
+      break;
+    }
+#endif
+
+    command(PCD8544_SETYADDR | p);
+
+
+#ifdef enablePartialUpdate
+    col = xUpdateMin;
+    maxcol = xUpdateMax;
+#else
+    // start at the beginning of the row
+    col = 0;
+    maxcol = LCDWIDTH-1;
+#endif
+
+    command(PCD8544_SETXADDR | col);
+    Pins[PIN_DC]->write(1);
+    //digitalWrite(_dc, HIGH);
+    if (_cs > 0)
+        Pins[PIN_SCE]->write(0);//digitalWrite(_cs, LOW);
+    for(; col <= maxcol; col++) {
+      spiWrite(pcd8544_buffer[(LCDWIDTH*p)+col]);
+    }
+    if (_cs > 0)
+        Pins[PIN_SCE]->write(1);//digitalWrite(_cs, HIGH);
+
+  }
+
+  command(PCD8544_SETYADDR );  // no idea why this is necessary but it is to finish the last byte?
+#ifdef enablePartialUpdate
+  xUpdateMin = LCDWIDTH - 1;
+  xUpdateMax = 0;
+  yUpdateMin = LCDHEIGHT-1;
+  yUpdateMax = 0;
+#endif
+
+}
+
+// clear everything
+void Adafruit_PCD8544::clearDisplay(void) {
+  memset(pcd8544_buffer, 0, LCDWIDTH*LCDHEIGHT/8);
+  updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
+  cursor_y = cursor_x = 0;
+}
+
+/*
+// this doesnt touch the buffer, just clears the display RAM - might be handy
+void Adafruit_PCD8544::clearDisplay(void) {
+  
+  uint8_t p, c;
+  
+  for(p = 0; p < 8; p++) {
+
+    st7565_command(CMD_SET_PAGE | p);
+    for(c = 0; c < 129; c++) {
+      //uart_putw_dec(c);
+      //uart_putchar(' ');
+      st7565_command(CMD_SET_COLUMN_LOWER | (c & 0xf));
+      st7565_command(CMD_SET_COLUMN_UPPER | ((c >> 4) & 0xf));
+      st7565_data(0x0);
+    }     
+    }
+
+}
+
+*/