Demonstration of SSD1308 OLED driver library

Dependencies:   mbed SSD1308_128x64_I2C

Revision:
3:1337e3d65ed0
Parent:
2:d86478c0f5da
--- a/SSD1308.cpp	Mon Jul 09 20:46:27 2012 +0000
+++ b/SSD1308.cpp	Wed Jul 18 13:59:03 2012 +0000
@@ -3,8 +3,11 @@
 //   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 is using (and has been submitted as a part of) Jeff Rowberg's I2Cdevlib library,
+// 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>
@@ -39,10 +42,19 @@
 
 //#define SSD1308_USE_FONT
 //#ifdef SSD1308_USE_FONT
-#include "FixedWidthFont.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"
 //#endif
 
-//Constructor
+//@brief Constructor
+//@param I2C &i2c reference to i2c
+//@param uint8_t deviceAddress slaveaddress
 //
 SSD1308::SSD1308(I2C &i2c, uint8_t deviceAddress) : _i2c(i2c) {
 //  m_devAddr = deviceAddress; 
@@ -53,14 +65,21 @@
   initialize(); 
 }
 
-// High level Init, most settings remain at Power-On reset value
+// @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(0)
 // Standard version
 void SSD1308::clearDisplay() {
@@ -71,7 +90,7 @@
 
   for (uint8_t page = 0; page < PAGES; page++) {
     for (uint8_t col = 0; col < COLUMNS; col++) {
-      sendData(0x00);
+      _sendData(0x00);
     }
   }
 
@@ -102,6 +121,9 @@
 #endif
 
 
+// @brief fill the display
+// @param uint8_t pattern fillpattern vertical patch or 8 bits 
+//
 #if(0)
 //Standard version
 void SSD1308::fillDisplay(uint8_t pattern) {
@@ -113,36 +135,51 @@
 
   for (uint8_t page = 0; page < PAGES; page++) {
     for (uint8_t col = 0; col < COLUMNS; col++) {
-      sendData(pattern); 
+      _sendData(pattern); 
     }
   }
  
   //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) {
-
+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(0, MAX_PAGE);  // all pages
-  setColumnAddress(0, MAX_COL); // all columns
-
+  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<(PAGES * COLUMNS); i++) {
+  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(0)
+//Standard version
 void SSD1308::writeBitmap(int len, uint8_t* data) {
 
   //setDisplayOff();
@@ -159,41 +196,71 @@
 
   //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
 
 
-// Write single character to the display using the 8x8 fontable
-// Start at current cursor location
-//     char chr character
-//     bool inverted invert pixels
-void SSD1308::writeChar(char chr, bool inverted) {
+// @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++) {
-//     const uint8_t b = pgm_read_byte( &fontData[char_index][i] );
-//     const uint8_t b = fontData[char_index][i];     
-//     sendData( b ); 
-     if (inverted) {
-       sendData( ~fontData[char_index][i] );           
+     if (_inverted) {
+       _sendData( ~font_8x8[char_index][i] );           
      }
      else {
-       sendData( fontData[char_index][i] );
+       _sendData( font_8x8[char_index][i] );
      }  
   }
 
 }
 
 
-// Write a string to the display using the 8x8 fontable
-// Start at current cursor location
-void SSD1308::writeString(uint8_t row, uint8_t col, uint16_t len, const char * text, bool inverted) {
+// @brief Write a string to the display using the 8x8 font
+// @brief Start at selected cursor location
+// @param uint8_t row  row number    (0...ROWS/FONT_HEIGHT)
+// @param uint8_t col  column number (0...COLUMNS/FONT_WIDTH)
+// @param uint16_t len number of chars in text
+// @param const char * text pointer to text
+//
+void SSD1308::writeString(uint8_t row, uint8_t col, uint16_t len, const char * text) {
   uint16_t index = 0;
   setPageAddress(row, MAX_PAGE);
-  const uint8_t col_addr = FONT_WIDTH*col;
+  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++], inverted);
+     writeChar(text[index++]);
   }
 
   // write remaining lines
@@ -204,7 +271,7 @@
     setColumnAddress(0, MAX_COL);
     bool wrapEntireScreen = false;
     while (index + 1 < len) {
-       writeChar(text[index++], inverted);
+       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) {
@@ -216,22 +283,47 @@
   }
 }
 
-// Write command that has no parameters
+
+
+// @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) {
+void SSD1308::_sendCommand(uint8_t command) {
 //  I2Cdev::writeByte(m_devAddr, COMMAND_MODE, command);
 
+#if(0)
   char databytes[2];
     
   databytes[0] = COMMAND_MODE;
   databytes[1] = command;    
   _i2c.write(_writeOpcode, databytes, 2);    // Write command   
+#endif
+  
+  _i2c.start();
+  _i2c.write(_writeOpcode);
+  
+  _i2c.write(COMMAND_MODE);      
+  _i2c.write(command);       // Write Command   
+
+  _i2c.stop();  
 
 }
 
-// Write command that has one parameter
+// @brief Write command that has one parameter
 // 
-void SSD1308::sendCommand(uint8_t command, uint8_t param1) {
+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!
@@ -248,9 +340,9 @@
   
 }
 
-// Write command that has two parameters
+// @brief Write command that has two parameters
 // 
-void SSD1308::sendCommand(uint8_t command, uint8_t param1, uint8_t param2) {
+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!
@@ -269,11 +361,10 @@
   
 }
 
-
-
-// Write command that has multiple parameters
+#if(0)
+// @brief Write command that has multiple parameters
 // 
-void SSD1308::sendCommands(uint8_t len, uint8_t* commands) {
+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, 
@@ -289,10 +380,13 @@
   _i2c.stop();
   
 }
+#endif
 
-// Write databyte to display
-// Start at current cursor location
-void SSD1308::sendData(uint8_t data){
+// @brief Write databyte to display
+// @brief Start at current cursor location
+// @param uint8_t data databyte to write
+//
+void SSD1308::_sendData(uint8_t data){
 //  I2Cdev::writeByte(m_devAddr, DATA_MODE, data);
 
   char databytes[2];
@@ -303,9 +397,12 @@
   
 }
 
-// Write len bytes from buffer data to display
-// Start at current cursor location
-void SSD1308::sendData(uint8_t len, uint8_t* data) {
+// @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);
   
   _i2c.start();
@@ -333,41 +430,49 @@
 }
     
 void SSD1308::setMemoryAddressingMode(uint8_t mode){
-  uint8_t cmds[2] = { SET_MEMORY_ADDRESSING_MODE, mode };
-  sendCommands(2, cmds); 
+
+  _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) {
-  uint8_t data[3] = { SET_PAGE_ADDRESS, start, end };
-  sendCommands(3, data);  
-}
 
-void SSD1308::setColumnAddress(uint8_t start, uint8_t end) {
-  uint8_t data[3] = { SET_COLUMN_ADDRESS, start, end };
-  sendCommands(3, data);  
+  _sendCommand(SET_PAGE_ADDRESS, start, end);   
 }
 
 
-// takes one byte, 0x00 (lowest) - 0xFF (highest)
+// @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 Contrast
+// @param uint8_t contrast (valid range 0x00 (lowest) - 0xFF (highest))
 void SSD1308::setContrastControl(uint8_t contrast) {
-//  uint8_t cmds[2] = { SET_CONTRAST, contrast };
-//  sendCommands(2, cmds); 
   
-    sendCommand(SET_CONTRAST, contrast);  
+    _sendCommand(SET_CONTRAST, contrast);  
 } 
 
-// Enable Display
+// @brief Enable Display
 // 
 void SSD1308::setDisplayOn() {
-  sendCommand(SET_DISPLAY_POWER_ON);
+  _sendCommand(SET_DISPLAY_POWER_ON);
 }
 
-// Disable Display
+// @brief Disable Display
 // 
 void SSD1308::setDisplayOff() {
-  sendCommand(SET_DISPLAY_POWER_OFF);
+  _sendCommand(SET_DISPLAY_POWER_OFF);
 }
 
+// @brief Enable or Disable Display
+// @param bool on
 void SSD1308::setDisplayPower(bool on) {
   if (on) {
     setDisplayOn();
@@ -376,81 +481,113 @@
   }
 }
 
-// White on Black background
+// @brief White pixels on Black background
 // 
 void SSD1308::setDisplayNormal() {
-  sendCommand(SET_NORMAL_DISPLAY);
+  _sendCommand(SET_NORMAL_DISPLAY);
+}
+
+// @brief Black pixels on White background
+// 
+void SSD1308::setDisplayInverse() {
+  _sendCommand(SET_INVERSE_DISPLAY);
 }
 
-// Black 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);  
+  }
+}       
 
 
-// Display Flip (Left/Right, Up/Down)
-// 
+// @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);
+    _sendCommand(SET_SEGMENT_REMAP_0);
   }
   else {
     // column address 127 is mapped to SEG0    
-    sendCommand(SET_SEGMENT_REMAP_127);
+    _sendCommand(SET_SEGMENT_REMAP_127);
   }  
 
   if (down) {
     // Reset mode
-    sendCommand(SET_COMMON_REMAP_0);    
+    _sendCommand(SET_COMMON_REMAP_0);    
   }
   else {
     // Flip Up/Down (Need to rewrite display before H effect shows)
-    sendCommand(SET_COMMON_REMAP_63);        
+    _sendCommand(SET_COMMON_REMAP_63);        
   }  
 
 }
 
