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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Adafruit_PCD8544.cpp Source File

Adafruit_PCD8544.cpp

00001 /*********************************************************************
00002 This is a library for our Monochrome Nokia 5110 LCD Displays
00003 
00004   Pick one up today in the adafruit shop!
00005   ------> http://www.adafruit.com/products/338
00006 
00007 These displays use SPI to communicate, 4 or 5 pins are required to  
00008 interface
00009 
00010 Adafruit invests time and resources providing this open source code, 
00011 please support Adafruit and open-source hardware by purchasing 
00012 products from Adafruit!
00013 
00014 Written by Limor Fried/Ladyada  for Adafruit Industries.  
00015 BSD license, check license.txt for more information
00016 All text above, and the splash screen below must be included in any redistribution
00017 
00018 
00019 Modified for MBED usage and tested with STM32F411RE on a Nucleo board.
00020 Hardware SPI only, tested using default arduino pin out D11/D13 for MOSI/SCLK, Support provided for different pin layouts
00021 by James Kidd 2014
00022 *********************************************************************/
00023 
00024 #ifndef _BV
00025 #define _BV( bit ) ( 1<<(bit) )
00026 #endif
00027 //#include <Wire.h>
00028 #include <stdint.h>
00029 #include <Adafruit_GFX.h>
00030 //#include "Adafruit_GFX.h"
00031 #include "Adafruit_PCD8544.h"
00032 
00033 // the memory buffer for the LCD
00034 uint8_t pcd8544_buffer[LCDWIDTH * LCDHEIGHT / 8] = {
00035 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00037 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 0xFC, 0xE0,
00038 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00039 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00041 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
00042 0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0xC0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x7F,
00043 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF,
00047 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x87, 0x8F, 0x9F, 0x9F, 0xFF, 0xFF, 0xFF,
00048 0xC1, 0xC0, 0xE0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE,
00049 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00050 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00052 0x00, 0x80, 0xC0, 0xE0, 0xF1, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x87,
00053 0xE7, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x3F, 0xF9, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFD, 0xFF,
00054 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00,
00055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00057 0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
00058 0x7E, 0x3F, 0x3F, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0xE0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF,
00059 0xFF, 0xFC, 0xF0, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
00060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00061 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00062 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01,
00063 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x7F, 0x7F,
00064 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x1F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00065 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00066 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
00067 };
00068 
00069 
00070 // reduces how much is refreshed, which speeds it up!
00071 // originally derived from Steve Evans/JCW's mod but cleaned up and
00072 // optimized
00073 //#define enablePartialUpdate
00074 
00075 #ifdef enablePartialUpdate
00076 static uint8_t xUpdateMin, xUpdateMax, yUpdateMin, yUpdateMax;
00077 #endif
00078 
00079 
00080 
00081 static void updateBoundingBox(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) {
00082 #ifdef enablePartialUpdate
00083   if (xmin < xUpdateMin) xUpdateMin = xmin;
00084   if (xmax > xUpdateMax) xUpdateMax = xmax;
00085   if (ymin < yUpdateMin) yUpdateMin = ymin;
00086   if (ymax > yUpdateMax) yUpdateMax = ymax;
00087 #endif
00088 }
00089 
00090 
00091 /*
00092  * 3,4,5 by default with D13(sclk)/D11(mosi) used by default for SPI
00093  */
00094 Adafruit_PCD8544::Adafruit_PCD8544(PinName RST, PinName CS,PinName DC,PinName MOSI,PinName SCLK ): Adafruit_GFX(LCDWIDTH,LCDHEIGHT) {
00095       _din = -1;
00096       _sclk = -1;
00097       _dc = 1;
00098       _rst = 1;
00099       _cs = 1;
00100     myPins.rst  = RST;
00101     myPins.sce  = CS;
00102     myPins.dc   = DC;
00103     myPins.mosi = MOSI;
00104     myPins.miso = NC;
00105     myPins.sclk = SCLK;
00106 }
00107 /*
00108  * 3,4,5 by default with D13(sclk)/D11(mosi) used by default for SPI
00109  */
00110 Adafruit_PCD8544::Adafruit_PCD8544(PinName RST, PinName CS,PinName DC ): Adafruit_GFX(LCDWIDTH,LCDHEIGHT) {
00111       _din = -1;
00112       _sclk = -1;
00113       _dc = 1;
00114       _rst = 1;
00115       _cs = 1;
00116     myPins.rst  = RST;
00117     myPins.sce  = CS;
00118     myPins.dc   = DC;
00119     myPins.mosi = D11;
00120     myPins.miso = NC;
00121     myPins.sclk = D13;
00122 }
00123 
00124 
00125 // the most basic function, set a single pixel
00126 void Adafruit_PCD8544::drawPixel(int16_t x, int16_t y, uint16_t color) {
00127   if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height))
00128     return;
00129 
00130   int16_t t;
00131   switch(rotation){
00132     case 1:
00133       t = x;
00134       x = y;
00135       y =  LCDHEIGHT - 1 - t;
00136       break;
00137     case 2:
00138       x = LCDWIDTH - 1 - x;
00139       y = LCDHEIGHT - 1 - y;
00140       break;
00141     case 3:
00142       t = x;
00143       x = LCDWIDTH - 1 - y;
00144       y = t;
00145       break;
00146   }
00147 
00148   if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT))
00149     return;
00150 
00151   // x is which column
00152   if (color) 
00153     pcd8544_buffer[x+ (y/8)*LCDWIDTH] |= _BV(y%8);  
00154   else
00155     pcd8544_buffer[x+ (y/8)*LCDWIDTH] &= ~_BV(y%8); 
00156 
00157   updateBoundingBox(x,y,x,y);
00158 }
00159 
00160 
00161 // the most basic function, get a single pixel
00162 uint8_t Adafruit_PCD8544::getPixel(int8_t x, int8_t y) {
00163   if ((x < 0) || (x >= LCDWIDTH) || (y < 0) || (y >= LCDHEIGHT))
00164     return 0;
00165 
00166   return (pcd8544_buffer[x+ (y/8)*LCDWIDTH] >> (y%8)) & 0x1;  
00167 }
00168 
00169 
00170 void Adafruit_PCD8544::begin(uint8_t contrast, uint8_t bias) {
00171 
00172 
00173   if (isHardwareSPI()) {
00174     // Setup hardware SPI.
00175         LcdSPI = new SPI(myPins.mosi,NC,myPins.sclk);
00176         LcdSPI->format(LCD_SPI_BITS, LCD_SPI_MODE);
00177         LcdSPI->frequency(LCD_FREQ);
00178   }
00179   else {
00180     // Setup software SPI.
00181 
00182     // Set software SPI specific pin outputs.
00183    /* pinMode(_din, OUTPUT);
00184     pinMode(_sclk, OUTPUT);
00185 
00186     // Set software SPI ports and masks.
00187     clkport     = portOutputRegister(digitalPinToPort(_sclk));
00188     clkpinmask  = digitalPinToBitMask(_sclk);
00189     mosiport    = portOutputRegister(digitalPinToPort(_din));
00190     mosipinmask = digitalPinToBitMask(_din);*/
00191   }
00192   Pins = new DigitalOut*[3];
00193    Pins[PIN_RST]   = new DigitalOut(myPins.rst);
00194      Pins[PIN_SCE]   = new DigitalOut(myPins.sce);
00195      Pins[PIN_DC]    = new DigitalOut(myPins.dc);
00196 
00197 
00198   // Set common pin outputs.
00199   /*pinMode(_dc, OUTPUT);
00200   if (_rst > 0)
00201       pinMode(_rst, OUTPUT);
00202   if (_cs > 0)
00203       pinMode(_cs, OUTPUT);*/
00204 
00205   // toggle RST low to reset
00206   if (_rst > 0) {
00207       Pins[PIN_RST]->write(0);
00208       wait_ms(500);
00209       Pins[PIN_RST]->write(1);
00210   }
00211 
00212   // get into the EXTENDED mode!
00213   command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION );
00214 
00215   // LCD bias select (4 is optimal?)
00216   command(PCD8544_SETBIAS | bias);
00217 
00218   // set VOP
00219   if (contrast > 0x7f)
00220     contrast = 0x7f;
00221 
00222   command( PCD8544_SETVOP | contrast); // Experimentally determined
00223 
00224 
00225   // normal mode
00226   command(PCD8544_FUNCTIONSET);
00227 
00228   // Set display to Normal
00229   command(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL);
00230 
00231   // initial display line
00232   // set page address
00233   // set column address
00234   // write display data
00235 
00236   // set up a bounding box for screen updates
00237 
00238   updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
00239   // Push out pcd8544_buffer to the Display (will show the AFI logo)
00240   display();
00241 }
00242 
00243 
00244 inline void Adafruit_PCD8544::spiWrite(uint8_t d) {
00245   if (isHardwareSPI()) {
00246     // Hardware SPI write.
00247       LcdSPI->write(d);
00248     //SPI.transfer(d);
00249   }
00250   else {
00251     // Software SPI write with bit banging.
00252     for(uint8_t bit = 0x80; bit; bit >>= 1) {
00253       *clkport &= ~clkpinmask;
00254       if(d & bit) *mosiport |=  mosipinmask;
00255       else        *mosiport &= ~mosipinmask;
00256       *clkport |=  clkpinmask;
00257     }
00258   }
00259 }
00260 
00261 bool Adafruit_PCD8544::isHardwareSPI() {
00262   return (_din == -1 && _sclk == -1);
00263 }
00264 
00265 void Adafruit_PCD8544::command(uint8_t c) {
00266     Pins[PIN_DC]->write(0);
00267   //digitalWrite(_dc, LOW);
00268   if (_cs > 0)
00269       Pins[PIN_SCE]->write(0);
00270     //digitalWrite(_cs, LOW);
00271   spiWrite(c);
00272   if (_cs > 0)
00273       Pins[PIN_SCE]->write(1);
00274     //digitalWrite(_cs, HIGH);
00275 }
00276 
00277 void Adafruit_PCD8544::data(uint8_t c) {
00278     Pins[PIN_DC]->write(1);
00279   //digitalWrite(_dc, HIGH);
00280   if (_cs > 0)
00281       Pins[PIN_SCE]->write(0);//digitalWrite(_cs, LOW);
00282   spiWrite(c);
00283   if (_cs > 0)
00284       Pins[PIN_SCE]->write(1);//digitalWrite(_cs, HIGH);
00285 }
00286 
00287 void Adafruit_PCD8544::setContrast(uint8_t val) {
00288   if (val > 0x7f) {
00289     val = 0x7f;
00290   }
00291   command(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION );
00292   command( PCD8544_SETVOP | val); 
00293   command(PCD8544_FUNCTIONSET);
00294   
00295  }
00296 
00297 
00298 
00299 void Adafruit_PCD8544::display(void) {
00300   uint8_t col, maxcol, p;
00301   
00302   for(p = 0; p < 6; p++) {
00303 #ifdef enablePartialUpdate
00304     // check if this page is part of update
00305     if ( yUpdateMin >= ((p+1)*8) ) {
00306       continue;   // nope, skip it!
00307     }
00308     if (yUpdateMax < p*8) {
00309       break;
00310     }
00311 #endif
00312 
00313     command(PCD8544_SETYADDR | p);
00314 
00315 
00316 #ifdef enablePartialUpdate
00317     col = xUpdateMin;
00318     maxcol = xUpdateMax;
00319 #else
00320     // start at the beginning of the row
00321     col = 0;
00322     maxcol = LCDWIDTH-1;
00323 #endif
00324 
00325     command(PCD8544_SETXADDR | col);
00326     Pins[PIN_DC]->write(1);
00327     //digitalWrite(_dc, HIGH);
00328     if (_cs > 0)
00329         Pins[PIN_SCE]->write(0);//digitalWrite(_cs, LOW);
00330     for(; col <= maxcol; col++) {
00331       spiWrite(pcd8544_buffer[(LCDWIDTH*p)+col]);
00332     }
00333     if (_cs > 0)
00334         Pins[PIN_SCE]->write(1);//digitalWrite(_cs, HIGH);
00335 
00336   }
00337 
00338   command(PCD8544_SETYADDR );  // no idea why this is necessary but it is to finish the last byte?
00339 #ifdef enablePartialUpdate
00340   xUpdateMin = LCDWIDTH - 1;
00341   xUpdateMax = 0;
00342   yUpdateMin = LCDHEIGHT-1;
00343   yUpdateMax = 0;
00344 #endif
00345 
00346 }
00347 
00348 // clear everything
00349 void Adafruit_PCD8544::clearDisplay(void) {
00350   memset(pcd8544_buffer, 0, LCDWIDTH*LCDHEIGHT/8);
00351   updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
00352   cursor_y = cursor_x = 0;
00353 }
00354 
00355 /*
00356 // this doesnt touch the buffer, just clears the display RAM - might be handy
00357 void Adafruit_PCD8544::clearDisplay(void) {
00358   
00359   uint8_t p, c;
00360   
00361   for(p = 0; p < 8; p++) {
00362 
00363     st7565_command(CMD_SET_PAGE | p);
00364     for(c = 0; c < 129; c++) {
00365       //uart_putw_dec(c);
00366       //uart_putchar(' ');
00367       st7565_command(CMD_SET_COLUMN_LOWER | (c & 0xf));
00368       st7565_command(CMD_SET_COLUMN_UPPER | ((c >> 4) & 0xf));
00369       st7565_data(0x0);
00370     }     
00371     }
00372 
00373 }
00374 
00375 */