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.
Adafruit_PCD8544.cpp
- Committer:
- infotech1
- Date:
- 2014-11-02
- Revision:
- 1:03227e59446f
- Parent:
- 0:4d2abaa4de64
- Child:
- 2:c70a41c0d9d8
File content as of revision 1:03227e59446f:
/********************************************************************* 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); } 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); } // 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); } } } */