modtronix H / modtronix_im4OLED

Fork of Adafruit_GFX by Neal Horman

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mx_ssd1306.h Source File

mx_ssd1306.h

00001 /*********************************************************************
00002 This is a library for our Monochrome OLEDs based on SSD1306 drivers
00003 
00004   Pick one up today in the adafruit shop!
00005   ------> http://www.adafruit.com/category/63_98
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 must be included in any redistribution
00017 *********************************************************************/
00018 
00019 /*
00020  *  Modified by Neal Horman 7/14/2012 for use in mbed
00021  */
00022 
00023 #ifndef _ADAFRUIT_SSD1306_H_
00024 #define _ADAFRUIT_SSD1306_H_
00025 #include "im4oled_default_config.h"
00026 #include "mx_gfx.h"
00027 
00028 #if (OLED_USE_VECTOR==1)
00029 #include <vector>
00030 #endif
00031 #include <algorithm>
00032 
00033 #define OLED_HAS_RESET      0
00034 
00035 // A DigitalOut sub-class that provides a constructed default state
00036 class DigitalOut2 : public DigitalOut
00037 {
00038 public:
00039     DigitalOut2(PinName pin, bool active = false) : DigitalOut(pin) { write(active); };
00040     DigitalOut2& operator= (int value) { write(value); return *this; };
00041     DigitalOut2& operator= (DigitalOut2& rhs) { write(rhs.read()); return *this; };
00042     operator int() { return read(); };
00043 };
00044 
00045 #define SSD1306_EXTERNALVCC 0x1
00046 #define SSD1306_SWITCHCAPVCC 0x2
00047 
00048 /** The pure base class for the SSD1306 display driver.
00049  *
00050  * You should derive from this for a new transport interface type,
00051  * such as the SPI and I2C drivers.
00052  */
00053 class MxSSD1306 : public MxGfx
00054 {
00055 public:
00056 #if (OLED_HAS_RESET==1)
00057     MxSSD1306(PinName RST, uint8_t rawHeight = 32, uint8_t rawWidth = 128)
00058         : MxGfx(rawWidth,rawHeight)
00059         , colBlock(0)
00060         , rowBlock(0)
00061         , rst(RST,false)
00062 #else
00063     MxSSD1306(uint8_t rawHeight = 32, uint8_t rawWidth = 128)
00064         : MxGfx(rawWidth,rawHeight)
00065         , colBlock(0)
00066         , rowBlock(0)
00067 #endif
00068     {
00069         //Initialize as all dirty
00070         memset(&dirty[0], 0xff, sizeof(dirty));
00071 
00072 #if (OLED_USE_VECTOR==0)
00073         memset(&buffer[0], 0, sizeof(buffer));
00074 #else
00075         buffer.resize(rawHeight * rawWidth / 8);
00076 #endif
00077     };
00078 
00079     /** Initialize
00080      * @return 0 if success, else I2C or SPI error code
00081      */
00082     uint8_t begin(uint8_t switchvcc = SSD1306_SWITCHCAPVCC);
00083     
00084     // These must be implemented in the derived transport driver
00085     virtual uint8_t command(uint8_t c) = 0;
00086     virtual uint8_t data(uint8_t c) = 0;
00087     virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
00088 
00089     /**
00090      * Clear the display buffer. Requires a display() call at some point afterwards.
00091      * NOTE that this function will make the WHOLE display as dirty! The next display() call will update the
00092      * entire display! This can be prevented by just clearing the required part of the display using fillRect()!
00093      */
00094     void clearDisplay(void);
00095 
00096     /** Set display contrast
00097      * @return 0 if success, else I2C or SPI error code
00098      */
00099     virtual uint8_t setContrast(uint8_t contrast);
00100 
00101     /** Turn display on or off
00102      * @return 0 if success, else I2C or SPI error code
00103      */
00104     virtual uint8_t displayOn(bool on);
00105 
00106     /** Invert Display
00107      * @return 0 if success, else I2C or SPI error code
00108      */
00109     virtual uint8_t invertDisplay(bool i);
00110 
00111     /** Cause the display to be updated with the buffer content.
00112      * @return 0 if success, else I2C or SPI error code
00113      */
00114     uint8_t display();
00115 
00116     // Fill the buffer with the AdaFruit splash screen.
00117     virtual void splash();
00118     
00119 protected:
00120     /** Write contents of display buffer to OLED display.
00121      * @return 0 if success, else I2C or SPI error code
00122      */
00123     virtual uint8_t sendDisplayBuffer() = 0;
00124 
00125     /** Write a block of display data. The 128x64 pixels are divided into:
00126      * - 8 RowBlocks, each with 8 rows. This is 1 page of the SSD1206
00127      * - 8 ColBlocks, each with 16 columns.
00128      *
00129      * @param rowBlock Value 0-7 indicating what block of 8 rows to write. 0=0-7,
00130      *        1=8-15, ...., 7=56-63
00131      * @param colBlock Value 0-7 indicating what block of 16 columns to write. 0=0-15,
00132      *        1=16-31, ...., 7=112-127
00133      * @return 0 if success, else I2C or SPI error code
00134      */
00135     virtual uint8_t sendDisplayBuffer(uint8_t rowBlock, uint8_t colBlock) = 0;
00136 
00137 public:
00138     // Set whole display as being dirty
00139     virtual void setAllDirty();
00140 
00141     // Protected Data
00142 protected:
00143     uint8_t colBlock, rowBlock;
00144 
00145 #if (OLED_WIDTH <= 128 )
00146     uint8_t dirty[OLED_HEIGHT/8];   //Each bit marks block of "8 Rows x 16 Columns". So, a single byte is enough for up to 128col. One byte for each 8 rows.
00147 #elif (OLED_WIDTH <= 256 )
00148     uint16_t dirty[OLED_HEIGHT/8];  //Each bit marks block of "8 Rows x 16 Columns". One UINT16 = 16x16 = 256 columns.
00149 #endif
00150 
00151 #if (OLED_HAS_RESET==1)
00152     DigitalOut2 rst;
00153 #endif
00154 
00155     // the memory buffer for the LCD
00156 #if (OLED_USE_VECTOR==1)
00157     std::vector<uint8_t> buffer;
00158 #else
00159     uint8_t buffer[OLED_HEIGHT * OLED_WIDTH / 8];
00160 #endif
00161 };
00162 
00163 
00164 /** This is the SPI SSD1306 display driver transport class
00165  *
00166  */
00167 class MxSSD1306_SPI : public MxSSD1306
00168 {
00169 public:
00170     /** Create a SSD1306 SPI transport display driver instance with the specified DC, RST, and CS pins, as well as the display dimentions
00171      *
00172      * Required parameters
00173      * @param spi - a reference to an initialized SPI object
00174      * @param DC (Data/Command) pin name
00175      * @param RST (Reset) pin name
00176      * @param CS (Chip Select) pin name
00177      *
00178      * Optional parameters
00179      * @param rawHeight - the vertical number of pixels for the display, defaults to 32
00180      * @param rawWidth - the horizonal number of pixels for the display, defaults to 128
00181      */
00182 #if (OLED_HAS_RESET==1)
00183     MxSSD1306_SPI(SPI &spi, PinName DC, PinName RST, PinName CS, uint8_t rawHieght = 32, uint8_t rawWidth = 128)
00184         : MxSSD1306(RST, rawHieght, rawWidth)
00185 #else
00186     MxSSD1306_SPI(SPI &spi, PinName DC, PinName CS, uint8_t rawHieght = 32, uint8_t rawWidth = 128)
00187         : MxSSD1306(rawHieght, rawWidth)
00188 #endif
00189         , cs(CS,true)
00190         , dc(DC,false)
00191         , mspi(spi)
00192         {
00193             begin();
00194             splash();
00195             display();
00196         };
00197 
00198     /** Send command via SPI
00199      * @param c The command to send
00200      * @return 0 if success, else SPI error
00201      */
00202     virtual uint8_t command(uint8_t c)
00203     {
00204         cs = 1;
00205         dc = 0;
00206         cs = 0;
00207         mspi.write(c);
00208         cs = 1;
00209         return 0;
00210     };
00211 
00212     /** Send Data via SPI
00213      * @param c The data to send
00214      * @return 0 if success, else SPI error
00215      */
00216     virtual uint8_t data(uint8_t c)
00217     {
00218         cs = 1;
00219         dc = 1;
00220         cs = 0;
00221         mspi.write(c);
00222         cs = 1;
00223         return 0;
00224     };
00225 
00226 protected:
00227     virtual uint8_t sendDisplayBuffer()
00228     {
00229         uint8_t retVal;
00230         cs = 1;
00231         dc = 1;
00232         cs = 0;
00233 
00234 #if (OLED_USE_VECTOR==0)
00235         for(uint16_t i=0, q=sizeof(buffer); i<q; i++) {
00236 #else
00237         for(uint16_t i=0, q=buffer.size(); i<q; i++) {
00238 #endif
00239             if((retVal=mspi.write(buffer[i])) != 0) {
00240                 cs = 1;
00241                 return retVal;
00242             }
00243         }
00244 
00245         if(height() == 32)
00246         {
00247 #if (OLED_USE_VECTOR==0)
00248             for(uint16_t i=0, q=sizeof(buffer); i<q; i++) {
00249 #else
00250             for(uint16_t i=0, q=buffer.size(); i<q; i++) {
00251 #endif
00252                 if((retVal=mspi.write(0)) != 0) {
00253                     cs = 1;
00254                     return retVal;
00255                 }
00256             }
00257         }
00258 
00259         cs = 1;
00260         return 0;
00261     };
00262 
00263     DigitalOut2 cs, dc;
00264     SPI &mspi;
00265 };
00266 
00267 /** This is the I2C SSD1306 display driver transport class
00268  *
00269  */
00270 class MxSSD1306_I2C : public MxSSD1306
00271 {
00272 public:
00273     #define SSD_I2C_ADDRESS     0x78
00274     /** Create a SSD1306 I2C transport display driver instance with the specified RST pin name, the I2C address, as well as the display dimensions
00275      *
00276      * Required parameters
00277      * @param i2c - A reference to an initialized I2C object
00278      * @param RST - The Reset pin name
00279      *
00280      * Optional parameters
00281      * @param i2cAddress - The i2c address of the display
00282      * @param rawHeight - The vertical number of pixels for the display, defaults to 32
00283      * @param rawWidth - The horizonal number of pixels for the display, defaults to 128
00284      */
00285 #if (OLED_HAS_RESET==1)
00286     Adafruit_SSD1306_I2c(I2C &i2c, PinName RST, uint8_t i2cAddress = SSD_I2C_ADDRESS, uint8_t rawHeight = 32, uint8_t rawWidth = 128)
00287         : MxSSD1306(RST, rawHeight, rawWidth)
00288 #else
00289     MxSSD1306_I2C(I2C &i2c, uint8_t i2cAddress = SSD_I2C_ADDRESS, uint8_t rawHeight = 32, uint8_t rawWidth = 128)
00290         : MxSSD1306(rawHeight, rawWidth)
00291 #endif
00292         , mi2c(i2c)
00293         , mi2cAddress(i2cAddress)
00294     {
00295         begin();
00296         splash();
00297         display();
00298     };
00299 
00300 
00301     /**Constructor without doing any initialization requiring I2C object. Use this constructor if the I2C object must still be
00302      * initialized, or used after startup delay.
00303      * !!!!! IMPORTANT !!!!!
00304      * This constructor must be followed by calling the init() function BEFORE using any other functions!
00305      *
00306      * Required parameters
00307      * @param i2cAddress - The i2c address of the display
00308      * @param i2c - A reference to an initialized I2C object
00309      *
00310      * Optional parameters
00311      * @param rawHeight - The vertical number of pixels for the display, defaults to 32
00312      * @param rawWidth - The horizonal number of pixels for the display, defaults to 128
00313      */
00314     MxSSD1306_I2C(uint8_t i2cAddress, I2C &i2c, uint8_t rawHeight = 32, uint8_t rawWidth = 128)
00315         : MxSSD1306(rawHeight, rawWidth), mi2c(i2c), mi2cAddress(i2cAddress)
00316     {
00317     };
00318 
00319 
00320     /**
00321      * Initialize with given I2C bus.
00322      * !!!!! IMPORTANT !!!!!
00323      * This function must be called after the Adafruit_SSD1306_I2c(rawHeight, rawWidth) constructor!
00324      *
00325      * @param i2c I2C Bus to use
00326      * @return 0 if OK, else error code
00327      */
00328     uint8_t init()
00329     {
00330         uint8_t retVal;
00331         if((retVal=begin()) != 0) {
00332             return retVal;  //Return error code
00333         }
00334 
00335         //splash();
00336         if((retVal=display()) != 0) {
00337             return retVal;  //Return error code
00338         }
00339         return 0;
00340     }
00341 
00342     /** Send command via I2C
00343      * @param c The command to send
00344      * @return 0 if success, else I2C error
00345      */
00346     virtual uint8_t command(uint8_t c)
00347     {
00348         char buff[2];
00349         buff[0] = 0; // Command Mode
00350         buff[1] = c;
00351         return mi2c.write(mi2cAddress, buff, sizeof(buff));
00352     }
00353 
00354     /** Send Data via I2C
00355      * @param c The data to send
00356      * @return 0 if success, else I2C error
00357      */
00358     virtual uint8_t data(uint8_t c)
00359     {
00360         char buff[2];
00361         buff[0] = 0x40; // Data Mode
00362         buff[1] = c;
00363         return mi2c.write(mi2cAddress, buff, sizeof(buff));
00364     };
00365 
00366 protected:
00367     virtual uint8_t sendDisplayBuffer()
00368     {
00369         char buff[17];
00370         buff[0] = 0x40; // Data Mode
00371 
00372         // send display buffer in 16 byte chunks
00373 #if (OLED_USE_VECTOR==0)
00374         for(uint16_t i=0, q=sizeof(buffer); i<q; i+=16 ) {
00375 #else
00376         for(uint16_t i=0, q=buffer.size(); i<q; i+=16 ) {
00377 #endif
00378             uint8_t retVal;
00379             uint8_t x;
00380 
00381             for(x=1; x<sizeof(buff); x++) {
00382                 buff[x] = buffer[i+x-1];
00383             }
00384 
00385             if((retVal=mi2c.write(mi2cAddress, buff, sizeof(buff))) != 0) {
00386                 return retVal;  //Return error code
00387             }
00388         }
00389         return 0;
00390     };
00391 
00392     /** Write a block of display data. The 128x64 pixels are divided into:
00393      * - 8 RowBlocks, each with 8 rows. This is 1 page of the SSD1206
00394      * - 8 ColBlocks, each with 16 columns.
00395      *
00396      * @param rowBlock Value 0-7 indicating what block of 8 rows to write. 0=0-7,
00397      *        1=8-15, ...., 7=56-63
00398      * @param colBlock Value 0-7 indicating what block of 16 columns to write. 0=0-15,
00399      *        1=16-31, ...., 7=112-127
00400      * @return 0 if success, else I2C or SPI error code
00401      */
00402     uint8_t sendDisplayBuffer(uint8_t rowBlock, uint8_t colBlock) {
00403         uint8_t retVal;
00404         int idxBuffer;
00405         char buff[17];
00406 
00407         buff[0] = 0x40; // Data Mode
00408 
00409         //Each byte of buffer contains 8pixels for single column, and 8 rows. For example:
00410         //buffer[0] contains row 0-7 for column 0
00411         //buffer[1] contains row 0-7 for column 1
00412         idxBuffer = (rowBlock*128) + (colBlock*16);
00413 
00414         // Copy requested "row block" and "column block"
00415         for(uint16_t i=0; i<16; i++) {
00416             buff[i+1] = buffer[idxBuffer+i];
00417         }
00418 
00419         //Write all display data
00420         if((retVal=mi2c.write(mi2cAddress, buff, 17)) != 0) {
00421             return retVal;  //Return error code
00422         }
00423 
00424         return 0;
00425     }
00426 
00427     I2C &mi2c;
00428     uint8_t mi2cAddress;
00429 };
00430 
00431 #endif