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.
Diff: Adafruit_PCD8544.cpp
- 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); + } + } + +} + +*/