ThingPulse OLED SSD1306

Dependents:   Turtle_RadioShuttle

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SSD1306I2C.h Source File

SSD1306I2C.h

00001 /**
00002  * The MIT License (MIT)
00003  *
00004  * Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a copy
00007  * of this software and associated documentation files (the "Software"), to deal
00008  * in the Software without restriction, including without limitation the rights
00009  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010  * copies of the Software, and to permit persons to whom the Software is
00011  * furnished to do so, subject to the following conditions:
00012  *
00013  * The above copyright notice and this permission notice shall be included in all
00014  * copies or substantial portions of the Software.
00015  *
00016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00019  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00020  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00021  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00022  * SOFTWARE.
00023  *
00024  * ThingPulse invests considerable time and money to develop these open source libraries.
00025  * Please support us by buying our products (and not the clones) from
00026  * https://thingpulse.com
00027  *
00028  */
00029 
00030 #ifndef SSD1306I2C_h
00031 #define SSD1306I2C_h
00032 
00033 
00034 #ifdef __MBED__
00035 
00036 #include "OLEDDisplay.h"
00037 #include <mbed.h>
00038 
00039 #ifndef UINT8_MAX
00040  #define UINT8_MAX 0xff
00041 #endif
00042 
00043 class SSD1306I2C : public OLEDDisplay {
00044 public:
00045     SSD1306I2C(uint8_t _address, PinName _sda, PinName _scl, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64) {
00046       setGeometry(g);
00047 
00048       this->_address = _address << 1;  // convert from 7 to 8 bit for mbed.
00049       this->_sda = _sda;
00050       this->_scl = _scl;
00051       _i2c = new I2C(_sda, _scl);
00052     }
00053 
00054     bool connect() {
00055         // mbed supports 100k and 400k some device maybe 1000k
00056 #ifdef TARGET_STM32L4
00057       _i2c->frequency(1000000);
00058 #else
00059       _i2c->frequency(400000);
00060 #endif
00061       return true;
00062     }
00063 
00064     void display(void) {
00065       const int x_offset = (128 - this->width()) / 2;
00066 #ifdef OLEDDISPLAY_DOUBLE_BUFFER
00067         uint8_t minBoundY = UINT8_MAX;
00068         uint8_t maxBoundY = 0;
00069 
00070         uint8_t minBoundX = UINT8_MAX;
00071         uint8_t maxBoundX = 0;
00072         uint8_t x, y;
00073 
00074         // Calculate the Y bounding box of changes
00075         // and copy buffer[pos] to buffer_back[pos];
00076         for (y = 0; y < (this->height() / 8); y++) {
00077           for (x = 0; x < this->width(); x++) {
00078            uint16_t pos = x + y * this->width();
00079            if (buffer[pos] != buffer_back[pos]) {
00080              minBoundY = std::min(minBoundY, y);
00081              maxBoundY = std::max(maxBoundY, y);
00082              minBoundX = std::min(minBoundX, x);
00083              maxBoundX = std::max(maxBoundX, x);
00084            }
00085            buffer_back[pos] = buffer[pos];
00086          }
00087          yield();
00088         }
00089 
00090         // If the minBoundY wasn't updated
00091         // we can savely assume that buffer_back[pos] == buffer[pos]
00092         // holdes true for all values of pos
00093 
00094         if (minBoundY == UINT8_MAX) return;
00095 
00096         sendCommand(COLUMNADDR);
00097         sendCommand(x_offset + minBoundX);  // column start address (0 = reset)
00098         sendCommand(x_offset + maxBoundX);  // column end address (127 = reset)
00099 
00100         sendCommand(PAGEADDR);
00101         sendCommand(minBoundY);             // page start address
00102         sendCommand(maxBoundY);             // page end address
00103 
00104         for (y = minBoundY; y <= maxBoundY; y++) {
00105             uint8_t *start = &buffer[(minBoundX + y * this->width())-1];
00106             uint8_t save = *start;
00107             
00108             *start = 0x40; // control
00109             _i2c->write(_address, (char *)start, (maxBoundX-minBoundX) + 1 + 1);
00110             *start = save;
00111         }
00112 #else
00113 
00114         sendCommand(COLUMNADDR);
00115         sendCommand(x_offset);                      // column start address (0 = reset)
00116         sendCommand(x_offset + (this->width() - 1));// column end address (127 = reset)
00117 
00118         sendCommand(PAGEADDR);
00119         sendCommand(0x0);                           // page start address (0 = reset)
00120 
00121         if (geometry == GEOMETRY_128_64) {
00122           sendCommand(0x7);
00123         } else if (geometry == GEOMETRY_128_32) {
00124           sendCommand(0x3);
00125         }
00126 
00127         buffer[-1] = 0x40; // control
00128         _i2c->write(_address, (char *)&buffer[-1], displayBufferSize + 1);
00129 #endif
00130     }
00131 
00132 private:
00133     int getBufferOffset(void) {
00134         return 0;
00135     }
00136 
00137     inline void sendCommand(uint8_t command) __attribute__((always_inline)) {
00138         char _data[2];
00139         _data[0] = 0x80; // control
00140         _data[1] = command;
00141         _i2c->write(_address, _data, sizeof(_data));
00142     }
00143 
00144     uint8_t             _address;
00145     PinName             _sda;
00146     PinName             _scl;
00147     I2C *_i2c;
00148 };
00149 
00150 #endif
00151 
00152 #endif