Seeed Studio's 0.96" OLED module

Dependencies:   Adafruit_GFX

Fork of SSD1308_128x64_I2C by Wim Huiskamp

Revision:
7:dcff685d41a5
Parent:
4:df92b0c0cb92
Child:
10:74ef7544744e
--- a/SSD1308.cpp	Sat Apr 22 23:19:33 2017 +0000
+++ b/SSD1308.cpp	Thu Apr 27 16:06:54 2017 -0600
@@ -1,1065 +1,1052 @@
-/**  @file SSD1308 I2C device class file
- *   Based on Solomon Systech SSD1308 datasheet, rev. 1, 10/2008
- *   The SSD1308 is used for example in the Seeed 128x64 OLED Display
- *   http://www.seeedstudio.com/depot/grove-oled-display-12864-p-781.html?cPath=163_167
-*/
-// The original code by Andrew Schamp is using (and has been submitted as a part of) Jeff Rowberg's I2Cdevlib library,
-// which should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
-// Some parts also mashed up from Graphic Library for driving monochrome displays based on the PCD8544,
-// Copyright (c) 2011, Wim De Roeve, who in turn did partial port of code found on
-// http://serdisplib.sourceforge.net/ser/pcd8544.html#links and by Petras Saduikis <petras@petras.co.uk>
-//
-// Changelog:
-//   2011-08-25 - Initial release by Andrew Schamp <schamp@gmail.com>
-//   2012-06-19 - Ported to mbed and optimised (WH)
-//   2013-07-12 - Minor comment fix and placeholder for SSD1306 (WH)
-//   2015-01-01 - Switch for optimised I2C calls to test on F401 (WH)
-//       
-/* 
-================================================================================
-I2Cdev device library code is placed under the MIT license
-Copyright (c) 2011 Andrew Schamp
-Copyright (c) 2012,2013 WH (mbed port)
-
-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.
-================================================================================
-*/
-#include "mbed.h"
-#include "SSD1308.h"
-
-//#include "font_3x5.h"
-//#include "font_5x7.h"
-//#include "font_6x8.h"
-#include "font_8x8.h"
-//#include "font_8x12.h"
-//#include "font_16x20.h"
-#include "font_16x24.h"
-
-#if defined(TARGET_LPC1768)
-#define I2C_OPTIMIZE   1
-#else
-#define I2C_OPTIMIZE   0
-#endif
-
-/**
- *@brief Constructor
- *@param I2C &i2c reference to i2c
- *@param uint8_t deviceAddress slaveaddress
- */
-SSD1308::SSD1308(I2C &i2c, uint8_t deviceAddress) : _i2c(i2c) {
-  
-  _writeOpcode = deviceAddress & 0xFE; // low order bit = 0 for write
-  _readOpcode  = deviceAddress | 0x01; // low order bit = 1 for read  
-  
-  initialize(); 
-}
-
-/** @brief High level Init, most settings remain at Power-On reset value
- */
-void SSD1308::initialize() {
-  setHorizontalAddressingMode();
-
-  clearDisplay();
-
-  setInverted(false);
-  
-  setDisplayOn();  
-}
-
-
-/** @brief clear the display
-*/
-#if (I2C_OPTIMIZE == 0)
-// Standard version
-void SSD1308::clearDisplay() {
- 
-  //setDisplayOff();
-  setPageAddress(0, MAX_PAGE);  // all pages
-  setColumnAddress(0, MAX_COL); // all columns
-
-  for (uint8_t page = 0; page < PAGES; page++) {
-    for (uint8_t col = 0; col < COLUMNS; col++) {
-      _sendData(0x00);
-    }
-  }
-
-  //setDisplayOn();
-}
-#else
-//Optimised version
-// Save lots of I2C S,P, address and datacommands:
-// Send S, address, DATA_MODE, data, data, data,...., P
-//
-void SSD1308::clearDisplay() {
-
-  //setDisplayOff();
-  
-  setPageAddress(0, MAX_PAGE);  // all pages
-  setColumnAddress(0, MAX_COL); // all columns
-
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  _i2c.write(DATA_MODE);  
-  for (int i=0; i<(PAGES * COLUMNS); i++) {
-    _i2c.write(0x00);  // Write Data   
-  }
-  _i2c.stop();
-
-  //setDisplayOn();
-}
-#endif
-
-
-/** @brief fill the display
- *  @param uint8_t pattern fillpattern vertical patch or 8 bits 
- *  @param uint8_t start_page begin page   (0..MAX_PAGE)
- *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)                     
- *  @param uint8_t start_col  begin column (0..MAX_COL)
- *  @param uint8_t end_col    end column   (start_col..MAX_COL)
-*/
-#if (I2C_OPTIMIZE == 0)
-//Standard version
-
-void SSD1308::fillDisplay(uint8_t pattern,
-                          uint8_t start_page, uint8_t end_page,
-                          uint8_t start_col, uint8_t end_col) {
-  
-  int count = (end_page - start_page + 1) * (end_col - start_col + 1);
-  
-  //setDisplayOff();
-  setPageAddress(start_page, end_page);  // set page window
-  setColumnAddress(start_col, end_col);  // set column window
- 
-  for (int i=0; i<count; i++) {
-    _sendData(pattern); // Write Data    
-  }
-
-  //setDisplayOn();
-}
-
-#else
-
-//Optimised version
-// Save lots of I2C S,P, address and datacommands:
-// Send S, address, DATA_MODE, data, data, data,...., P
-//
-void SSD1308::fillDisplay(uint8_t pattern,
-                          uint8_t start_page, uint8_t end_page,
-                          uint8_t start_col, uint8_t end_col) {
-  
-  int count = (end_page - start_page + 1) * (end_col - start_col + 1);
-  
-  //setDisplayOff();
-  setPageAddress(start_page, end_page);  // set page window
-  setColumnAddress(start_col, end_col);  // set column window
- 
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  _i2c.write(DATA_MODE);  
-  for (int i=0; i<count; i++) {
-    _i2c.write(pattern);  // Write Data   
-  }
-  _i2c.stop();
-
-  //setDisplayOn();
-}
-
-#endif
-
-
-/** @brief write a bitmap to the display
- *  @param uint8_t* data pointer to bitmap
- *  @param uint8_t start_page begin page   (0..MAX_PAGE)
- *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)                     
- *  @param uint8_t start_col  begin column (0..MAX_COL)
- *  @param uint8_t end_col    end column   (start_col..MAX_COL)
-*/
-#if (I2C_OPTIMIZE == 0)
-//Standard version
-void SSD1308::writeBitmap(uint8_t* data,
-                          uint8_t start_page, uint8_t end_page,
-                          uint8_t start_col, uint8_t end_col){
-  
-  int count = (end_page - start_page + 1) * (end_col - start_col + 1);
-
-  //setDisplayOff();
-  setPageAddress(start_page, end_page);  // set page window
-  setColumnAddress(start_col, end_col);  // set column window
-
-  for (int i=0; i<count; i++) {
-    _sendData(data[i]); // Write Data   
-  }
-
-  //setDisplayOn();
-}
-
-#else
-//Optimised version
-// Save lots of I2C S,P, address and datacommands:
-// Send S, address, DATA_MODE, data, data, data,...., P
-//
-void SSD1308::writeBitmap(uint8_t* data,
-                          uint8_t start_page, uint8_t end_page,
-                          uint8_t start_col, uint8_t end_col){
-  
-  int count = (end_page - start_page + 1) * (end_col - start_col + 1);
-
-  //setDisplayOff();
-  setPageAddress(start_page, end_page);  // set page window
-  setColumnAddress(start_col, end_col);  // set column window
-
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  _i2c.write(DATA_MODE);  
-  for (int i=0; i<count; i++) {
-    _i2c.write(data[i]);  // Write Data       
-  }
-  _i2c.stop();
-
-  //setDisplayOn();
-}
-
-#endif
-
-
-/** @brief write a progressbar to the display, Width is (PRG_MAX_SCALE + 2) pixels
- *  @param uint8_t page begin page   (0..MAX_PAGE)
- *  @param uint8_t col  begin column (0..MAX_COL)
- *  @param int percentage value      (0..100)
-*/
-#define PRG_MAX_SCALE     50
-#define PRG_LEFT_EDGE   0xFF
-#define PRG_RIGHT_EDGE  0xFF
-#define PRG_ACTIVE      0xFF
-//#define PRG_ACTIVE      0xBD
-#define PRG_NOT_ACTIVE  0x81
-
-#if (I2C_OPTIMIZE == 0)
-//Standard version
-void SSD1308::writeProgressBar(uint8_t page, uint8_t col, int percentage) {
-  uint8_t scale_value;
-  
-  if (percentage <= 0) {
-    scale_value = 0;
-  } else if (percentage >= 100) {
-      scale_value = PRG_MAX_SCALE - 1;
-  }
-  else {
-    scale_value = (percentage * PRG_MAX_SCALE) / 100; 
-  }      
-      
-  //setDisplayOff();
-  setPageAddress(page, page);  
-  setColumnAddress(col, MAX_COL); 
-  
-  _sendData(PRG_LEFT_EDGE);
-
-  for (uint8_t col = 0; col < scale_value; col++) {
-      _sendData(PRG_ACTIVE);
-  }
-      
-  _sendData(PRG_ACTIVE);
-  
-  for (uint8_t col = (scale_value+1); col < PRG_MAX_SCALE; col++) {
-      _sendData(PRG_NOT_ACTIVE);
-  }
-
-  _sendData(PRG_RIGHT_EDGE);    
-  
-  //setDisplayOn();
-}
-#else
-
-//Optimised version
-// Save lots of I2C S,P, address and datacommands:
-// Send S, address, DATA_MODE, data, data, data,...., P
-//
-void SSD1308::writeProgressBar(uint8_t page, uint8_t col, int percentage) {
-  uint8_t scale_value;
-  
-  if (percentage <= 0) {
-    scale_value = 0;
-  } else if (percentage >= 100) {
-      scale_value = PRG_MAX_SCALE - 1 ;
-  }
-  else {
-    scale_value = (percentage * PRG_MAX_SCALE) / 100; 
-  }      
-      
-  //setDisplayOff();
-  setPageAddress(page, page);  
-  setColumnAddress(col, MAX_COL); 
-
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  _i2c.write(DATA_MODE);  
-
-  _i2c.write(PRG_LEFT_EDGE);  // Write Data         
-
-  for (uint8_t col = 0; col < scale_value; col++) {
-     _i2c.write(PRG_ACTIVE);  // Write Data                       
-  }
-
-  _i2c.write(PRG_ACTIVE);  // Write Data                       
-     
-  for (uint8_t col = (scale_value+1); col < PRG_MAX_SCALE; col++) {
-     _i2c.write(PRG_NOT_ACTIVE);  // Write Data                 
-  }
-
-  _i2c.write(PRG_RIGHT_EDGE);  // Write Data           
-
-  _i2c.stop();
-    
-  //setDisplayOn();
-}
-#endif
-
-/** @brief write a level meter to the display, Width is (PRG_MAX_SCALE + 2) pixels
- *  @param uint8_t page begin page   (0..MAX_PAGE)
- *  @param uint8_t col  begin column (0..MAX_COL)
- *  @param int percentage value      (0..100)
-*/
-#if (I2C_OPTIMIZE == 0)
-void SSD1308::writeLevelBar(uint8_t page, uint8_t col, int percentage) {
-  uint8_t scale_value;
-  
-  if (percentage <= 0) {
-    scale_value = 0;
-  } else if (percentage >= 100) {
-      scale_value = PRG_MAX_SCALE - 1;
-  }
-  else {
-    scale_value = (percentage * PRG_MAX_SCALE) / 100; 
-  }      
-      
-  //setDisplayOff();
-  setPageAddress(page, page);  
-  setColumnAddress(col, MAX_COL); 
- 
-  _sendData(PRG_LEFT_EDGE);   
-
-  for (uint8_t col = 0; col < scale_value; col++) {
-     _sendData(PRG_NOT_ACTIVE);  // Write Data                       
-  }
-
-  _sendData(PRG_ACTIVE);  // Write Data at active meterlevel
-
-  for (uint8_t col = scale_value+1; col < PRG_MAX_SCALE; col++) {
-      _sendData(PRG_NOT_ACTIVE);                
-  }
-         
-  _sendData(PRG_RIGHT_EDGE);
-    
-  //setDisplayOn();
-}
-#else
-//Optimised version
-// Save lots of I2C S,P, address and datacommands:
-// Send S, address, DATA_MODE, data, data, data,...., P
-//
-void SSD1308::writeLevelBar(uint8_t page, uint8_t col, int percentage) {
-  uint8_t scale_value;
-  
-  if (percentage <= 0) {
-    scale_value = 0;
-  } else if (percentage >= 100) {
-      scale_value = PRG_MAX_SCALE - 1;
-  }
-  else {
-    scale_value = (percentage * PRG_MAX_SCALE) / 100; 
-  }      
-      
-  //setDisplayOff();
-  setPageAddress(page, page);  
-  setColumnAddress(col, MAX_COL); 
-
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  _i2c.write(DATA_MODE);  
-
-  _i2c.write(PRG_LEFT_EDGE);  // Write Data         
-
-  for (uint8_t col = 0; col < scale_value; col++) {
-     _i2c.write(PRG_NOT_ACTIVE);  // Write Data                       
-  }
-
-  _i2c.write(PRG_ACTIVE);  // Write Data at active meterlevel
-  
-  for (uint8_t col = scale_value+1; col < PRG_MAX_SCALE; col++) {
-     _i2c.write(PRG_NOT_ACTIVE);  // Write Data                 
-  }
-
-  _i2c.write(PRG_RIGHT_EDGE);  // Write Data           
-
-  _i2c.stop();
-    
-  //setDisplayOn();
-}
-#endif
-
-/** @brief Write single character to the display using the 8x8 fontable
- *  @brief Start at current cursor location
- *  @param char chr character to write
-*/
-void SSD1308::writeChar(char chr) {
-
-  const uint8_t char_index = chr - 0x20;
-
-  for (uint8_t i = 0; i < 8; i++) {
-     if (_inverted) {
-       _sendData( ~font_8x8[char_index][i] );           
-     }
-     else {
-       _sendData( font_8x8[char_index][i] );
-     }  
-  }
-
-}
-
-
-/** @brief Write a string to the display using the 8x8 font
- *  @brief Start at selected cursor location, text will wrap around until it is done
- *  @param uint8_t row  row number    (0...ROWS/FONT_HEIGHT)
- *  @param uint8_t col  column number (0...COLUMNS/FONT_WIDTH)
- *  @param const char * text pointer to text
- */
-void SSD1308::writeString(uint8_t row, uint8_t col, const char * text) {
-  uint16_t index = 0;
-  uint16_t len = strlen(text);
-  
-  setPageAddress(row, MAX_PAGE);
-  const uint8_t col_addr = FONT8x8_WIDTH*col;
-  setColumnAddress(col_addr, MAX_COL);
-
-  while ((col+index) < CHARS && (index < len)) {
-     // write first line, starting at given position
-     writeChar(text[index++]);
-  }
-
-  // write remaining lines
-  // write until the end of memory
-  // then wrap around again from the top.
-  if (index + 1 < len) {
-    setPageAddress(row + 1, MAX_PAGE);
-    setColumnAddress(0, MAX_COL);
-    bool wrapEntireScreen = false;
-    while (index + 1 < len) {
-       writeChar(text[index++]);
-       // if we've written the last character space on the screen, 
-       // reset the page and column address so that it wraps around from the top again
-       if (!wrapEntireScreen && (row*CHARS + col + index) > 127) {
-         setPageAddress(0, MAX_PAGE);
-         setColumnAddress(0, MAX_COL);
-         wrapEntireScreen = true;
-       }
-    }
-  }
-}
-
-
-
-/** @brief Write large character (16x24 font)
- *  @param uint8_t row  row number    (0...MAX_ROW)
- *  @param uint8_t col  column number (0...MAX_COL)
- *  @param char chr     Used for displaying numbers 0 - 9 and '+', '-', '.'
- */
-void SSD1308::writeBigChar(uint8_t row, uint8_t col, char chr) {
-
-  writeBitmap((uint8_t*) font_16x24[int(chr) - FONT16x24_START],
-              row, (row + FONT16x24_BYTES - 1),
-              col, (col + FONT16x24_WIDTH - 1));
-}
-
-
-/** @brief Write command that has no parameters
-*/ 
-void SSD1308::_sendCommand(uint8_t command) {
-//  I2Cdev::writeByte(m_devAddr, COMMAND_MODE, command);
-
-#if (I2C_OPTIMIZE == 0)
-  char databytes[2];
-    
-  databytes[0] = COMMAND_MODE;
-  databytes[1] = command;    
-  _i2c.write(_writeOpcode, databytes, 2);    // Write command   
-#else  
-
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(command);       // Write Command   
-
-  _i2c.stop();  
-#endif
-}
-
-/** @brief Write command that has one parameter
-*/ 
-void SSD1308::_sendCommand(uint8_t command, uint8_t param1) {
-
-//  Note continuationbit is set, so COMMAND_MODE must be
-//  repeated before each databyte that serves as parameter!
-#if (I2C_OPTIMIZE == 0)
-  char databytes[4];
-    
-  databytes[0] = COMMAND_MODE;
-  databytes[1] = command;    
-  databytes[2] = COMMAND_MODE;
-  databytes[3] = param1; 
-  _i2c.write(_writeOpcode, databytes, 4);    // Write command   
-#else  
-
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(command);       // Write Command   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param1);        // Write Param1   
-
-  _i2c.stop();
-#endif  
-}
-
-/** @brief Write command that has two parameters
-*/ 
-void SSD1308::_sendCommand(uint8_t command, uint8_t param1, uint8_t param2) {
-
-//  Note continuationbit is set, so COMMAND_MODE must be
-//  repeated before each databyte that serves as parameter!
-#if (I2C_OPTIMIZE == 0)
-  char databytes[6];
-    
-  databytes[0] = COMMAND_MODE;
-  databytes[1] = command;    
-  databytes[2] = COMMAND_MODE;
-  databytes[3] = param1; 
-  databytes[4] = COMMAND_MODE;
-  databytes[5] = param2; 
-  _i2c.write(_writeOpcode, databytes, 6);    // Write command   
-#else  
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(command);       // Write Command   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param1);        // Write Param1   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param2);        // Write Param2   
-
-  _i2c.stop();
- #endif 
-}
-
-/** @brief Write command that has five parameters
-*/ 
-void SSD1308::_sendCommand(uint8_t command, uint8_t param1, uint8_t param2,
-                                            uint8_t param3, uint8_t param4,
-                                            uint8_t param5) {
-
-//  Note continuationbit is set, so COMMAND_MODE must be
-//  repeated before each databyte that serves as parameter!
-#if (I2C_OPTIMIZE == 0)
-  char databytes[12];
-    
-  databytes[0] = COMMAND_MODE;
-  databytes[1] = command;    
-  databytes[2] = COMMAND_MODE;
-  databytes[3] = param1; 
-  databytes[4] = COMMAND_MODE;
-  databytes[5] = param2; 
-  databytes[6] = COMMAND_MODE;
-  databytes[7] = param3; 
-  databytes[8] = COMMAND_MODE;
-  databytes[9] = param4; 
-  databytes[10] = COMMAND_MODE;
-  databytes[11] = param5;       
-  _i2c.write(_writeOpcode, databytes, 12);    // Write command   
-#else  
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(command);       // Write Command   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param1);        // Write Param1   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param2);        // Write Param2   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param3);        // Write Param3   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param4);        // Write Param4   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param5);        // Write Param5   
-
-  _i2c.stop();
-#endif  
-}
-
-
-/** @brief Write command that has six parameters
-*/ 
-void SSD1308::_sendCommand(uint8_t command, uint8_t param1, uint8_t param2,
-                                            uint8_t param3, uint8_t param4,
-                                            uint8_t param5, uint8_t param6) {
-
-//  Note continuationbit is set, so COMMAND_MODE must be
-//  repeated before each databyte that serves as parameter!
-#if (I2C_OPTIMIZE == 0)
-  char databytes[14];
-    
-  databytes[0] = COMMAND_MODE;
-  databytes[1] = command;    
-  databytes[2] = COMMAND_MODE;
-  databytes[3] = param1; 
-  databytes[4] = COMMAND_MODE;
-  databytes[5] = param2; 
-  databytes[6] = COMMAND_MODE;
-  databytes[7] = param3; 
-  databytes[8] = COMMAND_MODE;
-  databytes[9] = param4; 
-  databytes[10] = COMMAND_MODE;
-  databytes[11] = param5;   
-  databytes[12] = COMMAND_MODE;
-  databytes[13] = param6;       
-  _i2c.write(_writeOpcode, databytes, 14);    // Write command   
-#else  
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(command);       // Write Command   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param1);        // Write Param1   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param2);        // Write Param2   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param3);        // Write Param3   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param4);        // Write Param4   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param5);        // Write Param5   
-  _i2c.write(COMMAND_MODE);      
-  _i2c.write(param6);        // Write Param6   
-
-  _i2c.stop();
-#endif  
-}
-
-
-#if(0)
-/** @brief Write command that has multiple parameters
-*/ 
-void SSD1308::_sendCommands(uint8_t len, uint8_t* commands) {
-
-//  I2Cdev::writeBytes(m_devAddr, COMMAND_MODE, len, commands);
-//  Note this original code is not correct, continuationbit is set, 
-//  so COMMAND_MODE must be repeated before each databyte that serves as parameter!
-
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  
-  for (int i=0; i<len ; i++) {
-    _i2c.write(COMMAND_MODE);      
-    _i2c.write(commands[i]);  // Write Commands   
-  }
-  _i2c.stop();
-  
-}
-#endif
-
-/** @brief Write databyte to display
- *  @brief Start at current cursor location
- *  @param uint8_t data databyte to write
-*/
-void SSD1308::_sendData(uint8_t data){
-
-#if (I2C_OPTIMIZE == 0)
-//I2C Blockwrite versions dont seem to work ?
-//That may be related to fact that the SSD1308/SSD1306 does NOT return an acknowledge: blockwrite may abort the operation
-//Noted for mbed lib v63 on 20/7/13 
-  char databytes[2];
-    
-  databytes[0] = DATA_MODE;
-  databytes[1] = data;    
-  _i2c.write(_writeOpcode, databytes, 2);    // Write Data   
-
-#else
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  _i2c.write(DATA_MODE);  
-  _i2c.write(data); 
-  _i2c.stop();  
-#endif
-
-}
-
-/** @brief Write len bytes from buffer data to display, 
- *  @brief Start at current cursor location
- *  @param uint8_t len number of bytes to write 
- *  @param uint8_t* data pointer to data
-*/
-void SSD1308::_sendData(uint8_t len, uint8_t* data) {
-//  I2Cdev::writeBytes(m_devAddr, DATA_MODE, len, data);
-#if (I2C_OPTIMIZE == 0)
-  for (int i=0; i<len ; i++) {
-    _sendData(data[i]);  // Write Data   
-  }
-#else  
-  _i2c.start();
-  _i2c.write(_writeOpcode);
-  _i2c.write(DATA_MODE);  
-  for (int i=0; i<len ; i++) {
-    _i2c.write(data[i]);  // Write Data   
-  }
-  _i2c.stop();
-#endif 
-}
-
-
-/** @brief Set Horizontal Addressing Mode (cursor incr left-to-right, top-to-bottom)
- * 
- */
-void SSD1308::setHorizontalAddressingMode(){
-  setMemoryAddressingMode(HORIZONTAL_ADDRESSING_MODE); 
-}
-
-/** @brief Set Vertical Addressing Mode  (cursor incr top-to-bottom, left-to-right)
- * 
- */
-void SSD1308::setVerticalAddressingMode() {
-  setMemoryAddressingMode(VERTICAL_ADDRESSING_MODE); 
-}
-
-/** @brief Set Page Addressing Mode  (cursor incr left-to-right)
- * 
- */
-void SSD1308::setPageAddressingMode(){
-  setMemoryAddressingMode(PAGE_ADDRESSING_MODE); 
-}
-    
-/** @brief Set Addressing Mode
- *  @param uint8_t mode 
- */
-void SSD1308::setMemoryAddressingMode(uint8_t mode){
-
-  _sendCommand(SET_MEMORY_ADDRESSING_MODE, mode);   
-}
-
-
-/** @param uint8_t start startpage (valid range 0..MAX_PAGE)
- *  @param uint8_t end   endpage   (valid range start..MAX_PAGE)
- */
-void SSD1308::setPageAddress(uint8_t start, uint8_t end) {
-
-  _sendCommand(SET_PAGE_ADDRESS, start, end);   
-}
-
-
-/** @param uint8_t start startcolumn (valid range 0..MAX_COL)
- *  @param uint8_t end   endcolumn   (valid range start..MAX_COL)
- */
-void SSD1308::setColumnAddress(uint8_t start, uint8_t end) {
-
-  _sendCommand(SET_COLUMN_ADDRESS, start, end);     
-}
-
-/** 
- *  @brief Set Display StartLine, takes one byte, 0x00-0x3F
- *  @param uint8_t line startline (valid range 0..MAX_ROWS)
- */  
-void SSD1308::setDisplayStartLine(uint8_t line) {
-
-  line = line & MAX_ROW;
-   
-  _sendCommand(SET_DISPLAY_START_LINE | line);     
-}
-
-
-/** 
- *  @brief Set Column Start (for Page Addressing Mode only)
- *  @param uint8_t column column start (valid range 0..MAX_COL)
- */  
-void SSD1308::setColumnStartForPageAddressingMode(uint8_t column) {
-
-  column = column & MAX_COL;
-
-  _sendCommand(SET_LOWER_COLUMN  | ( column     & 0x0F));  // lower nibble   
-  _sendCommand(SET_HIGHER_COLUMN | ((column>>4) & 0x0F));  // higher nibble     
-}
-
-
-/** 
- *  @brief Set Page Start (for Page Addressing Mode only)
- *  @param uint8_t page page start (valid range PAGE0 - PAGE7)
- */    
-void SSD1308::setPageStartForPageAddressingMode(uint8_t page) {
-
-  page = page & MAX_PAGE;
-
-  _sendCommand(SET_PAGE_START_ADDRESS | page);
- 
-}
-
-
-/** @brief Set Contrast
- *  @param uint8_t contrast (valid range 0x00 (lowest) - 0xFF (highest))
-*/
-void SSD1308::setContrastControl(uint8_t contrast) {
-  
-    _sendCommand(SET_CONTRAST, contrast);  
-} 
-
-/** @brief Enable Display
-*/ 
-void SSD1308::setDisplayOn() {
-  _sendCommand(SET_DISPLAY_POWER_ON);
-}
-
-/** @brief Disable Display
-*/ 
-void SSD1308::setDisplayOff() {
-  _sendCommand(SET_DISPLAY_POWER_OFF);
-}
-
-/** @brief Enable or Disable Display
- *  @param bool on
- */
-void SSD1308::setDisplayPower(bool on) {
-  if (on) {
-    setDisplayOn();
-  } else {
-    setDisplayOff();
-  }
-}
-
-/** @brief Show White pixels on Black background
- */ 
-void SSD1308::setDisplayNormal() {
-  _sendCommand(SET_NORMAL_DISPLAY);
-}
-
-/** @brief Show Black pixels on White background
- */ 
-void SSD1308::setDisplayInverse() {
-  _sendCommand(SET_INVERSE_DISPLAY);
-}
-
-/** @brief Blink display by fading in and out over a set number of frames
- *  @param bool on
- */
-void SSD1308::setDisplayBlink(bool on){
-  if (on) {
-    _sendCommand(SET_FADE_BLINK, (BLINK_ENABLE | FADE_INTERVAL_128_FRAMES));
-  }
-  else {  
-    _sendCommand(SET_FADE_BLINK, FADE_BLINK_DISABLE);  
-  }
-}       
-
-
-/** @brief Fade out display in set number of frames
- *  @param bool on
- */
-void SSD1308::setDisplayFade(bool on) {
-  if (on) {
-    _sendCommand(SET_FADE_BLINK, (FADE_OUT_ENABLE | FADE_INTERVAL_128_FRAMES));
-  }
-  else {  
-    _sendCommand(SET_FADE_BLINK, FADE_BLINK_DISABLE);  
-  }
-}    
-
-/** @brief Display Flip (Left/Right, Up/Down)
- *  @param bool left flip Left/Right
- *  @param bool down flip Up/Down
- */
-void SSD1308::setDisplayFlip(bool left, bool down) {
-  if (left) {
-    // column address   0 is mapped to SEG0 (Reset)    
-    _sendCommand(SET_SEGMENT_REMAP_0);
-  }
-  else {
-    // column address 127 is mapped to SEG0    
-    _sendCommand(SET_SEGMENT_REMAP_127);
-  }  
-
-  if (down) {
-    // Reset mode
-    _sendCommand(SET_COMMON_REMAP_0);    
-  }
-  else {
-    // Flip Up/Down (Need to rewrite display before H effect shows)
-    _sendCommand(SET_COMMON_REMAP_63);        
-  }  
-
-}
-
-/** @brief Sets Internal Iref
- */
-void SSD1308::setInternalIref() {
-//  uint8_t cmds[2] = {SET_IREF_SELECTION, INTERNAL_IREF};
-//  _sendCommands(2, cmds); 
-  
-  _sendCommand(SET_IREF_SELECTION, INTERNAL_IREF);   
-}
-
-/** @brief Sets External Iref (default)
- */
-void SSD1308::setExternalIref() {
-//  uint8_t cmds[2] = {SET_IREF_SELECTION, EXTERNAL_IREF};
-//  _sendCommands(2, cmds); 
-  _sendCommand(SET_IREF_SELECTION, EXTERNAL_IREF); 
-}
-
-
-/** @brief Shows All Pixels On
- */
-void SSD1308::setEntireDisplayOn(){
-  _sendCommand(SET_ENTIRE_DISPLAY_ON); 
-}
-
-/** @brief Shows Pixels as RAM content
- */
-void SSD1308::setEntireDisplayRAM(){
-  _sendCommand(SET_DISPLAY_GDDRAM); 
-}
-
-/** @brief Shows Pixels On or as RAM content
- *  @param bool on (true is All on, false is RAM content)
- */
-void SSD1308::setEntireDisplay(bool on){
-  if (on) {
-    setEntireDisplayOn();  // All Pixels on
-  }
-  else {  
-    setEntireDisplayRAM(); // Pixels are RAM content
-  }
-}
-
-
-/** @brief Horizontal scroll by one column per interval
- *  @param bool left select Left/Right scroll
- *  @param uint8_t start_page begin page   (0..MAX_PAGE)
- *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)                     
- *  @param uint8_t interval   scroll interval in frames (see codes above)                      
- */  
-void SSD1308::setContinuousHorizontalScroll(bool left, uint8_t start_page, uint8_t end_page, uint8_t interval) {
-  if (left) {
-    _sendCommand(SET_LEFT_HOR_SCROLL, 0x00, start_page, interval, end_page, 0x00, 0xFF);  // Scroll Left
-  }
-  else {  
-    _sendCommand(SET_RIGHT_HOR_SCROLL, 0x00, start_page, interval, end_page, 0x00, 0xFF); // Scroll Right  
-  }
-
-}
-
-
-/** @brief Horizontal and Vertical scroll by one column per interval
- *  @param bool left select Left/Right scroll
- *  @param uint8_t start_page begin page   (0..MAX_PAGE)
- *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)                     
- *  @param uint8_t offset     vert offset  (0x01..0x63)                       
- *  @param uint8_t interval   scroll interval in frames (see codes above)                       
- */  
-void SSD1308::setContinuousVerticalAndHorizontalScroll(bool left, uint8_t start_page, uint8_t end_page, 
-                                                       uint8_t offset, uint8_t interval) {
-  if (left) {
-    _sendCommand(SET_VERT_LEFT_HOR_SCROLL, 0x00, start_page, interval, end_page, offset);  // Scroll Left
-  }
-  else {  
-    _sendCommand(SET_VERT_RIGHT_HOR_SCROLL, 0x00, start_page, interval, end_page, offset); // Scroll Right  
-  }
-                                                       
-}    
-
-/** @brief Set Vertical scroll area
- *  @param uint8_t topRowsFixed      fixed rows   (0..MAX_ROW)                     
- *  @param uint8_t scrollRowsoffset  scroll rows  (topRowsFixed..ROWS)                       
- */  
-void SSD1308::setVerticalScrollArea(uint8_t topRowsFixed, uint8_t scrollRows) { 
-   
-  if ((topRowsFixed + scrollRows) > ROWS) {
-     scrollRows = ROWS - topRowsFixed; 
-  };
-  
-  _sendCommand(SET_VERTICAL_SCROLL_AREA, topRowsFixed, scrollRows); 
-}
-
-/** @brief Activate or Deactivate Horizontal and Vertical scroll
- *  @brief Note: after deactivating scrolling, the RAM data needs to be rewritten
- *  @param bool on activate scroll 
- */  
-void SSD1308::setDisplayScroll(bool on) {
-  if (on) {
-    _sendCommand(SET_ACTIVATE_SCROLL);   // Scroll on
-  }
-  else {  
-    _sendCommand(SET_DEACTIVATE_SCROLL); // Scroll off  
-  }
-}
-
-
-
-/** @brief Low level Init
- *  @brief Init the configuration registers in accordance with the datasheet
- */
-void SSD1308::_init() {
-
-  _sendCommand(SET_DISPLAY_POWER_OFF);      // 0xAE
-  
-  // column address   0 is mapped to SEG0 (Reset)    
-  // row address   0 is mapped to COM0 (Reset)      
-  _sendCommand(SET_SEGMENT_REMAP_0);        // 0xA0 (Reset)
-  _sendCommand(SET_COMMON_REMAP_0);         // 0xC0 (Reset) 
-
-  setDisplayStartLine(0);                   // 0x40 (Reset) 
-  
-  _sendCommand(SET_COMMON_CONF, COMMON_BASE | COMMON_ALTERNATIVE | COMMON_LEFTRIGHT_NORMAL); // 0xDA, 0x12 (Reset)
-
-  // Pagemode or Horizontal mode
-//  setPageAddressingMode();                  // 0x20, 0x02 (Reset)  
-//  setColumnStartForPageAddressingMode(0);   // 0x00, 0x10 (Reset = Column 0)
-//  setPageStartForPageAddressingMode(PAGE_0);// 0xBO       (Reset = Page 0)
-  setHorizontalAddressingMode();            // 0x20, 0x00 (Non-Reset)
-  setColumnAddress(0, MAX_COL);             // 0x21, 0x00, 0x37 (Reset)
-  setPageAddress(0, MAX_PAGE);              // 0x22, 0x00, 0x07 (Reset)
-
-  setExternalIref();                        // 0xAD, 0x10 (Reset)
-  
-  _sendCommand(SET_DISPLAY_CLOCK, 0x70);    // 0xD5, 0x70 (Reset = 0x80)
-  _sendCommand(SET_PRECHARGE_TIME, 0x21);   // 0xD9, 0x21 (Reset = 0x22)
-  _sendCommand(SET_VCOMH_DESELECT_LEVEL, 0x30); // 0xDB, 0x30 (Reset = 0x20)  
-  _sendCommand(SET_MULTIPLEX_RATIO, 0x3F);  // 0xA8, 0x3F (Reset)  
-  _sendCommand(SET_DISPLAY_OFFSET, 0x00);   // 0xD3, 0x00 (Reset)  
-  
-  _sendCommand(SET_CONTRAST, 0x7F);         // 0x81, 0x7F (Reset)
-
-  _sendCommand(SET_NORMAL_DISPLAY);         // 0xA6 (Reset)
-  
-  setEntireDisplayRAM();                    // 0xA4 (Reset)
-  setDisplayScroll(false);
-  
-  clearDisplay();   
-  
-  _sendCommand(SET_DISPLAY_POWER_ON);       // 0xAF
-}
-
+/**  @file SSD1308 I2C device class file
+ *   Based on Solomon Systech SSD1308 datasheet, rev. 1, 10/2008
+ *   The SSD1308 is used for example in the Seeed 128x64 OLED Display
+ *   http://www.seeedstudio.com/depot/grove-oled-display-12864-p-781.html?cPath=163_167
+*/
+// The original code by Andrew Schamp is using (and has been submitted as a part of) Jeff Rowberg's I2Cdevlib library,
+// which should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
+// Some parts also mashed up from Graphic Library for driving monochrome displays based on the PCD8544,
+// Copyright (c) 2011, Wim De Roeve, who in turn did partial port of code found on
+// http://serdisplib.sourceforge.net/ser/pcd8544.html#links and by Petras Saduikis <petras@petras.co.uk>
+//
+// Changelog:
+//   2011-08-25 - Initial release by Andrew Schamp <schamp@gmail.com>
+//   2012-06-19 - Ported to mbed and optimised (WH)
+//   2013-07-12 - Minor comment fix and placeholder for SSD1306 (WH)
+//   2015-01-01 - Switch for optimised I2C calls to test on F401 (WH)
+//
+/*
+================================================================================
+I2Cdev device library code is placed under the MIT license
+Copyright (c) 2011 Andrew Schamp
+Copyright (c) 2012,2013 WH (mbed port)
+
+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.
+================================================================================
+*/
+#include "mbed.h"
+#include "SSD1308.h"
+
+//#include "font_3x5.h"
+//#include "font_5x7.h"
+//#include "font_6x8.h"
+#include "font_8x8.h"
+//#include "font_8x12.h"
+//#include "font_16x20.h"
+#include "font_16x24.h"
+
+#if defined(TARGET_LPC1768)
+#define I2C_OPTIMIZE   1
+#else
+#define I2C_OPTIMIZE   0
+#endif
+
+/**
+ *@brief Constructor
+ *@param I2C &i2c reference to i2c
+ *@param uint8_t deviceAddress slaveaddress
+ */
+SSD1308::SSD1308(I2C &i2c, uint8_t deviceAddress) : _i2c(i2c) {
+
+    _writeOpcode = deviceAddress & 0xFE; // low order bit = 0 for write
+    _readOpcode  = deviceAddress | 0x01; // low order bit = 1 for read
+
+    initialize();
+}
+
+/** @brief High level Init, most settings remain at Power-On reset value
+ */
+void SSD1308::initialize() {
+    setHorizontalAddressingMode();
+
+    clearDisplay();
+
+    setInverted(false);
+
+    setDisplayOn();
+}
+
+
+/** @brief clear the display
+*/
+#if (I2C_OPTIMIZE == 0)
+// Standard version
+void SSD1308::clearDisplay() {
+
+    //setDisplayOff();
+    setPageAddress(0, MAX_PAGE);  // all pages
+    setColumnAddress(0, MAX_COL); // all columns
+
+    for (uint8_t page = 0; page < PAGES; page++) {
+        for (uint8_t col = 0; col < COLUMNS; col++) {
+            _sendData(0x00);
+        }
+    }
+
+    //setDisplayOn();
+}
+#else
+//Optimised version
+// Save lots of I2C S,P, address and datacommands:
+// Send S, address, DATA_MODE, data, data, data,...., P
+//
+void SSD1308::clearDisplay() {
+
+    //setDisplayOff();
+
+    setPageAddress(0, MAX_PAGE);  // all pages
+    setColumnAddress(0, MAX_COL); // all columns
+
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+    _i2c.write(DATA_MODE);
+    for (int i=0; i<(PAGES * COLUMNS); i++) {
+        _i2c.write(0x00);  // Write Data
+    }
+    _i2c.stop();
+
+    //setDisplayOn();
+}
+#endif
+
+
+/** @brief fill the display
+ *  @param uint8_t pattern fillpattern vertical patch or 8 bits
+ *  @param uint8_t start_page begin page   (0..MAX_PAGE)
+ *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)
+ *  @param uint8_t start_col  begin column (0..MAX_COL)
+ *  @param uint8_t end_col    end column   (start_col..MAX_COL)
+*/
+#if (I2C_OPTIMIZE == 0)
+//Standard version
+
+void SSD1308::fillDisplay(uint8_t pattern,
+                          uint8_t start_page, uint8_t end_page,
+                          uint8_t start_col, uint8_t end_col) {
+
+    int count = (end_page - start_page + 1) * (end_col - start_col + 1);
+
+    //setDisplayOff();
+    setPageAddress(start_page, end_page);  // set page window
+    setColumnAddress(start_col, end_col);  // set column window
+
+    for (int i=0; i<count; i++) {
+        _sendData(pattern); // Write Data
+    }
+
+    //setDisplayOn();
+}
+
+#else
+
+//Optimised version
+// Save lots of I2C S,P, address and datacommands:
+// Send S, address, DATA_MODE, data, data, data,...., P
+//
+void SSD1308::fillDisplay(uint8_t pattern,
+                          uint8_t start_page, uint8_t end_page,
+                          uint8_t start_col, uint8_t end_col) {
+
+    int count = (end_page - start_page + 1) * (end_col - start_col + 1);
+
+    //setDisplayOff();
+    setPageAddress(start_page, end_page);  // set page window
+    setColumnAddress(start_col, end_col);  // set column window
+
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+    _i2c.write(DATA_MODE);
+    for (int i=0; i<count; i++) {
+        _i2c.write(pattern);  // Write Data
+    }
+    _i2c.stop();
+
+    //setDisplayOn();
+}
+
+#endif
+
+
+/** @brief write a bitmap to the display
+ *  @param uint8_t* data pointer to bitmap
+ *  @param uint8_t start_page begin page   (0..MAX_PAGE)
+ *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)
+ *  @param uint8_t start_col  begin column (0..MAX_COL)
+ *  @param uint8_t end_col    end column   (start_col..MAX_COL)
+*/
+#if (I2C_OPTIMIZE == 0)
+//Standard version
+void SSD1308::writeBitmap(uint8_t* data,
+                          uint8_t start_page, uint8_t end_page,
+                          uint8_t start_col, uint8_t end_col) {
+
+    int count = (end_page - start_page + 1) * (end_col - start_col + 1);
+
+    //setDisplayOff();
+    setPageAddress(start_page, end_page);  // set page window
+    setColumnAddress(start_col, end_col);  // set column window
+
+    for (int i=0; i<count; i++) {
+        _sendData(data[i]); // Write Data
+    }
+
+    //setDisplayOn();
+}
+
+#else
+//Optimised version
+// Save lots of I2C S,P, address and datacommands:
+// Send S, address, DATA_MODE, data, data, data,...., P
+//
+void SSD1308::writeBitmap(uint8_t* data,
+                          uint8_t start_page, uint8_t end_page,
+                          uint8_t start_col, uint8_t end_col) {
+
+    int count = (end_page - start_page + 1) * (end_col - start_col + 1);
+
+    //setDisplayOff();
+    setPageAddress(start_page, end_page);  // set page window
+    setColumnAddress(start_col, end_col);  // set column window
+
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+    _i2c.write(DATA_MODE);
+    for (int i=0; i<count; i++) {
+        _i2c.write(data[i]);  // Write Data
+    }
+    _i2c.stop();
+
+    //setDisplayOn();
+}
+
+#endif
+
+
+/** @brief write a progressbar to the display, Width is (PRG_MAX_SCALE + 2) pixels
+ *  @param uint8_t page begin page   (0..MAX_PAGE)
+ *  @param uint8_t col  begin column (0..MAX_COL)
+ *  @param int percentage value      (0..100)
+*/
+#define PRG_MAX_SCALE     50
+#define PRG_LEFT_EDGE   0xFF
+#define PRG_RIGHT_EDGE  0xFF
+#define PRG_ACTIVE      0xFF
+//#define PRG_ACTIVE      0xBD
+#define PRG_NOT_ACTIVE  0x81
+
+#if (I2C_OPTIMIZE == 0)
+//Standard version
+void SSD1308::writeProgressBar(uint8_t page, uint8_t col, int percentage) {
+    uint8_t scale_value;
+
+    if (percentage <= 0) {
+        scale_value = 0;
+    } else if (percentage >= 100) {
+        scale_value = PRG_MAX_SCALE - 1;
+    } else {
+        scale_value = (percentage * PRG_MAX_SCALE) / 100;
+    }
+
+    //setDisplayOff();
+    setPageAddress(page, page);
+    setColumnAddress(col, MAX_COL);
+
+    _sendData(PRG_LEFT_EDGE);
+
+    for (uint8_t col = 0; col < scale_value; col++) {
+        _sendData(PRG_ACTIVE);
+    }
+
+    _sendData(PRG_ACTIVE);
+
+    for (uint8_t col = (scale_value+1); col < PRG_MAX_SCALE; col++) {
+        _sendData(PRG_NOT_ACTIVE);
+    }
+
+    _sendData(PRG_RIGHT_EDGE);
+
+    //setDisplayOn();
+}
+#else
+
+//Optimised version
+// Save lots of I2C S,P, address and datacommands:
+// Send S, address, DATA_MODE, data, data, data,...., P
+//
+void SSD1308::writeProgressBar(uint8_t page, uint8_t col, int percentage) {
+    uint8_t scale_value;
+
+    if (percentage <= 0) {
+        scale_value = 0;
+    } else if (percentage >= 100) {
+        scale_value = PRG_MAX_SCALE - 1 ;
+    } else {
+        scale_value = (percentage * PRG_MAX_SCALE) / 100;
+    }
+
+    //setDisplayOff();
+    setPageAddress(page, page);
+    setColumnAddress(col, MAX_COL);
+
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+    _i2c.write(DATA_MODE);
+
+    _i2c.write(PRG_LEFT_EDGE);  // Write Data
+
+    for (uint8_t col = 0; col < scale_value; col++) {
+        _i2c.write(PRG_ACTIVE);  // Write Data
+    }
+
+    _i2c.write(PRG_ACTIVE);  // Write Data
+
+    for (uint8_t col = (scale_value+1); col < PRG_MAX_SCALE; col++) {
+        _i2c.write(PRG_NOT_ACTIVE);  // Write Data
+    }
+
+    _i2c.write(PRG_RIGHT_EDGE);  // Write Data
+
+    _i2c.stop();
+
+    //setDisplayOn();
+}
+#endif
+
+/** @brief write a level meter to the display, Width is (PRG_MAX_SCALE + 2) pixels
+ *  @param uint8_t page begin page   (0..MAX_PAGE)
+ *  @param uint8_t col  begin column (0..MAX_COL)
+ *  @param int percentage value      (0..100)
+*/
+#if (I2C_OPTIMIZE == 0)
+void SSD1308::writeLevelBar(uint8_t page, uint8_t col, int percentage) {
+    uint8_t scale_value;
+
+    if (percentage <= 0) {
+        scale_value = 0;
+    } else if (percentage >= 100) {
+        scale_value = PRG_MAX_SCALE - 1;
+    } else {
+        scale_value = (percentage * PRG_MAX_SCALE) / 100;
+    }
+
+    //setDisplayOff();
+    setPageAddress(page, page);
+    setColumnAddress(col, MAX_COL);
+
+    _sendData(PRG_LEFT_EDGE);
+
+    for (uint8_t col = 0; col < scale_value; col++) {
+        _sendData(PRG_NOT_ACTIVE);  // Write Data
+    }
+
+    _sendData(PRG_ACTIVE);  // Write Data at active meterlevel
+
+    for (uint8_t col = scale_value+1; col < PRG_MAX_SCALE; col++) {
+        _sendData(PRG_NOT_ACTIVE);
+    }
+
+    _sendData(PRG_RIGHT_EDGE);
+
+    //setDisplayOn();
+}
+#else
+//Optimised version
+// Save lots of I2C S,P, address and datacommands:
+// Send S, address, DATA_MODE, data, data, data,...., P
+//
+void SSD1308::writeLevelBar(uint8_t page, uint8_t col, int percentage) {
+    uint8_t scale_value;
+
+    if (percentage <= 0) {
+        scale_value = 0;
+    } else if (percentage >= 100) {
+        scale_value = PRG_MAX_SCALE - 1;
+    } else {
+        scale_value = (percentage * PRG_MAX_SCALE) / 100;
+    }
+
+    //setDisplayOff();
+    setPageAddress(page, page);
+    setColumnAddress(col, MAX_COL);
+
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+    _i2c.write(DATA_MODE);
+
+    _i2c.write(PRG_LEFT_EDGE);  // Write Data
+
+    for (uint8_t col = 0; col < scale_value; col++) {
+        _i2c.write(PRG_NOT_ACTIVE);  // Write Data
+    }
+
+    _i2c.write(PRG_ACTIVE);  // Write Data at active meterlevel
+
+    for (uint8_t col = scale_value+1; col < PRG_MAX_SCALE; col++) {
+        _i2c.write(PRG_NOT_ACTIVE);  // Write Data
+    }
+
+    _i2c.write(PRG_RIGHT_EDGE);  // Write Data
+
+    _i2c.stop();
+
+    //setDisplayOn();
+}
+#endif
+
+/** @brief Write single character to the display using the 8x8 fontable
+ *  @brief Start at current cursor location
+ *  @param char chr character to write
+*/
+void SSD1308::writeChar(char chr) {
+
+    const uint8_t char_index = chr - 0x20;
+
+    for (uint8_t i = 0; i < 8; i++) {
+        if (_inverted) {
+            _sendData( ~font_8x8[char_index][i] );
+        } else {
+            _sendData( font_8x8[char_index][i] );
+        }
+    }
+
+}
+
+
+/** @brief Write a string to the display using the 8x8 font
+ *  @brief Start at selected cursor location, text will wrap around until it is done
+ *  @param uint8_t row  row number    (0...ROWS/FONT_HEIGHT)
+ *  @param uint8_t col  column number (0...COLUMNS/FONT_WIDTH)
+ *  @param const char * text pointer to text
+ */
+void SSD1308::writeString(uint8_t row, uint8_t col, const char * text) {
+    uint16_t index = 0;
+    uint16_t len = strlen(text);
+
+    setPageAddress(row, MAX_PAGE);
+    const uint8_t col_addr = FONT8x8_WIDTH*col;
+    setColumnAddress(col_addr, MAX_COL);
+
+    while ((col+index) < CHARS && (index < len)) {
+        // write first line, starting at given position
+        writeChar(text[index++]);
+    }
+
+    // write remaining lines
+    // write until the end of memory
+    // then wrap around again from the top.
+    if (index + 1 < len) {
+        setPageAddress(row + 1, MAX_PAGE);
+        setColumnAddress(0, MAX_COL);
+        bool wrapEntireScreen = false;
+        while (index + 1 < len) {
+            writeChar(text[index++]);
+            // if we've written the last character space on the screen,
+            // reset the page and column address so that it wraps around from the top again
+            if (!wrapEntireScreen && (row*CHARS + col + index) > 127) {
+                setPageAddress(0, MAX_PAGE);
+                setColumnAddress(0, MAX_COL);
+                wrapEntireScreen = true;
+            }
+        }
+    }
+}
+
+
+
+/** @brief Write large character (16x24 font)
+ *  @param uint8_t row  row number    (0...MAX_ROW)
+ *  @param uint8_t col  column number (0...MAX_COL)
+ *  @param char chr     Used for displaying numbers 0 - 9 and '+', '-', '.'
+ */
+void SSD1308::writeBigChar(uint8_t row, uint8_t col, char chr) {
+
+    writeBitmap((uint8_t*) font_16x24[int(chr) - FONT16x24_START],
+                row, (row + FONT16x24_BYTES - 1),
+                col, (col + FONT16x24_WIDTH - 1));
+}
+
+
+/** @brief Write command that has no parameters
+*/
+void SSD1308::_sendCommand(uint8_t command) {
+//  I2Cdev::writeByte(m_devAddr, COMMAND_MODE, command);
+
+#if (I2C_OPTIMIZE == 0)
+    char databytes[2];
+
+    databytes[0] = COMMAND_MODE;
+    databytes[1] = command;
+    _i2c.write(_writeOpcode, databytes, 2);    // Write command
+#else
+
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(command);       // Write Command
+
+    _i2c.stop();
+#endif
+}
+
+/** @brief Write command that has one parameter
+*/
+void SSD1308::_sendCommand(uint8_t command, uint8_t param1) {
+
+//  Note continuationbit is set, so COMMAND_MODE must be
+//  repeated before each databyte that serves as parameter!
+#if (I2C_OPTIMIZE == 0)
+    char databytes[4];
+
+    databytes[0] = COMMAND_MODE;
+    databytes[1] = command;
+    databytes[2] = COMMAND_MODE;
+    databytes[3] = param1;
+    _i2c.write(_writeOpcode, databytes, 4);    // Write command
+#else
+
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(command);       // Write Command
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param1);        // Write Param1
+
+    _i2c.stop();
+#endif
+}
+
+/** @brief Write command that has two parameters
+*/
+void SSD1308::_sendCommand(uint8_t command, uint8_t param1, uint8_t param2) {
+
+//  Note continuationbit is set, so COMMAND_MODE must be
+//  repeated before each databyte that serves as parameter!
+#if (I2C_OPTIMIZE == 0)
+    char databytes[6];
+
+    databytes[0] = COMMAND_MODE;
+    databytes[1] = command;
+    databytes[2] = COMMAND_MODE;
+    databytes[3] = param1;
+    databytes[4] = COMMAND_MODE;
+    databytes[5] = param2;
+    _i2c.write(_writeOpcode, databytes, 6);    // Write command
+#else
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(command);       // Write Command
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param1);        // Write Param1
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param2);        // Write Param2
+
+    _i2c.stop();
+#endif
+}
+
+/** @brief Write command that has five parameters
+*/
+void SSD1308::_sendCommand(uint8_t command, uint8_t param1, uint8_t param2,
+                           uint8_t param3, uint8_t param4,
+                           uint8_t param5) {
+
+//  Note continuationbit is set, so COMMAND_MODE must be
+//  repeated before each databyte that serves as parameter!
+#if (I2C_OPTIMIZE == 0)
+    char databytes[12];
+
+    databytes[0] = COMMAND_MODE;
+    databytes[1] = command;
+    databytes[2] = COMMAND_MODE;
+    databytes[3] = param1;
+    databytes[4] = COMMAND_MODE;
+    databytes[5] = param2;
+    databytes[6] = COMMAND_MODE;
+    databytes[7] = param3;
+    databytes[8] = COMMAND_MODE;
+    databytes[9] = param4;
+    databytes[10] = COMMAND_MODE;
+    databytes[11] = param5;
+    _i2c.write(_writeOpcode, databytes, 12);    // Write command
+#else
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(command);       // Write Command
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param1);        // Write Param1
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param2);        // Write Param2
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param3);        // Write Param3
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param4);        // Write Param4
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param5);        // Write Param5
+
+    _i2c.stop();
+#endif
+}
+
+
+/** @brief Write command that has six parameters
+*/
+void SSD1308::_sendCommand(uint8_t command, uint8_t param1, uint8_t param2,
+                           uint8_t param3, uint8_t param4,
+                           uint8_t param5, uint8_t param6) {
+
+//  Note continuationbit is set, so COMMAND_MODE must be
+//  repeated before each databyte that serves as parameter!
+#if (I2C_OPTIMIZE == 0)
+    char databytes[14];
+
+    databytes[0] = COMMAND_MODE;
+    databytes[1] = command;
+    databytes[2] = COMMAND_MODE;
+    databytes[3] = param1;
+    databytes[4] = COMMAND_MODE;
+    databytes[5] = param2;
+    databytes[6] = COMMAND_MODE;
+    databytes[7] = param3;
+    databytes[8] = COMMAND_MODE;
+    databytes[9] = param4;
+    databytes[10] = COMMAND_MODE;
+    databytes[11] = param5;
+    databytes[12] = COMMAND_MODE;
+    databytes[13] = param6;
+    _i2c.write(_writeOpcode, databytes, 14);    // Write command
+#else
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(command);       // Write Command
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param1);        // Write Param1
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param2);        // Write Param2
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param3);        // Write Param3
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param4);        // Write Param4
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param5);        // Write Param5
+    _i2c.write(COMMAND_MODE);
+    _i2c.write(param6);        // Write Param6
+
+    _i2c.stop();
+#endif
+}
+
+
+#if(0)
+/** @brief Write command that has multiple parameters
+*/
+void SSD1308::_sendCommands(uint8_t len, uint8_t* commands) {
+
+//  I2Cdev::writeBytes(m_devAddr, COMMAND_MODE, len, commands);
+//  Note this original code is not correct, continuationbit is set,
+//  so COMMAND_MODE must be repeated before each databyte that serves as parameter!
+
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+
+    for (int i=0; i<len ; i++) {
+        _i2c.write(COMMAND_MODE);
+        _i2c.write(commands[i]);  // Write Commands
+    }
+    _i2c.stop();
+
+}
+#endif
+
+/** @brief Write databyte to display
+ *  @brief Start at current cursor location
+ *  @param uint8_t data databyte to write
+*/
+void SSD1308::_sendData(uint8_t data) {
+
+#if (I2C_OPTIMIZE == 0)
+//I2C Blockwrite versions dont seem to work ?
+//That may be related to fact that the SSD1308/SSD1306 does NOT return an acknowledge: blockwrite may abort the operation
+//Noted for mbed lib v63 on 20/7/13
+    char databytes[2];
+
+    databytes[0] = DATA_MODE;
+    databytes[1] = data;
+    _i2c.write(_writeOpcode, databytes, 2);    // Write Data
+
+#else
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+    _i2c.write(DATA_MODE);
+    _i2c.write(data);
+    _i2c.stop();
+#endif
+
+}
+
+/** @brief Write len bytes from buffer data to display,
+ *  @brief Start at current cursor location
+ *  @param uint8_t len number of bytes to write
+ *  @param uint8_t* data pointer to data
+*/
+void SSD1308::_sendData(uint8_t len, uint8_t* data) {
+//  I2Cdev::writeBytes(m_devAddr, DATA_MODE, len, data);
+#if (I2C_OPTIMIZE == 0)
+    for (int i=0; i<len ; i++) {
+        _sendData(data[i]);  // Write Data
+    }
+#else
+    _i2c.start();
+    _i2c.write(_writeOpcode);
+    _i2c.write(DATA_MODE);
+    for (int i=0; i<len ; i++) {
+        _i2c.write(data[i]);  // Write Data
+    }
+    _i2c.stop();
+#endif
+}
+
+
+/** @brief Set Horizontal Addressing Mode (cursor incr left-to-right, top-to-bottom)
+ *
+ */
+void SSD1308::setHorizontalAddressingMode() {
+    setMemoryAddressingMode(HORIZONTAL_ADDRESSING_MODE);
+}
+
+/** @brief Set Vertical Addressing Mode  (cursor incr top-to-bottom, left-to-right)
+ *
+ */
+void SSD1308::setVerticalAddressingMode() {
+    setMemoryAddressingMode(VERTICAL_ADDRESSING_MODE);
+}
+
+/** @brief Set Page Addressing Mode  (cursor incr left-to-right)
+ *
+ */
+void SSD1308::setPageAddressingMode() {
+    setMemoryAddressingMode(PAGE_ADDRESSING_MODE);
+}
+
+/** @brief Set Addressing Mode
+ *  @param uint8_t mode
+ */
+void SSD1308::setMemoryAddressingMode(uint8_t mode) {
+
+    _sendCommand(SET_MEMORY_ADDRESSING_MODE, mode);
+}
+
+
+/** @param uint8_t start startpage (valid range 0..MAX_PAGE)
+ *  @param uint8_t end   endpage   (valid range start..MAX_PAGE)
+ */
+void SSD1308::setPageAddress(uint8_t start, uint8_t end) {
+
+    _sendCommand(SET_PAGE_ADDRESS, start, end);
+}
+
+
+/** @param uint8_t start startcolumn (valid range 0..MAX_COL)
+ *  @param uint8_t end   endcolumn   (valid range start..MAX_COL)
+ */
+void SSD1308::setColumnAddress(uint8_t start, uint8_t end) {
+
+    _sendCommand(SET_COLUMN_ADDRESS, start, end);
+}
+
+/**
+ *  @brief Set Display StartLine, takes one byte, 0x00-0x3F
+ *  @param uint8_t line startline (valid range 0..MAX_ROWS)
+ */
+void SSD1308::setDisplayStartLine(uint8_t line) {
+
+    line = line & MAX_ROW;
+
+    _sendCommand(SET_DISPLAY_START_LINE | line);
+}
+
+
+/**
+ *  @brief Set Column Start (for Page Addressing Mode only)
+ *  @param uint8_t column column start (valid range 0..MAX_COL)
+ */
+void SSD1308::setColumnStartForPageAddressingMode(uint8_t column) {
+
+    column = column & MAX_COL;
+
+    _sendCommand(SET_LOWER_COLUMN  | ( column     & 0x0F));  // lower nibble
+    _sendCommand(SET_HIGHER_COLUMN | ((column>>4) & 0x0F));  // higher nibble
+}
+
+
+/**
+ *  @brief Set Page Start (for Page Addressing Mode only)
+ *  @param uint8_t page page start (valid range PAGE0 - PAGE7)
+ */
+void SSD1308::setPageStartForPageAddressingMode(uint8_t page) {
+
+    page = page & MAX_PAGE;
+
+    _sendCommand(SET_PAGE_START_ADDRESS | page);
+
+}
+
+
+/** @brief Set Contrast
+ *  @param uint8_t contrast (valid range 0x00 (lowest) - 0xFF (highest))
+*/
+void SSD1308::setContrastControl(uint8_t contrast) {
+
+    _sendCommand(SET_CONTRAST, contrast);
+}
+
+/** @brief Enable Display
+*/
+void SSD1308::setDisplayOn() {
+    _sendCommand(SET_DISPLAY_POWER_ON);
+}
+
+/** @brief Disable Display
+*/
+void SSD1308::setDisplayOff() {
+    _sendCommand(SET_DISPLAY_POWER_OFF);
+}
+
+/** @brief Enable or Disable Display
+ *  @param bool on
+ */
+void SSD1308::setDisplayPower(bool on) {
+    if (on) {
+        setDisplayOn();
+    } else {
+        setDisplayOff();
+    }
+}
+
+/** @brief Show White pixels on Black background
+ */
+void SSD1308::setDisplayNormal() {
+    _sendCommand(SET_NORMAL_DISPLAY);
+}
+
+/** @brief Show Black pixels on White background
+ */
+void SSD1308::setDisplayInverse() {
+    _sendCommand(SET_INVERSE_DISPLAY);
+}
+
+/** @brief Blink display by fading in and out over a set number of frames
+ *  @param bool on
+ */
+void SSD1308::setDisplayBlink(bool on) {
+    if (on) {
+        _sendCommand(SET_FADE_BLINK, (BLINK_ENABLE | FADE_INTERVAL_128_FRAMES));
+    } else {
+        _sendCommand(SET_FADE_BLINK, FADE_BLINK_DISABLE);
+    }
+}
+
+
+/** @brief Fade out display in set number of frames
+ *  @param bool on
+ */
+void SSD1308::setDisplayFade(bool on) {
+    if (on) {
+        _sendCommand(SET_FADE_BLINK, (FADE_OUT_ENABLE | FADE_INTERVAL_128_FRAMES));
+    } else {
+        _sendCommand(SET_FADE_BLINK, FADE_BLINK_DISABLE);
+    }
+}
+
+/** @brief Display Flip (Left/Right, Up/Down)
+ *  @param bool left flip Left/Right
+ *  @param bool down flip Up/Down
+ */
+void SSD1308::setDisplayFlip(bool left, bool down) {
+    if (left) {
+        // column address   0 is mapped to SEG0 (Reset)
+        _sendCommand(SET_SEGMENT_REMAP_0);
+    } else {
+        // column address 127 is mapped to SEG0
+        _sendCommand(SET_SEGMENT_REMAP_127);
+    }
+
+    if (down) {
+        // Reset mode
+        _sendCommand(SET_COMMON_REMAP_0);
+    } else {
+        // Flip Up/Down (Need to rewrite display before H effect shows)
+        _sendCommand(SET_COMMON_REMAP_63);
+    }
+
+}
+
+/** @brief Sets Internal Iref
+ */
+void SSD1308::setInternalIref() {
+//  uint8_t cmds[2] = {SET_IREF_SELECTION, INTERNAL_IREF};
+//  _sendCommands(2, cmds);
+
+    _sendCommand(SET_IREF_SELECTION, INTERNAL_IREF);
+}
+
+/** @brief Sets External Iref (default)
+ */
+void SSD1308::setExternalIref() {
+//  uint8_t cmds[2] = {SET_IREF_SELECTION, EXTERNAL_IREF};
+//  _sendCommands(2, cmds);
+    _sendCommand(SET_IREF_SELECTION, EXTERNAL_IREF);
+}
+
+
+/** @brief Shows All Pixels On
+ */
+void SSD1308::setEntireDisplayOn() {
+    _sendCommand(SET_ENTIRE_DISPLAY_ON);
+}
+
+/** @brief Shows Pixels as RAM content
+ */
+void SSD1308::setEntireDisplayRAM() {
+    _sendCommand(SET_DISPLAY_GDDRAM);
+}
+
+/** @brief Shows Pixels On or as RAM content
+ *  @param bool on (true is All on, false is RAM content)
+ */
+void SSD1308::setEntireDisplay(bool on) {
+    if (on) {
+        setEntireDisplayOn();  // All Pixels on
+    } else {
+        setEntireDisplayRAM(); // Pixels are RAM content
+    }
+}
+
+
+/** @brief Horizontal scroll by one column per interval
+ *  @param bool left select Left/Right scroll
+ *  @param uint8_t start_page begin page   (0..MAX_PAGE)
+ *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)
+ *  @param uint8_t interval   scroll interval in frames (see codes above)
+ */
+void SSD1308::setContinuousHorizontalScroll(bool left, uint8_t start_page, uint8_t end_page, uint8_t interval) {
+    if (left) {
+        _sendCommand(SET_LEFT_HOR_SCROLL, 0x00, start_page, interval, end_page, 0x00, 0xFF);  // Scroll Left
+    } else {
+        _sendCommand(SET_RIGHT_HOR_SCROLL, 0x00, start_page, interval, end_page, 0x00, 0xFF); // Scroll Right
+    }
+
+}
+
+
+/** @brief Horizontal and Vertical scroll by one column per interval
+ *  @param bool left select Left/Right scroll
+ *  @param uint8_t start_page begin page   (0..MAX_PAGE)
+ *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)
+ *  @param uint8_t offset     vert offset  (0x01..0x63)
+ *  @param uint8_t interval   scroll interval in frames (see codes above)
+ */
+void SSD1308::setContinuousVerticalAndHorizontalScroll(bool left, uint8_t start_page, uint8_t end_page,
+        uint8_t offset, uint8_t interval) {
+    if (left) {
+        _sendCommand(SET_VERT_LEFT_HOR_SCROLL, 0x00, start_page, interval, end_page, offset);  // Scroll Left
+    } else {
+        _sendCommand(SET_VERT_RIGHT_HOR_SCROLL, 0x00, start_page, interval, end_page, offset); // Scroll Right
+    }
+
+}
+
+/** @brief Set Vertical scroll area
+ *  @param uint8_t topRowsFixed      fixed rows   (0..MAX_ROW)
+ *  @param uint8_t scrollRowsoffset  scroll rows  (topRowsFixed..ROWS)
+ */
+void SSD1308::setVerticalScrollArea(uint8_t topRowsFixed, uint8_t scrollRows) {
+
+    if ((topRowsFixed + scrollRows) > ROWS) {
+        scrollRows = ROWS - topRowsFixed;
+    };
+
+    _sendCommand(SET_VERTICAL_SCROLL_AREA, topRowsFixed, scrollRows);
+}
+
+/** @brief Activate or Deactivate Horizontal and Vertical scroll
+ *  @brief Note: after deactivating scrolling, the RAM data needs to be rewritten
+ *  @param bool on activate scroll
+ */
+void SSD1308::setDisplayScroll(bool on) {
+    if (on) {
+        _sendCommand(SET_ACTIVATE_SCROLL);   // Scroll on
+    } else {
+        _sendCommand(SET_DEACTIVATE_SCROLL); // Scroll off
+    }
+}
+
+
+
+/** @brief Low level Init
+ *  @brief Init the configuration registers in accordance with the datasheet
+ */
+void SSD1308::_init() {
+
+    _sendCommand(SET_DISPLAY_POWER_OFF);      // 0xAE
+
+    // column address   0 is mapped to SEG0 (Reset)
+    // row address   0 is mapped to COM0 (Reset)
+    _sendCommand(SET_SEGMENT_REMAP_0);        // 0xA0 (Reset)
+    _sendCommand(SET_COMMON_REMAP_0);         // 0xC0 (Reset)
+
+    setDisplayStartLine(0);                   // 0x40 (Reset)
+
+    _sendCommand(SET_COMMON_CONF, COMMON_BASE | COMMON_ALTERNATIVE | COMMON_LEFTRIGHT_NORMAL); // 0xDA, 0x12 (Reset)
+
+    // Pagemode or Horizontal mode
+//  setPageAddressingMode();                  // 0x20, 0x02 (Reset)
+//  setColumnStartForPageAddressingMode(0);   // 0x00, 0x10 (Reset = Column 0)
+//  setPageStartForPageAddressingMode(PAGE_0);// 0xBO       (Reset = Page 0)
+    setHorizontalAddressingMode();            // 0x20, 0x00 (Non-Reset)
+    setColumnAddress(0, MAX_COL);             // 0x21, 0x00, 0x37 (Reset)
+    setPageAddress(0, MAX_PAGE);              // 0x22, 0x00, 0x07 (Reset)
+
+    setExternalIref();                        // 0xAD, 0x10 (Reset)
+
+    _sendCommand(SET_DISPLAY_CLOCK, 0x70);    // 0xD5, 0x70 (Reset = 0x80)
+    _sendCommand(SET_PRECHARGE_TIME, 0x21);   // 0xD9, 0x21 (Reset = 0x22)
+    _sendCommand(SET_VCOMH_DESELECT_LEVEL, 0x30); // 0xDB, 0x30 (Reset = 0x20)
+    _sendCommand(SET_MULTIPLEX_RATIO, 0x3F);  // 0xA8, 0x3F (Reset)
+    _sendCommand(SET_DISPLAY_OFFSET, 0x00);   // 0xD3, 0x00 (Reset)
+
+    _sendCommand(SET_CONTRAST, 0x7F);         // 0x81, 0x7F (Reset)
+
+    _sendCommand(SET_NORMAL_DISPLAY);         // 0xA6 (Reset)
+
+    setEntireDisplayRAM();                    // 0xA4 (Reset)
+    setDisplayScroll(false);
+
+    clearDisplay();
+
+    _sendCommand(SET_DISPLAY_POWER_ON);       // 0xAF
+}
+