diff --git a/SSD1306.cpp b/OLEDDisplay.cpp
similarity index 70%
rename from SSD1306.cpp
rename to OLEDDisplay.cpp
index e5e39c1c1c334317d9741d24320f9a0ab847fade..445d41b7e0f06480924e299273ca9eba368e7ad1 100644
--- a/SSD1306.cpp
+++ b/OLEDDisplay.cpp
@@ -25,63 +25,54 @@
  * Credits for parts of this code go to Mike Rankin. Thank you so much for sharing!
  */
 
-#include "SSD1306.h"
+#include "OLEDDisplay.h"
 
-
-SSD1306::SSD1306(uint8_t i2cAddress, uint8_t sda, uint8_t sdc) {
-  this->i2cAddress = i2cAddress;
-  this->sda = sda;
-  this->sdc = sdc;
-}
-
-bool SSD1306::init() {
+bool OLEDDisplay::init() {
+  if (!this->connect()) {
+    DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Can't establish connection to display\n");
+    return false;
+  }
   this->buffer = (uint8_t*) malloc(sizeof(uint8_t) * DISPLAY_BUFFER_SIZE);
   if(!this->buffer) {
-    DEBUG_SSD1306("[SSD1306][init] Not enough memory to create display\n");
+    DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create display\n");
     return false;
   }
 
-  #ifdef SSD1306_DOUBLE_BUFFER
+  #ifdef OLEDDISPLAY_DOUBLE_BUFFER
   this->buffer_back = (uint8_t*) malloc(sizeof(uint8_t) * DISPLAY_BUFFER_SIZE);
   if(!this->buffer_back) {
-    DEBUG_SSD1306("[SSD1306][init] Not enough memory to create back buffer\n");
+    DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create back buffer\n");
     free(this->buffer);
     return false;
   }
   #endif
 
-  reconnect();
   sendInitCommands();
   resetDisplay();
 
   return true;
 }
 
-void SSD1306::end() {
+void OLEDDisplay::end() {
   if (this->buffer) free(this->buffer);
-  #ifdef SSD1306_DOUBLE_BUFFER
+  #ifdef OLEDDISPLAY_DOUBLE_BUFFER
   if (this->buffer_back) free(this->buffer_back);
   #endif
 }
 
-void SSD1306::resetDisplay(void) {
+void OLEDDisplay::resetDisplay(void) {
   clear();
-  display();
-}
-
-void SSD1306::reconnect() {
-  #ifdef SSD1306_USE_BRZO
-    brzo_i2c_setup(this->sda, this->sdc, 2000);
-  #else
-    Wire.begin(this->sda, this->sdc);
+  #ifdef OLEDDISPLAY_DOUBLE_BUFFER
+  memset(buffer_back, 1, DISPLAY_BUFFER_SIZE);
   #endif
+  display();
 }
 
-void SSD1306::setColor(SSD1306_COLOR color) {
+void OLEDDisplay::setColor(OLEDDISPLAY_COLOR color) {
   this->color = color;
 }
 
-void SSD1306::setPixel(int16_t x, int16_t y) {
+void OLEDDisplay::setPixel(int16_t x, int16_t y) {
   if (x >= 0 && x < 128 && y >= 0 && y < 64) {
     switch (color) {
       case WHITE:   buffer[x + (y / 8) * DISPLAY_WIDTH] |=  (1 << (y & 7)); break;
@@ -92,7 +83,7 @@ void SSD1306::setPixel(int16_t x, int16_t y) {
 }
 
 // Bresenham's algorithm - thx wikipedia and Adafruit_GFX
-void SSD1306::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
+void OLEDDisplay::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
   int16_t steep = abs(y1 - y0) > abs(x1 - x0);
   if (steep) {
     _swap_int16_t(x0, y0);
@@ -131,20 +122,20 @@ void SSD1306::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
   }
 }
 
-void SSD1306::drawRect(int16_t x, int16_t y, int16_t width, int16_t height) {
+void OLEDDisplay::drawRect(int16_t x, int16_t y, int16_t width, int16_t height) {
   drawHorizontalLine(x, y, width);
   drawVerticalLine(x, y, height);
   drawVerticalLine(x + width, y, height);
   drawHorizontalLine(x, y + height, width);
 }
 
-void SSD1306::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t height) {
+void OLEDDisplay::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t height) {
   for (int16_t i = yMove; i < yMove + height; i++) {
     drawHorizontalLine(xMove, i, width);
   }
 }
 
-void SSD1306::drawCircle(int16_t x0, int16_t y0, int16_t radius) {
+void OLEDDisplay::drawCircle(int16_t x0, int16_t y0, int16_t radius) {
   int16_t x = 0, y = radius;
 	int16_t dp = 1 - radius;
 	do {
@@ -170,7 +161,7 @@ void SSD1306::drawCircle(int16_t x0, int16_t y0, int16_t radius) {
   setPixel(x0, y0 - radius);
 }
 
-void SSD1306::fillCircle(int16_t x0, int16_t y0, int16_t radius) {
+void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) {
   int16_t x = 0, y = radius;
 	int16_t dp = 1 - radius;
 	do {
@@ -190,7 +181,7 @@ void SSD1306::fillCircle(int16_t x0, int16_t y0, int16_t radius) {
 
 }
 
-void SSD1306::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
+void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
   if (y < 0 || y >= DISPLAY_HEIGHT) { return; }
 
   if (x < 0) {
@@ -223,7 +214,7 @@ void SSD1306::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
   }
 }
 
-void SSD1306::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
+void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
   if (y < 0 || y > DISPLAY_HEIGHT) return;
 
   if (x < 0) {
@@ -292,7 +283,7 @@ void SSD1306::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
   }
 }
 
-void SSD1306::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress) {
+void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress) {
   uint16_t radius = height / 2;
   uint16_t innerRadius = radius - 3;
   setColor(WHITE);
@@ -309,11 +300,11 @@ void SSD1306::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t h
 
 }
 
-void SSD1306::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *image) {
+void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *image) {
   drawInternal(xMove, yMove, width, height, image, 0, 0);
 }
 
-void SSD1306::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *xbm) {
+void OLEDDisplay::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *xbm) {
   int16_t widthInXbm = (width + 7) / 8;
   uint8_t data;
 
@@ -332,7 +323,7 @@ void SSD1306::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t heigh
   }
 }
 
-void SSD1306::drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth) {
+void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth) {
   uint8_t textHeight       = pgm_read_byte(fontData + HEIGHT_POS);
   uint8_t firstChar        = pgm_read_byte(fontData + FIRST_CHAR_POS);
   uint16_t sizeOfJumpTable = pgm_read_byte(fontData + CHAR_NUM_POS)  * JUMPTABLE_BYTES;
@@ -383,7 +374,7 @@ void SSD1306::drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint1
 }
 
 
-void SSD1306::drawString(int16_t xMove, int16_t yMove, String strUser) {
+void OLEDDisplay::drawString(int16_t xMove, int16_t yMove, String strUser) {
   uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
 
   // char* text must be freed!
@@ -412,7 +403,7 @@ void SSD1306::drawString(int16_t xMove, int16_t yMove, String strUser) {
   free(text);
 }
 
-void SSD1306::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineWidth, String strUser) {
+void OLEDDisplay::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineWidth, String strUser) {
   uint16_t firstChar  = pgm_read_byte(fontData + FIRST_CHAR_POS);
   uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
 
@@ -452,7 +443,7 @@ void SSD1306::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineW
   free(text);
 }
 
-uint16_t SSD1306::getStringWidth(const char* text, uint16_t length) {
+uint16_t OLEDDisplay::getStringWidth(const char* text, uint16_t length) {
   uint16_t firstChar        = pgm_read_byte(fontData + FIRST_CHAR_POS);
 
   uint16_t stringWidth = 0;
@@ -469,7 +460,7 @@ uint16_t SSD1306::getStringWidth(const char* text, uint16_t length) {
   return max(maxWidth, stringWidth);
 }
 
-uint16_t SSD1306::getStringWidth(String strUser) {
+uint16_t OLEDDisplay::getStringWidth(String strUser) {
   char* text = utf8ascii(strUser);
   uint16_t length = strlen(text);
   uint16_t width = getStringWidth(text, length);
@@ -477,194 +468,46 @@ uint16_t SSD1306::getStringWidth(String strUser) {
   return width;
 }
 
-void SSD1306::setTextAlignment(SSD1306_TEXT_ALIGNMENT textAlignment) {
+void OLEDDisplay::setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment) {
   this->textAlignment = textAlignment;
 }
 
-void SSD1306::setFont(const char *fontData) {
+void OLEDDisplay::setFont(const char *fontData) {
   this->fontData = fontData;
 }
 
-void SSD1306::displayOn(void) {
+void OLEDDisplay::displayOn(void) {
   sendCommand(DISPLAYON);
 }
 
-void SSD1306::displayOff(void) {
+void OLEDDisplay::displayOff(void) {
   sendCommand(DISPLAYOFF);
 }
 
-void SSD1306::invertDisplay(void) {
+void OLEDDisplay::invertDisplay(void) {
   sendCommand(INVERTDISPLAY);
 }
 
-void SSD1306::normalDisplay(void) {
+void OLEDDisplay::normalDisplay(void) {
   sendCommand(NORMALDISPLAY);
 }
 
-void SSD1306::setContrast(char contrast) {
+void OLEDDisplay::setContrast(char contrast) {
   sendCommand(SETCONTRAST);
   sendCommand(contrast);
 }
 
-void SSD1306::flipScreenVertically() {
-  sendCommand(SEGREMAP | 0x01);      //Rotate screen 180 deg
+void OLEDDisplay::flipScreenVertically() {
+  sendCommand(SEGREMAP | 0x01);
   sendCommand(COMSCANDEC);           //Rotate screen 180 Deg
 }
 
-void SSD1306::display(void) {
-  #ifdef SSD1306_DOUBLE_BUFFER
-    uint16_t minBoundY = ~0;
-    uint16_t maxBoundY = 0;
-
-    uint16_t minBoundX = ~0;
-    uint16_t maxBoundX = 0;
-
-    uint16_t x, y;
-
-    // Calculate the Y bounding box of changes
-    // and copy buffer[pos] to buffer_back[pos];
-    for (y = 0; y < 8; y++) {
-      for (x = 0; x < DISPLAY_WIDTH; x++) {
-       uint16_t pos = x + y * DISPLAY_WIDTH;
-       if (buffer[pos] != buffer_back[pos]) {
-         minBoundY = min(minBoundY, y);
-         maxBoundY = max(maxBoundY, y);
-         minBoundX = min(minBoundX, x);
-         maxBoundX = max(maxBoundX, x);
-       }
-       buffer_back[pos] = buffer[pos];
-     }
-     yield();
-    }
-
-    // If the minBoundY wasn't updated
-    // we can savely assume that buffer_back[pos] == buffer[pos]
-    // holdes true for all values of pos
-    if (minBoundY == ~0) return;
-
-    sendCommand(COLUMNADDR);
-    sendCommand(minBoundX);
-    sendCommand(maxBoundX);
-
-    sendCommand(PAGEADDR);
-    sendCommand(minBoundY);
-    sendCommand(maxBoundY);
-
-    byte k = 0;
-    #ifdef SSD1306_USE_BRZO
-      uint8_t sendBuffer[17];
-      sendBuffer[0] = 0x40;
-      brzo_i2c_start_transaction(this->i2cAddress, BRZO_I2C_SPEED);
-      for (y = minBoundY; y <= maxBoundY; y++) {
-          for (x = minBoundX; x <= maxBoundX; x++) {
-              k++;
-              sendBuffer[k] = buffer[x + y * DISPLAY_WIDTH];
-              if (k == 16)  {
-                brzo_i2c_write(sendBuffer, 17, true);
-                k = 0;
-              }
-          }
-          yield();
-      }
-      brzo_i2c_write(sendBuffer, k + 1, true);
-      brzo_i2c_end_transaction();
-    #else
-      for (y = minBoundY; y <= maxBoundY; y++) {
-          for (x = minBoundX; x <= maxBoundX; x++) {
-              if (k == 0) {
-                Wire.beginTransmission(this->i2cAddress);
-                Wire.write(0x40);
-              }
-              Wire.write(buffer[x + y * DISPLAY_WIDTH]);
-              k++;
-              if (k == 16)  {
-                Wire.endTransmission();
-                k = 0;
-              }
-          }
-          yield();
-      }
-
-      if (k != 0) {
-        Wire.endTransmission();
-      }
-    #endif
-
-  #else
-  // No double buffering
-    sendCommand(COLUMNADDR);
-    sendCommand(0x0);
-    sendCommand(0x7F);
-
-    sendCommand(PAGEADDR);
-    sendCommand(0x0);
-    sendCommand(0x7);
-
-    #ifdef SSD1306_USE_BRZO
-      uint8_t sendBuffer[17];
-      sendBuffer[0] = 0x40;
-      brzo_i2c_start_transaction(this->i2cAddress, BRZO_I2C_SPEED);
-      for (uint16_t i=0; i<DISPLAY_BUFFER_SIZE; i++) {
-        for (uint8_t x=1; x<17; x++) {
-          sendBuffer[x] = buffer[i];
-          i++;
-        }
-        i--;
-        brzo_i2c_write(sendBuffer,  17,  true);
-        yield();
-      }
-      brzo_i2c_end_transaction();
-    #else
-      byte k = 0;
-      for (y = minBoundY; y <= maxBoundY; y++) {
-          for (x = minBoundX; x <= maxBoundX; x++) {
-              if (k == 0) {
-                Wire.beginTransmission(this->i2cAddress);
-                Wire.write(0x40);
-              }
-              Wire.write(buffer[x + y * DISPLAY_WIDTH]);
-              k++;
-              if (k == 16)  {
-                Wire.endTransmission();
-                k = 0;
-              }
-          }
-          yield();
-      }
-
-      if (k != 0) {
-        Wire.endTransmission();
-      }
-    #endif
-  #endif
-}
-
-
-void SSD1306::clear(void) {
+void OLEDDisplay::clear(void) {
   memset(buffer, 0, DISPLAY_BUFFER_SIZE);
-  #ifdef SSD1306_DOUBLE_BUFFER
-  memset(buffer_back, 1, DISPLAY_BUFFER_SIZE);
-  #endif
 }
 
-
 // Private functions
-
-void SSD1306::sendCommand(unsigned char com) {
-  #ifdef SSD1306_USE_BRZO
-    uint8_t command[2] = {0x80 /* command mode */, com};
-    brzo_i2c_start_transaction(this->i2cAddress, BRZO_I2C_SPEED);
-    brzo_i2c_write(command, 2, true);
-    brzo_i2c_end_transaction();
-  #else
-    Wire.beginTransmission(this->i2cAddress);  //begin transmitting
-    Wire.write(0x80);                          //command mode
-    Wire.write(com);
-    Wire.endTransmission();                    // stop transmitting
-  #endif
-}
-
-void SSD1306::sendInitCommands(void) {
+void OLEDDisplay::sendInitCommands(void) {
   sendCommand(DISPLAYOFF);
   sendCommand(SETDISPLAYCLOCKDIV);
   sendCommand(0xF0); // Increase speed of the display max ~96Hz
@@ -691,7 +534,7 @@ void SSD1306::sendInitCommands(void) {
   sendCommand(DISPLAYON);
 }
 
-void SSD1306::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *data, uint16_t offset, uint16_t bytesInData) {
+void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *data, uint16_t offset, uint16_t bytesInData) {
   if (width < 0 || height < 0) return;
   if (yMove + height < 0 || yMove > DISPLAY_HEIGHT)  return;
   if (xMove + width  < 0 || xMove > DISPLAY_WIDTH)   return;
@@ -760,7 +603,7 @@ void SSD1306::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t
 }
 
 // Code form http://playground.arduino.cc/Main/Utf8ascii
-uint8_t SSD1306::utf8ascii(byte ascii) {
+uint8_t OLEDDisplay::utf8ascii(byte ascii) {
   static uint8_t LASTCHAR;
 
   if ( ascii < 128 ) { // Standard ASCII-set 0..0x7F handling
@@ -781,14 +624,14 @@ uint8_t SSD1306::utf8ascii(byte ascii) {
 }
 
 // You need to free the char!
-char* SSD1306::utf8ascii(String str) {
+char* OLEDDisplay::utf8ascii(String str) {
   uint16_t k = 0;
   uint16_t length = str.length() + 1;
 
   // Copy the string into a char array
   char* s = (char*) malloc(length * sizeof(char));
   if(!s) {
-    DEBUG_SSD1306("[SSD1306][utf8ascii] Can't allocate another char array. Drop support for UTF-8.\n");
+    DEBUG_OLEDDISPLAY("[OLEDDISPLAY][utf8ascii] Can't allocate another char array. Drop support for UTF-8.\n");
     return (char*) str.c_str();
   }
   str.toCharArray(s, length);
diff --git a/OLEDDisplay.h b/OLEDDisplay.h
new file mode 100644
index 0000000000000000000000000000000000000000..226ecefdf0d0f4716ae82c041c6223a9f81596bb
--- /dev/null
+++ b/OLEDDisplay.h
@@ -0,0 +1,244 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 by Daniel Eichhorn
+ * Copyright (c) 2016 by Fabrice Weinberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Credits for parts of this code go to Mike Rankin. Thank you so much for sharing!
+ */
+
+#ifndef OLEDDISPLAY_h
+#define OLEDDISPLAY_h
+
+#include <Arduino.h>
+#include "OLEDDisplayFonts.h"
+
+//#define DEBUG_OLEDDISPLAY(...) Serial.printf( __VA_ARGS__ )
+
+#ifndef DEBUG_OLEDDISPLAY
+#define DEBUG_OLEDDISPLAY(...)
+#endif
+
+// Use DOUBLE BUFFERING by default
+#ifndef OLEDDISPLAY_REDUCE_MEMORY
+#define OLEDDISPLAY_DOUBLE_BUFFER
+#endif
+
+
+// Display settings
+#define DISPLAY_WIDTH 128
+#define DISPLAY_HEIGHT 64
+#define DISPLAY_BUFFER_SIZE 1024
+
+// Header Values
+#define JUMPTABLE_BYTES 4
+
+#define JUMPTABLE_LSB   1
+#define JUMPTABLE_SIZE  2
+#define JUMPTABLE_WIDTH 3
+#define JUMPTABLE_START 4
+
+#define WIDTH_POS 0
+#define HEIGHT_POS 1
+#define FIRST_CHAR_POS 2
+#define CHAR_NUM_POS 3
+
+
+// Display commands
+#define CHARGEPUMP 0x8D
+#define COLUMNADDR 0x21
+#define COMSCANDEC 0xC8
+#define COMSCANINC 0xC0
+#define DISPLAYALLON 0xA5
+#define DISPLAYALLON_RESUME 0xA4
+#define DISPLAYOFF 0xAE
+#define DISPLAYON 0xAF
+#define EXTERNALVCC 0x1
+#define INVERTDISPLAY 0xA7
+#define MEMORYMODE 0x20
+#define NORMALDISPLAY 0xA6
+#define PAGEADDR 0x22
+#define SEGREMAP 0xA0
+#define SETCOMPINS 0xDA
+#define SETCONTRAST 0x81
+#define SETDISPLAYCLOCKDIV 0xD5
+#define SETDISPLAYOFFSET 0xD3
+#define SETHIGHCOLUMN 0x10
+#define SETLOWCOLUMN 0x00
+#define SETMULTIPLEX 0xA8
+#define SETPRECHARGE 0xD9
+#define SETSEGMENTREMAP 0xA1
+#define SETSTARTLINE 0x40
+#define SETVCOMDETECT 0xDB
+#define SWITCHCAPVCC 0x2
+
+#ifndef _swap_int16_t
+#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
+#endif
+
+enum OLEDDISPLAY_COLOR {
+  BLACK = 0,
+  WHITE = 1,
+  INVERSE = 2
+};
+
+enum OLEDDISPLAY_TEXT_ALIGNMENT {
+  TEXT_ALIGN_LEFT = 0,
+  TEXT_ALIGN_RIGHT = 1,
+  TEXT_ALIGN_CENTER = 2,
+  TEXT_ALIGN_CENTER_BOTH = 3
+};
+
+
+class OLEDDisplay {
+  public:
+    // Initialize the display
+    bool init();
+
+    // Free the memory used by the display
+    void end();
+
+    // Cycle through the initialization
+    void resetDisplay(void);
+
+    /* Drawing functions */
+    // Sets the color of all pixel operations
+    void setColor(OLEDDISPLAY_COLOR color);
+
+    // Draw a pixel at given position
+    void setPixel(int16_t x, int16_t y);
+
+    // Draw a line from position 0 to position 1
+    void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1);
+
+    // Draw the border of a rectangle at the given location
+    void drawRect(int16_t x, int16_t y, int16_t width, int16_t height);
+
+    // Fill the rectangle
+    void fillRect(int16_t x, int16_t y, int16_t width, int16_t height);
+
+    // Draw the border of a circle
+    void drawCircle(int16_t x, int16_t y, int16_t radius);
+
+    // Fill circle
+    void fillCircle(int16_t x, int16_t y, int16_t radius);
+
+    // Draw a line horizontally
+    void drawHorizontalLine(int16_t x, int16_t y, int16_t length);
+
+    // Draw a lin vertically
+    void drawVerticalLine(int16_t x, int16_t y, int16_t length);
+
+    /**
+     * Draws a rounded progress bar with the outer dimensions given by width and height.
+     */
+    void drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress);
+
+    // Draw a bitmap in the internal image format
+    void drawFastImage(int16_t x, int16_t y, int16_t width, int16_t height, const char *image);
+
+    // Draw a XBM
+    void drawXbm(int16_t x, int16_t y, int16_t width, int16_t height, const char *xbm);
+
+    /* Text functions */
+
+    // Draws a string at the given location
+    void drawString(int16_t x, int16_t y, String text);
+
+    // Draws a String with a maximum width at the given location.
+    // If the given String is wider than the specified width
+    // The text will be wrapped to the next line at a space or dash
+    void drawStringMaxWidth(int16_t x, int16_t y, uint16_t maxLineWidth, String text);
+
+    // Returns the width of the const char* with the current
+    // font settings
+    uint16_t getStringWidth(const char* text, uint16_t length);
+
+    // Convencience method for the const char version
+    uint16_t getStringWidth(String text);
+
+    // Specifies relative to which anchor point
+    // the text is rendered. Available constants:
+    // TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER_BOTH
+    void setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment);
+
+    // Sets the current font. Available default fonts
+    // ArialMT_Plain_10, ArialMT_Plain_16, ArialMT_Plain_24
+    void setFont(const char *fontData);
+
+    /* Display functions */
+
+    // Turn the display on
+    void displayOn(void);
+
+    // Turn the display offs
+    void displayOff(void);
+
+    // Inverted display mode
+    void invertDisplay(void);
+
+    // Normal display mode
+    void normalDisplay(void);
+
+    // Set display contrast
+    void setContrast(char contrast);
+
+    // Turn the display upside down
+    void flipScreenVertically();
+
+    // Write the buffer to the display memory
+    virtual void display(void);
+
+    // Clear the local pixel buffer
+    void clear(void);
+
+    uint8_t            *buffer;
+
+    #ifdef OLEDDISPLAY_DOUBLE_BUFFER
+    uint8_t            *buffer_back;
+    #endif
+
+  protected:
+    OLEDDISPLAY_TEXT_ALIGNMENT   textAlignment = TEXT_ALIGN_LEFT;
+    OLEDDISPLAY_COLOR            color         = WHITE;
+
+    const char          *fontData          = ArialMT_Plain_10;
+
+    // Send a command to the display (low level function)
+    virtual void sendCommand(uint8_t com);
+
+    // Connect to the display
+    virtual bool connect();
+
+    // Send all the init commands
+    void sendInitCommands();
+
+    // converts utf8 characters to extended ascii
+    static char* utf8ascii(String s);
+    static byte utf8ascii(byte ascii);
+
+    void inline drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *data, uint16_t offset, uint16_t bytesInData) __attribute__((always_inline));
+
+    void drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth);
+
+};
+
+#endif
diff --git a/SSD1306Fonts.h b/OLEDDisplayFonts.h
similarity index 99%
rename from SSD1306Fonts.h
rename to OLEDDisplayFonts.h
index 41d91f8046c049ee724618b33e59da647367193a..6dd21ef60b9919ca2dd24935340f3a5f518735a8 100644
--- a/SSD1306Fonts.h
+++ b/OLEDDisplayFonts.h
@@ -1,3 +1,6 @@
+#ifndef OLEDDISPLAYFONTS_h
+#define OLEDDISPLAYFONTS_h
+
 const char ArialMT_Plain_10[] PROGMEM = {
   0x0A, // Width: 10
   0x0D, // Height: 13
@@ -1268,3 +1271,4 @@ const char ArialMT_Plain_24[] PROGMEM = {
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x07,0xE0,0xFF,0xFF,0x07,0x00,0x1C,0x18,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x06,0x30,0x00,0x00,0x0E,0x38,0x00,0x00,0x1C,0x1C,0x00,0x00,0xF8,0x0F,0x00,0x00,0xF0,0x03, // 254
   0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x7E,0x00,0x06,0xC0,0xF0,0x01,0x06,0xC0,0x80,0x0F,0x07,0x00,0x00,0xFE,0x03,0x00,0x00,0xFC,0x00,0xC0,0xC0,0x1F,0x00,0xC0,0xF8,0x03,0x00,0x00,0x3E,0x00,0x00,0x00,0x06 // 255
 };
+#endif 
diff --git a/SSD1306Ui.cpp b/OLEDDisplayUi.cpp
similarity index 85%
rename from SSD1306Ui.cpp
rename to OLEDDisplayUi.cpp
index d6d7bdace48b22fb445dffa3ab04d7d32dc0e336..5f6499c2da16f7896592521d10c834d6ca984e64 100644
--- a/SSD1306Ui.cpp
+++ b/OLEDDisplayUi.cpp
@@ -24,17 +24,17 @@
  *
  */
 
-#include "SSD1306Ui.h"
+#include "OLEDDisplayUi.h"
 
-SSD1306Ui::SSD1306Ui(SSD1306 *display) {
+OLEDDisplayUi::OLEDDisplayUi(OLEDDisplay *display) {
   this->display = display;
 }
 
-void SSD1306Ui::init() {
+void OLEDDisplayUi::init() {
   this->display->init();
 }
 
-void SSD1306Ui::setTargetFPS(uint8_t fps){
+void OLEDDisplayUi::setTargetFPS(uint8_t fps){
   float oldInterval = this->updateInterval;
   this->updateInterval = ((float) 1.0 / (float) fps) * 1000;
 
@@ -46,68 +46,68 @@ void SSD1306Ui::setTargetFPS(uint8_t fps){
 
 // -/------ Automatic controll ------\-
 
-void SSD1306Ui::enableAutoTransition(){
+void OLEDDisplayUi::enableAutoTransition(){
   this->autoTransition = true;
 }
-void SSD1306Ui::disableAutoTransition(){
+void OLEDDisplayUi::disableAutoTransition(){
   this->autoTransition = false;
 }
-void SSD1306Ui::setAutoTransitionForwards(){
+void OLEDDisplayUi::setAutoTransitionForwards(){
   this->state.frameTransitionDirection = 1;
   this->lastTransitionDirection = 1;
 }
-void SSD1306Ui::setAutoTransitionBackwards(){
+void OLEDDisplayUi::setAutoTransitionBackwards(){
   this->state.frameTransitionDirection = -1;
   this->lastTransitionDirection = -1;
 }
-void SSD1306Ui::setTimePerFrame(uint16_t time){
+void OLEDDisplayUi::setTimePerFrame(uint16_t time){
   this->ticksPerFrame = (int) ( (float) time / (float) updateInterval);
 }
-void SSD1306Ui::setTimePerTransition(uint16_t time){
+void OLEDDisplayUi::setTimePerTransition(uint16_t time){
   this->ticksPerTransition = (int) ( (float) time / (float) updateInterval);
 }
 
 // -/------ Customize indicator position and style -------\-
-void SSD1306Ui::enableIndicator(){
+void OLEDDisplayUi::enableIndicator(){
   this->state.isIndicatorDrawen = true;
 }
 
-void SSD1306Ui::disableIndicator(){
+void OLEDDisplayUi::disableIndicator(){
   this->state.isIndicatorDrawen = false;
 }
 
-void SSD1306Ui::setIndicatorPosition(IndicatorPosition pos) {
+void OLEDDisplayUi::setIndicatorPosition(IndicatorPosition pos) {
   this->indicatorPosition = pos;
 }
-void SSD1306Ui::setIndicatorDirection(IndicatorDirection dir) {
+void OLEDDisplayUi::setIndicatorDirection(IndicatorDirection dir) {
   this->indicatorDirection = dir;
 }
-void SSD1306Ui::setActiveSymbol(const char* symbol) {
+void OLEDDisplayUi::setActiveSymbol(const char* symbol) {
   this->activeSymbol = symbol;
 }
-void SSD1306Ui::setInactiveSymbol(const char* symbol) {
+void OLEDDisplayUi::setInactiveSymbol(const char* symbol) {
   this->inactiveSymbol = symbol;
 }
 
+
 // -/----- Frame settings -----\-
-void SSD1306Ui::setFrameAnimation(AnimationDirection dir) {
+void OLEDDisplayUi::setFrameAnimation(AnimationDirection dir) {
   this->frameAnimationDirection = dir;
 }
-void SSD1306Ui::setFrames(FrameCallback* frameFunctions, uint8_t frameCount) {
+void OLEDDisplayUi::setFrames(FrameCallback* frameFunctions, uint8_t frameCount) {
   this->frameCount     = frameCount;
   this->frameFunctions = frameFunctions;
-  this->state.currentFrame = 0;
 }
 
 // -/----- Overlays ------\-
-void SSD1306Ui::setOverlays(OverlayCallback* overlayFunctions, uint8_t overlayCount){
+void OLEDDisplayUi::setOverlays(OverlayCallback* overlayFunctions, uint8_t overlayCount){
   this->overlayCount     = overlayCount;
   this->overlayFunctions = overlayFunctions;
 }
 
 // -/----- Loading Process -----\-
 
-void SSD1306Ui::runLoadingProcess(LoadingStage* stages, uint8_t stagesCount) {
+void OLEDDisplayUi::runLoadingProcess(LoadingStage* stages, uint8_t stagesCount) {
   display->setTextAlignment(TEXT_ALIGN_CENTER);
   display->setFont(ArialMT_Plain_10);
 
@@ -133,7 +133,7 @@ void SSD1306Ui::runLoadingProcess(LoadingStage* stages, uint8_t stagesCount) {
 }
 
 // -/----- Manuel control -----\-
-void SSD1306Ui::nextFrame() {
+void OLEDDisplayUi::nextFrame() {
   if (this->state.frameState != IN_TRANSITION) {
     this->state.manuelControll = true;
     this->state.frameState = IN_TRANSITION;
@@ -142,7 +142,7 @@ void SSD1306Ui::nextFrame() {
     this->state.frameTransitionDirection = 1;
   }
 }
-void SSD1306Ui::previousFrame() {
+void OLEDDisplayUi::previousFrame() {
   if (this->state.frameState != IN_TRANSITION) {
     this->state.manuelControll = true;
     this->state.frameState = IN_TRANSITION;
@@ -154,25 +154,26 @@ void SSD1306Ui::previousFrame() {
 
 
 // -/----- State information -----\-
-SSD1306UiState* SSD1306Ui::getUiState(){
+OLEDDisplayUiState* OLEDDisplayUi::getUiState(){
   return &this->state;
 }
 
 
-int8_t SSD1306Ui::update(){
-  int8_t timeBudget = this->updateInterval - (millis() - this->state.lastUpdate);
+int8_t OLEDDisplayUi::update(){
+  long frameStart = millis();
+  int8_t timeBudget = this->updateInterval - (frameStart - this->state.lastUpdate);
   if ( timeBudget <= 0) {
     // Implement frame skipping to ensure time budget is keept
     if (this->autoTransition && this->state.lastUpdate != 0) this->state.ticksSinceLastStateSwitch += ceil(-timeBudget / this->updateInterval);
 
-    this->state.lastUpdate = millis();
+    this->state.lastUpdate = frameStart;
     this->tick();
   }
-  return timeBudget;
+  return this->updateInterval - (millis() - frameStart);
 }
 
 
-void SSD1306Ui::tick() {
+void OLEDDisplayUi::tick() {
   this->state.ticksSinceLastStateSwitch++;
 
   switch (this->state.frameState) {
@@ -205,7 +206,7 @@ void SSD1306Ui::tick() {
   this->display->display();
 }
 
-void SSD1306Ui::drawFrame(){
+void OLEDDisplayUi::drawFrame(){
   switch (this->state.frameState){
      case IN_TRANSITION: {
        float progress = (float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition;
@@ -280,7 +281,7 @@ void SSD1306Ui::drawFrame(){
   }
 }
 
-void SSD1306Ui::drawIndicator() {
+void OLEDDisplayUi::drawIndicator() {
 
     // Only draw if the indicator is invisible
     // for both frames or
@@ -352,13 +353,13 @@ void SSD1306Ui::drawIndicator() {
     }
 }
 
-void SSD1306Ui::drawOverlays() {
+void OLEDDisplayUi::drawOverlays() {
  for (uint8_t i=0;i<this->overlayCount;i++){
     (this->overlayFunctions[i])(this->display, &this->state);
  }
 }
 
-uint8_t SSD1306Ui::getNextFrameNumber(){
+uint8_t OLEDDisplayUi::getNextFrameNumber(){
   int8_t nextFrame = (this->state.currentFrame + this->state.frameTransitionDirection) % this->frameCount;
   if (nextFrame < 0){
     nextFrame = this->frameCount + nextFrame;
diff --git a/SSD1306Ui.h b/OLEDDisplayUi.h
similarity index 88%
rename from SSD1306Ui.h
rename to OLEDDisplayUi.h
index 690e37e860e37e37dad644cb10d8e2db91ba9161..560c27ce18ed0040df92a3372260fa584a610e94 100644
--- a/SSD1306Ui.h
+++ b/OLEDDisplayUi.h
@@ -24,15 +24,16 @@
  *
  */
 
-#pragma once
+#ifndef OLEDDISPLAYUI_h
+#define OLEDDISPLAYUI_h
 
 #include <Arduino.h>
-#include "SSD1306.h"
+#include "OLEDDisplay.h"
 
-//#define DEBUG_SSD1306Ui(...) Serial.printf( __VA_ARGS__ )
+//#define DEBUG_OLEDDISPLAYUI(...) Serial.printf( __VA_ARGS__ )
 
-#ifndef DEBUG_SSD1306Ui
-#define DEBUG_SSD1306Ui(...)
+#ifndef DEBUG_OLEDDISPLAYUI
+#define DEBUG_OLEDDISPLAYUI(...)
 #endif
 
 enum AnimationDirection {
@@ -70,7 +71,7 @@ const char ANIMATION_inactiveSymbol[] PROGMEM = {
 
 
 // Structure of the UiState
-struct SSD1306UiState {
+struct OLEDDisplayUiState {
   u_int64_t     lastUpdate                = 0;
   uint16_t      ticksSinceLastStateSwitch = 0;
 
@@ -93,13 +94,13 @@ struct LoadingStage {
   void (*callback)();
 };
 
-typedef void (*FrameCallback)(SSD1306 *display,  SSD1306UiState* state, int16_t x, int16_t y);
-typedef void (*OverlayCallback)(SSD1306 *display,  SSD1306UiState* state);
-typedef void (*LoadingDrawFunction)(SSD1306 *display, LoadingStage* stage, uint8_t progress);
+typedef void (*FrameCallback)(OLEDDisplay *display,  OLEDDisplayUiState* state, int16_t x, int16_t y);
+typedef void (*OverlayCallback)(OLEDDisplay *display,  OLEDDisplayUiState* state);
+typedef void (*LoadingDrawFunction)(OLEDDisplay *display, LoadingStage* stage, uint8_t progress);
 
-class SSD1306Ui {
+class OLEDDisplayUi {
   private:
-    SSD1306             *display;
+    OLEDDisplay             *display;
 
     // Symbols for the Indicator
     IndicatorPosition   indicatorPosition         = BOTTOM;
@@ -133,16 +134,13 @@ class SSD1306Ui {
     uint8_t                indicatorDrawState        = 1;
 
     // Loading screen
-    LoadingDrawFunction loadingDrawFunction       = [](SSD1306 *display, LoadingStage* stage, uint8_t progress) {
+    LoadingDrawFunction loadingDrawFunction       = [](OLEDDisplay *display, LoadingStage* stage, uint8_t progress) {
       display->drawString(64, 20, stage->process);
-
-      // Draw a progress bar.
-      display->drawRect(4, 32, 120, 8);
-      display->fillRect(4 + 2, 32 + 2, (120 * ((float)progress / 100)) - 3, 8 - 3);
+      display->drawProgressBar(4, 32, 120, 8, progress);
     };
 
     // UI State
-    SSD1306UiState      state;
+    OLEDDisplayUiState      state;
 
     // Bookeeping for update
     uint8_t             updateInterval            = 33;
@@ -155,7 +153,7 @@ class SSD1306Ui {
 
   public:
 
-    SSD1306Ui(SSD1306 *display);
+    OLEDDisplayUi(OLEDDisplay *display);
 
     /**
      * Initialise the display
@@ -231,6 +229,7 @@ class SSD1306Ui {
      */
     void setInactiveSymbol(const char* symbol);
 
+
     // Frame settings
 
     /**
@@ -270,7 +269,8 @@ class SSD1306Ui {
     void previousFrame();
 
     // State Info
-    SSD1306UiState* getUiState();
+    OLEDDisplayUiState* getUiState();
 
     int8_t update();
 };
+#endif
diff --git a/SSD1306.h b/SSD1306.h
index 2c4400add57eb48e1d0e3bac9b30ccd0716baa14..f3b790949319e3d4e54f9edd06040c6b8cab8f62 100644
--- a/SSD1306.h
+++ b/SSD1306.h
@@ -25,239 +25,12 @@
  * Credits for parts of this code go to Mike Rankin. Thank you so much for sharing!
  */
 
-#pragma once
+#ifndef SSD1306_h
+#define SSD1306_h
+#include "SSD1306Wire.h"
 
-#include <Arduino.h>
-#include "SSD1306Fonts.h"
-
-#ifdef SSD1306_USE_BRZO
-  #include "brzo_i2c.h"
-  // Brzo can handle 1Mhz in ESP8266 160Mhz mode
-  // and 800KHz in 80Mhz mode
-  #if F_CPU == 160000000L
-    #define BRZO_I2C_SPEED 1000
-  #else
-    #define BRZO_I2C_SPEED 800
-  #endif
-#else // Default use Wire
-  #include <Wire.h>
-#endif
-
-
-//#define DEBUG_SSD1306(...) Serial.printf( __VA_ARGS__ )
-
-#ifndef DEBUG_SSD1306
-#define DEBUG_SSD1306(...)
-#endif
-
-// Use DOUBLE BUFFERING by default
-#ifndef SSD1306_REDUCE_MEMORY
-#define SSD1306_DOUBLE_BUFFER
-#endif
+// For legacy support make SSD1306 an alias for SSD1306
+typedef SSD1306Wire SSD1306;
 
 
-// Display settings
-#define DISPLAY_WIDTH 128
-#define DISPLAY_HEIGHT 64
-#define DISPLAY_BUFFER_SIZE 1024
-
-// Header Values
-#define JUMPTABLE_BYTES 4
-
-#define JUMPTABLE_LSB   1
-#define JUMPTABLE_SIZE  2
-#define JUMPTABLE_WIDTH 3
-#define JUMPTABLE_START 4
-
-#define WIDTH_POS 0
-#define HEIGHT_POS 1
-#define FIRST_CHAR_POS 2
-#define CHAR_NUM_POS 3
-
-
-// Display commands
-#define CHARGEPUMP 0x8D
-#define COLUMNADDR 0x21
-#define COMSCANDEC 0xC8
-#define COMSCANINC 0xC0
-#define DISPLAYALLON 0xA5
-#define DISPLAYALLON_RESUME 0xA4
-#define DISPLAYOFF 0xAE
-#define DISPLAYON 0xAF
-#define EXTERNALVCC 0x1
-#define INVERTDISPLAY 0xA7
-#define MEMORYMODE 0x20
-#define NORMALDISPLAY 0xA6
-#define PAGEADDR 0x22
-#define SEGREMAP 0xA0
-#define SETCOMPINS 0xDA
-#define SETCONTRAST 0x81
-#define SETDISPLAYCLOCKDIV 0xD5
-#define SETDISPLAYOFFSET 0xD3
-#define SETHIGHCOLUMN 0x10
-#define SETLOWCOLUMN 0x00
-#define SETMULTIPLEX 0xA8
-#define SETPRECHARGE 0xD9
-#define SETSEGMENTREMAP 0xA1
-#define SETSTARTLINE 0x40
-#define SETVCOMDETECT 0xDB
-#define SWITCHCAPVCC 0x2
-
-#ifndef _swap_int16_t
-#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
 #endif
-
-enum SSD1306_COLOR {
-  BLACK = 0,
-  WHITE = 1,
-  INVERSE = 2
-};
-
-enum SSD1306_TEXT_ALIGNMENT {
-  TEXT_ALIGN_LEFT = 0,
-  TEXT_ALIGN_RIGHT = 1,
-  TEXT_ALIGN_CENTER = 2,
-  TEXT_ALIGN_CENTER_BOTH = 3
-};
-
-class SSD1306 {
-  private:
-
-    uint8_t             i2cAddress;
-    uint8_t             sda;
-    uint8_t             sdc;
-
-    uint8_t            *buffer;
-
-    #ifdef SSD1306_DOUBLE_BUFFER
-    uint8_t            *buffer_back;
-    #endif
-
-    SSD1306_TEXT_ALIGNMENT   textAlignment = TEXT_ALIGN_LEFT;
-    SSD1306_COLOR            color         = WHITE;
-
-    const char          *fontData      = ArialMT_Plain_10;
-
-    // Send a command to the display (low level function)
-    void sendCommand(unsigned char com);
-
-    // Send all the init commands
-    void sendInitCommands(void);
-
-    // converts utf8 characters to extended ascii
-    byte utf8ascii(byte ascii);
-    char* utf8ascii(String s);
-
-    void drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *data, uint16_t offset, uint16_t bytesInData) __attribute__((always_inline));
-
-    void drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth);
-  public:
-
-    // Create the display object connected to pin sda and sdc
-    SSD1306(uint8_t i2cAddress, uint8_t sda, uint8_t sdc);
-
-    // Initialize the display
-    bool init();
-
-    // Free the memory used by the display
-    void end();
-
-    // Cycle through the initialization
-    void resetDisplay(void);
-
-    // Connect again to the display through I2C
-    void reconnect(void);
-
-    /* Drawing functions */
-
-    // Sets the color of all pixel operations
-    void setColor(SSD1306_COLOR color);
-
-    // Draw a pixel at given position
-    void setPixel(int16_t x, int16_t y);
-    
-    // Draw a line from position 0 to position 1
-    void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1);
-
-    // Draw the border of a rectangle at the given location
-    void drawRect(int16_t x, int16_t y, int16_t width, int16_t height);
-
-    // Fill the rectangle
-    void fillRect(int16_t x, int16_t y, int16_t width, int16_t height);
-
-    // Draw the border of a circle
-    void drawCircle(int16_t x, int16_t y, int16_t radius);
-
-    // Fill circle
-    void fillCircle(int16_t x, int16_t y, int16_t radius);
-
-    // Draw a line horizontally
-    void drawHorizontalLine(int16_t x, int16_t y, int16_t length);
-
-    // Draw a lin vertically
-    void drawVerticalLine(int16_t x, int16_t y, int16_t length);
-
-    /**
-     * Draws a rounded progress bar with the outer dimensions given by width and height.
-     */
-    void drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress);
-
-    // Draw a bitmap in the internal image format
-    void drawFastImage(int16_t x, int16_t y, int16_t width, int16_t height, const char *image);
-
-    // Draw a XBM
-    void drawXbm(int16_t x, int16_t y, int16_t width, int16_t height, const char *xbm);
-
-    /* Text functions */
-
-    // Draws a string at the given location
-    void drawString(int16_t x, int16_t y, String text);
-
-    // Draws a String with a maximum width at the given location.
-    // If the given String is wider than the specified width
-    // The text will be wrapped to the next line at a space or dash
-    void drawStringMaxWidth(int16_t x, int16_t y, uint16_t maxLineWidth, String text);
-
-    // Returns the width of the const char* with the current
-    // font settings
-    uint16_t getStringWidth(const char* text, uint16_t length);
-
-    // Convencience method for the const char version
-    uint16_t getStringWidth(String text);
-
-    // Specifies relative to which anchor point
-    // the text is rendered. Available constants:
-    // TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER_BOTH
-    void setTextAlignment(SSD1306_TEXT_ALIGNMENT textAlignment);
-
-    // Sets the current font. Available default fonts
-    // ArialMT_Plain_10, ArialMT_Plain_16, ArialMT_Plain_24
-    void setFont(const char *fontData);
-
-    /* Display functions */
-
-    // Turn the display on
-    void displayOn(void);
-
-    // Turn the display offs
-    void displayOff(void);
-
-    // Inverted display mode
-    void invertDisplay(void);
-
-    // Normal display mode
-    void normalDisplay(void);
-
-    // Set display contrast
-    void setContrast(char contrast);
-
-    // Turn the display upside down
-    void flipScreenVertically();
-
-    // Write the buffer to the display memory
-    void display(void);
-
-    // Clear the local pixel buffer
-    void clear(void);
-
-};
diff --git a/SSD1306Brzo.h b/SSD1306Brzo.h
new file mode 100644
index 0000000000000000000000000000000000000000..8098aec0b367508b3e5e4d3f45418b35bc5d8ce5
--- /dev/null
+++ b/SSD1306Brzo.h
@@ -0,0 +1,149 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 by Daniel Eichhorn
+ * Copyright (c) 2016 by Fabrice Weinberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Credits for parts of this code go to Mike Rankin. Thank you so much for sharing!
+ */
+
+#ifndef SSD1306Brzo_h
+#define SSD1306Brzo_h
+
+#include "OLEDDisplay.h"
+#include "brzo_i2c.h"
+
+#if F_CPU == 160000000L
+  #define BRZO_I2C_SPEED 1000
+#else
+  #define BRZO_I2C_SPEED 800
+#endif
+
+class SSD1306Brzo : public OLEDDisplay {
+  private:
+      uint8_t             _address;
+      uint8_t             _sda;
+      uint8_t             _scl;
+
+  public:
+    SSD1306Brzo(uint8_t _address, uint8_t _sda, uint8_t _scl) {
+      this->_address = _address;
+      this->_sda = _sda;
+      this->_scl = _scl;
+    }
+
+    bool connect(){
+      brzo_i2c_setup(_sda, _scl, 0);
+      return true;
+    }
+
+    void display(void) {
+    #ifdef OLEDDISPLAY_DOUBLE_BUFFER
+       uint8_t minBoundY = ~0;
+       uint8_t maxBoundY = 0;
+
+       uint8_t minBoundX = ~0;
+       uint8_t maxBoundX = 0;
+
+       uint8_t x, y;
+
+       // Calculate the Y bounding box of changes
+       // and copy buffer[pos] to buffer_back[pos];
+       for (y = 0; y < (DISPLAY_HEIGHT / 8); y++) {
+         for (x = 0; x < DISPLAY_WIDTH; x++) {
+          uint16_t pos = x + y * DISPLAY_WIDTH;
+          if (buffer[pos] != buffer_back[pos]) {
+            minBoundY = _min(minBoundY, y);
+            maxBoundY = _max(maxBoundY, y);
+            minBoundX = _min(minBoundX, x);
+            maxBoundX = _max(maxBoundX, x);
+          }
+          buffer_back[pos] = buffer[pos];
+        }
+        yield();
+       }
+
+       // If the minBoundY wasn't updated
+       // we can savely assume that buffer_back[pos] == buffer[pos]
+       // holdes true for all values of pos
+       if (minBoundY == ~0) return;
+
+       sendCommand(COLUMNADDR);
+       sendCommand(minBoundX);
+       sendCommand(maxBoundX);
+
+       sendCommand(PAGEADDR);
+       sendCommand(minBoundY);
+       sendCommand(maxBoundY);
+
+       byte k = 0;
+       uint8_t sendBuffer[17];
+       sendBuffer[0] = 0x40;
+       brzo_i2c_start_transaction(this->_address, BRZO_I2C_SPEED);
+       for (y = minBoundY; y <= maxBoundY; y++) {
+           for (x = minBoundX; x <= maxBoundX; x++) {
+               k++;
+               sendBuffer[k] = buffer[x + y * DISPLAY_WIDTH];
+               if (k == 16)  {
+                 brzo_i2c_write(sendBuffer, 17, true);
+                 k = 0;
+               }
+           }
+           yield();
+       }
+       brzo_i2c_write(sendBuffer, k + 1, true);
+       brzo_i2c_end_transaction();
+     #else
+       // No double buffering
+       sendCommand(COLUMNADDR);
+       sendCommand(0x0);
+       sendCommand(0x7F);
+
+       sendCommand(PAGEADDR);
+       sendCommand(0x0);
+       sendCommand(0x7);
+
+       uint8_t sendBuffer[17];
+       sendBuffer[0] = 0x40;
+       brzo_i2c_start_transaction(this->_address, BRZO_I2C_SPEED);
+       for (uint16_t i=0; i<DISPLAY_BUFFER_SIZE; i++) {
+         for (uint8_t x=1; x<17; x++) {
+           sendBuffer[x] = buffer[i];
+           i++;
+         }
+         i--;
+         brzo_i2c_write(sendBuffer,  17,  true);
+         yield();
+       }
+       brzo_i2c_end_transaction();
+     #endif
+    }
+
+  private:
+    inline void sendCommand(uint8_t com) __attribute__((always_inline)){
+      uint8_t command[2] = {0x80 /* command mode */, com};
+      brzo_i2c_start_transaction(_address, BRZO_I2C_SPEED);
+      brzo_i2c_write(command, 2, true);
+      brzo_i2c_end_transaction();
+    }
+};
+
+#endif
diff --git a/SSD1306Spi.h b/SSD1306Spi.h
new file mode 100644
index 0000000000000000000000000000000000000000..21794587ac612cb951706546dadb2d2bb0c23593
--- /dev/null
+++ b/SSD1306Spi.h
@@ -0,0 +1,150 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 by Daniel Eichhorn
+ * Copyright (c) 2016 by Fabrice Weinberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Credits for parts of this code go to Mike Rankin. Thank you so much for sharing!
+ */
+
+#ifndef SSD1306Spi_h
+#define SSD1306Spi_h
+
+#include "OLEDDisplay.h"
+#include <SPI.h>
+
+#if F_CPU == 160000000L
+  #define BRZO_I2C_SPEED 1000
+#else
+  #define BRZO_I2C_SPEED 800
+#endif
+
+class SSD1306Spi : public OLEDDisplay {
+  private:
+      uint8_t             _rst;
+      uint8_t             _dc;
+      uint8_t             _cs;
+
+  public:
+    SSD1306Spi(uint8_t _rst, uint8_t _dc, uint8_t _cs) {
+      this->_rst = _rst;
+      this->_dc  = _dc;
+      this->_cs  = _cs;
+    }
+
+    bool connect(){
+      pinMode(_dc, OUTPUT);
+      pinMode(_cs, OUTPUT);
+      pinMode(_rst, OUTPUT);
+
+      SPI.begin ();
+      SPI.setClockDivider (SPI_CLOCK_DIV2);
+
+      // Pulse Reset low for 10ms
+      digitalWrite(_rst, HIGH);
+      delay(1);
+      digitalWrite(_rst, LOW);
+      delay(10);
+      digitalWrite(_rst, HIGH);
+      return true;
+    }
+
+    void display(void) {
+    #ifdef OLEDDISPLAY_DOUBLE_BUFFER
+       uint8_t minBoundY = ~0;
+       uint8_t maxBoundY = 0;
+
+       uint8_t minBoundX = ~0;
+       uint8_t maxBoundX = 0;
+
+       uint8_t x, y;
+
+       // Calculate the Y bounding box of changes
+       // and copy buffer[pos] to buffer_back[pos];
+       for (y = 0; y < (DISPLAY_HEIGHT / 8); y++) {
+         for (x = 0; x < DISPLAY_WIDTH; x++) {
+          uint16_t pos = x + y * DISPLAY_WIDTH;
+          if (buffer[pos] != buffer_back[pos]) {
+            minBoundY = _min(minBoundY, y);
+            maxBoundY = _max(maxBoundY, y);
+            minBoundX = _min(minBoundX, x);
+            maxBoundX = _max(maxBoundX, x);
+          }
+          buffer_back[pos] = buffer[pos];
+        }
+        yield();
+       }
+
+       // If the minBoundY wasn't updated
+       // we can savely assume that buffer_back[pos] == buffer[pos]
+       // holdes true for all values of pos
+       if (minBoundY == ~0) return;
+
+       sendCommand(COLUMNADDR);
+       sendCommand(minBoundX);
+       sendCommand(maxBoundX);
+
+       sendCommand(PAGEADDR);
+       sendCommand(minBoundY);
+       sendCommand(maxBoundY);
+
+       digitalWrite(_cs, HIGH);
+       digitalWrite(_dc, HIGH);   // data mode
+       digitalWrite(_cs, LOW);
+       for (y = minBoundY; y <= maxBoundY; y++) {
+         for (x = minBoundX; x <= maxBoundX; x++) {
+           SPI.transfer(buffer[x + y * DISPLAY_WIDTH]);
+         }
+         yield();
+       }
+       digitalWrite(_cs, HIGH);
+     #else
+       // No double buffering
+       sendCommand(COLUMNADDR);
+       sendCommand(0x0);
+       sendCommand(0x7F);
+
+       sendCommand(PAGEADDR);
+       sendCommand(0x0);
+       sendCommand(0x7);
+
+        digitalWrite(_cs, HIGH);
+        digitalWrite(_dc, HIGH);   // data mode
+        digitalWrite(_cs, LOW);
+        for (uint16_t i=0; i<DISPLAY_BUFFER_SIZE; i++) {
+          SPI.transfer(buffer[i]);
+          yield();
+        }
+        digitalWrite(_cs, HIGH);
+     #endif
+    }
+
+  private:
+    inline void sendCommand(uint8_t com) __attribute__((always_inline)){
+      digitalWrite(_cs, HIGH);
+      digitalWrite(_dc, LOW);
+      digitalWrite(_cs, LOW);
+      SPI.transfer(com);
+      digitalWrite(_cs, HIGH);
+    }
+};
+
+#endif
diff --git a/SSD1306Wire.h b/SSD1306Wire.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac12becd0964a7d93b20e3e8a42a5db9ab9c253e
--- /dev/null
+++ b/SSD1306Wire.h
@@ -0,0 +1,147 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 by Daniel Eichhorn
+ * Copyright (c) 2016 by Fabrice Weinberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Credits for parts of this code go to Mike Rankin. Thank you so much for sharing!
+ */
+
+#ifndef SSD1306Wire_h
+#define SSD1306Wire_h
+
+#include "OLEDDisplay.h"
+#include <Wire.h>
+
+class SSD1306Wire : public OLEDDisplay {
+  private:
+      uint8_t             _address;
+      uint8_t             _sda;
+      uint8_t             _scl;
+
+  public:
+    SSD1306Wire(uint8_t _address, uint8_t _sda, uint8_t _scl) {
+      this->_address = _address;
+      this->_sda = _sda;
+      this->_scl = _scl;
+    }
+
+    bool connect() {
+      Wire.begin(this->_sda, this->_scl);
+      // Let's use ~700khz if ESP8266 is in 160Mhz mode
+      // this will be limited to ~400khz if the ESP8266 in 80Mhz mode.
+      Wire.setClock(700000);
+      return true;
+    }
+
+    void display(void) {
+      #ifdef OLEDDISPLAY_DOUBLE_BUFFER
+        uint8_t minBoundY = ~0;
+        uint8_t maxBoundY = 0;
+
+        uint8_t minBoundX = ~0;
+        uint8_t maxBoundX = 0;
+        uint8_t x, y;
+
+        // Calculate the Y bounding box of changes
+        // and copy buffer[pos] to buffer_back[pos];
+        for (y = 0; y < (DISPLAY_HEIGHT / 8); y++) {
+          for (x = 0; x < DISPLAY_WIDTH; x++) {
+           uint16_t pos = x + y * DISPLAY_WIDTH;
+           if (buffer[pos] != buffer_back[pos]) {
+             minBoundY = _min(minBoundY, y);
+             maxBoundY = _max(maxBoundY, y);
+             minBoundX = _min(minBoundX, x);
+             maxBoundX = _max(maxBoundX, x);
+           }
+           buffer_back[pos] = buffer[pos];
+         }
+         yield();
+        }
+
+        // If the minBoundY wasn't updated
+        // we can savely assume that buffer_back[pos] == buffer[pos]
+        // holdes true for all values of pos
+        if (minBoundY == ~0) return;
+
+        sendCommand(COLUMNADDR);
+        sendCommand(minBoundX);
+        sendCommand(maxBoundX);
+
+        sendCommand(PAGEADDR);
+        sendCommand(minBoundY);
+        sendCommand(maxBoundY);
+
+        byte k = 0;
+        for (y = minBoundY; y <= maxBoundY; y++) {
+          for (x = minBoundX; x <= maxBoundX; x++) {
+            if (k == 0) {
+              Wire.beginTransmission(_address);
+              Wire.write(0x40);
+            }
+            Wire.write(buffer[x + y * DISPLAY_WIDTH]);
+            k++;
+            if (k == 16)  {
+              Wire.endTransmission();
+              k = 0;
+            }
+          }
+          yield();
+        }
+
+        if (k != 0) {
+          Wire.endTransmission();
+        }
+      #else
+
+        sendCommand(COLUMNADDR);
+        sendCommand(0x0);
+        sendCommand(0x7F);
+
+        sendCommand(PAGEADDR);
+        sendCommand(0x0);
+        sendCommand(0x7);
+
+        for (uint16_t i=0; i < DISPLAY_BUFFER_SIZE; i++) {
+          Wire.beginTransmission(this->_address);
+          Wire.write(0x40);
+          for (uint8_t x = 0; x < 16; x++) {
+            Wire.write(buffer[i]);
+            i++;
+          }
+          i--;
+          Wire.endTransmission();
+        }
+      #endif
+    }
+
+  private:
+    inline void sendCommand(uint8_t command) __attribute__((always_inline)){
+      Wire.beginTransmission(_address);
+      Wire.write(0x80);
+      Wire.write(command);
+      Wire.endTransmission();
+    }
+
+
+};
+
+#endif