-// Sets Internal Iref
+// @brief Sets Internal Iref
 //
 void SSD1308::setInternalIref() {
-  uint8_t cmds[2] = {SET_IREF_SELECTION, INTERNAL_IREF};
-  sendCommands(2, cmds); 
+//  uint8_t cmds[2] = {SET_IREF_SELECTION, INTERNAL_IREF};
+//  _sendCommands(2, cmds); 
+  
+  _sendCommand(SET_IREF_SELECTION, INTERNAL_IREF);   
 }
 
-// Sets External Iref
+// @brief Sets External Iref (default)
 //
 void SSD1308::setExternalIref() {
-  uint8_t cmds[2] = {SET_IREF_SELECTION, EXTERNAL_IREF};
-  sendCommands(2, cmds); 
+//  uint8_t cmds[2] = {SET_IREF_SELECTION, EXTERNAL_IREF};
+//  _sendCommands(2, cmds); 
+  _sendCommand(SET_IREF_SELECTION, EXTERNAL_IREF); 
 }
 
 
-// Low level Init
-// Init the configuration registers in accordance with the datasheet
+// @brief Low level Init
+// @brief Init the configuration registers in accordance with the datasheet
 //
 void SSD1308::_init() {
 
 //not complete yet  
-  sendCommand(SET_DISPLAY_POWER_OFF);
+  _sendCommand(SET_DISPLAY_POWER_OFF);
   
   // column address   0 is mapped to SEG0 (Reset)    
   // row address   0 is mapped to COMM0 (Reset)      
-  sendCommand(SET_SEGMENT_REMAP_0);
-  sendCommand(SET_COMMON_REMAP_0);    
+  _sendCommand(SET_SEGMENT_REMAP_0);
+  _sendCommand(SET_COMMON_REMAP_0);    
   
-  uint8_t cmds[2] = { SET_COMMON_CONF, COMMON_BASE | COMMON_ALTERNATIVE | COMMON_LEFTRIGHT_NORMAL};
-  sendCommands(2, cmds); 
+//  uint8_t cmds[2] = { SET_COMMON_CONF, COMMON_BASE | COMMON_ALTERNATIVE | COMMON_LEFTRIGHT_NORMAL};
+//  _sendCommands(2, cmds); 
+  _sendCommand(SET_COMMON_CONF, COMMON_BASE | COMMON_ALTERNATIVE | COMMON_LEFTRIGHT_NORMAL);   
 
-  setHorizontalAddressingMode();
+  setHorizontalAddressingMode(); // (Non-Reset)
   
-  setExternalIref();
-    
-  sendCommand(SET_NORMAL_DISPLAY);  
+  setExternalIref(); // (Reset)
+
+  _sendCommand(SET_CONTRAST, 0x7F);  // (Reset)
+
+  _sendCommand(SET_NORMAL_DISPLAY);  
   
   clearDisplay();   
   
-  sendCommand(SET_DISPLAY_POWER_ON);
+  _sendCommand(SET_DISPLAY_POWER_ON);
 }