Team H - TVZ Seminar / SSD1308_128x64_I2C

Dependents:   Zavrsni_Daljinski Zavrsni_Daljinsk_vfinal

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SSD1308.cpp Source File

SSD1308.cpp

00001 /**  @file SSD1308 I2C device class file
00002  *   Based on Solomon Systech SSD1308 datasheet, rev. 1, 10/2008
00003  *   The SSD1308 is used for example in the Seeed 128x64 OLED Display
00004  *   http://www.seeedstudio.com/depot/grove-oled-display-12864-p-781.html?cPath=163_167
00005 */
00006 // The original code by Andrew Schamp is using (and has been submitted as a part of) Jeff Rowberg's I2Cdevlib library,
00007 // which should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
00008 // Some parts also mashed up from Graphic Library for driving monochrome displays based on the PCD8544,
00009 // Copyright (c) 2011, Wim De Roeve, who in turn did partial port of code found on
00010 // http://serdisplib.sourceforge.net/ser/pcd8544.html#links and by Petras Saduikis <petras@petras.co.uk>
00011 //
00012 // Changelog:
00013 //   2011-08-25 - Initial release by Andrew Schamp <schamp@gmail.com>
00014 //   2012-06-19 - Ported to mbed and optimised (WH)
00015 //   2013-07-12 - Minor comment fix and placeholder for SSD1306 (WH)
00016 //   2015-01-01 - Switch for optimised I2C calls to test on F401 (WH)
00017 //   2017-12-18 - Fixed non-copyable issue (Thx kenjiArai)
00018 //       
00019 /* 
00020 ================================================================================
00021 I2Cdev device library code is placed under the MIT license
00022 Copyright (c) 2011 Andrew Schamp
00023 Copyright (c) 2012,2013,2017 WH (mbed port)
00024 
00025 Permission is hereby granted, free of charge, to any person obtaining a copy
00026 of this software and associated documentation files (the "Software"), to deal
00027 in the Software without restriction, including without limitation the rights
00028 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00029 copies of the Software, and to permit persons to whom the Software is
00030 furnished to do so, subject to the following conditions:
00031 
00032 The above copyright notice and this permission notice shall be included in
00033 all copies or substantial portions of the Software.
00034 
00035 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00036 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00037 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00038 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00039 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00040 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00041 THE SOFTWARE.
00042 ================================================================================
00043 */
00044 #include "mbed.h"
00045 #include "SSD1308.h"
00046 
00047 //#include "font_3x5.h"
00048 //#include "font_5x7.h"
00049 //#include "font_6x8.h"
00050 #include "font_8x8.h"
00051 //#include "font_8x12.h"
00052 //#include "font_16x20.h"
00053 #include "font_16x24.h"
00054 
00055 #if defined(TARGET_LPC1768)
00056 #define I2C_OPTIMIZE   1
00057 #else
00058 #define I2C_OPTIMIZE   0
00059 #endif
00060 
00061 /**
00062  *@brief Constructor
00063  *@param I2C *i2c reference to i2c
00064  *@param uint8_t deviceAddress slaveaddress
00065  */
00066 SSD1308::SSD1308(I2C *i2c, uint8_t deviceAddress) : _i2c(i2c) {
00067   
00068   _writeOpcode = deviceAddress & 0xFE; // low order bit = 0 for write
00069   _readOpcode  = deviceAddress | 0x01; // low order bit = 1 for read  
00070   
00071   initialize(); 
00072 }
00073 
00074 /** @brief High level Init, most settings remain at Power-On reset value
00075  */
00076 void SSD1308::initialize() {
00077   setHorizontalAddressingMode();
00078 
00079   clearDisplay();
00080 
00081   setInverted(false);
00082   
00083   setDisplayOn();  
00084 }
00085 
00086 
00087 /** @brief clear the display
00088 */
00089 #if (I2C_OPTIMIZE == 0)
00090 // Standard version
00091 void SSD1308::clearDisplay() {
00092  
00093   //setDisplayOff();
00094   setPageAddress (0, MAX_PAGE);  // all pages
00095   setColumnAddress (0, MAX_COL); // all columns
00096 
00097   for (uint8_t page = 0; page < PAGES; page++) {
00098     for (uint8_t col = 0; col < COLUMNS; col++) {
00099       _sendData(0x00);
00100     }
00101   }
00102 
00103   //setDisplayOn();
00104 }
00105 #else
00106 //Optimised version
00107 // Save lots of I2C S,P, address and datacommands:
00108 // Send S, address, DATA_MODE, data, data, data,...., P
00109 //
00110 void SSD1308::clearDisplay() {
00111 
00112   //setDisplayOff();
00113   
00114   setPageAddress (0, MAX_PAGE);  // all pages
00115   setColumnAddress (0, MAX_COL); // all columns
00116 
00117   _i2c->start();
00118   _i2c->write(_writeOpcode);
00119   _i2c->write(DATA_MODE);  
00120   for (int i=0; i<(PAGES * COLUMNS); i++) {
00121     _i2c->write(0x00);  // Write Data   
00122   }
00123   _i2c->stop();
00124 
00125   //setDisplayOn();
00126 }
00127 #endif
00128 
00129 
00130 /** @brief fill the display
00131  *  @param uint8_t pattern fillpattern vertical patch or 8 bits 
00132  *  @param uint8_t start_page begin page   (0..MAX_PAGE)
00133  *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)                     
00134  *  @param uint8_t start_col  begin column (0..MAX_COL)
00135  *  @param uint8_t end_col    end column   (start_col..MAX_COL)
00136 */
00137 #if (I2C_OPTIMIZE == 0)
00138 //Standard version
00139 
00140 void SSD1308::fillDisplay(uint8_t pattern,
00141                           uint8_t start_page, uint8_t end_page,
00142                           uint8_t start_col, uint8_t end_col) {
00143   
00144   int count = (end_page - start_page + 1) * (end_col - start_col + 1);
00145   
00146   //setDisplayOff();
00147   setPageAddress (start_page, end_page);  // set page window
00148   setColumnAddress (start_col, end_col);  // set column window
00149  
00150   for (int i=0; i<count; i++) {
00151     _sendData(pattern); // Write Data    
00152   }
00153 
00154   //setDisplayOn();
00155 }
00156 
00157 #else
00158 
00159 //Optimised version
00160 // Save lots of I2C S,P, address and datacommands:
00161 // Send S, address, DATA_MODE, data, data, data,...., P
00162 //
00163 void SSD1308::fillDisplay(uint8_t pattern,
00164                           uint8_t start_page, uint8_t end_page,
00165                           uint8_t start_col, uint8_t end_col) {
00166   
00167   int count = (end_page - start_page + 1) * (end_col - start_col + 1);
00168   
00169   //setDisplayOff();
00170   setPageAddress (start_page, end_page);  // set page window
00171   setColumnAddress (start_col, end_col);  // set column window
00172  
00173   _i2c->start();
00174   _i2c->write(_writeOpcode);
00175   _i2c->write(DATA_MODE);  
00176   for (int i=0; i<count; i++) {
00177     _i2c->write(pattern);  // Write Data   
00178   }
00179   _i2c->stop();
00180 
00181   //setDisplayOn();
00182 }
00183 
00184 #endif
00185 
00186 
00187 /** @brief write a bitmap to the display
00188  *  @param uint8_t* data pointer to bitmap
00189  *  @param uint8_t start_page begin page   (0..MAX_PAGE)
00190  *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)                     
00191  *  @param uint8_t start_col  begin column (0..MAX_COL)
00192  *  @param uint8_t end_col    end column   (start_col..MAX_COL)
00193 */
00194 #if (I2C_OPTIMIZE == 0)
00195 //Standard version
00196 void SSD1308::writeBitmap(uint8_t* data,
00197                           uint8_t start_page, uint8_t end_page,
00198                           uint8_t start_col, uint8_t end_col){
00199   
00200   int count = (end_page - start_page + 1) * (end_col - start_col + 1);
00201 
00202   //setDisplayOff();
00203   setPageAddress (start_page, end_page);  // set page window
00204   setColumnAddress (start_col, end_col);  // set column window
00205 
00206   for (int i=0; i<count; i++) {
00207     _sendData(data[i]); // Write Data   
00208   }
00209 
00210   //setDisplayOn();
00211 }
00212 
00213 #else
00214 //Optimised version
00215 // Save lots of I2C S,P, address and datacommands:
00216 // Send S, address, DATA_MODE, data, data, data,...., P
00217 //
00218 void SSD1308::writeBitmap(uint8_t* data,
00219                           uint8_t start_page, uint8_t end_page,
00220                           uint8_t start_col, uint8_t end_col){
00221   
00222   int count = (end_page - start_page + 1) * (end_col - start_col + 1);
00223 
00224   //setDisplayOff();
00225   setPageAddress (start_page, end_page);  // set page window
00226   setColumnAddress (start_col, end_col);  // set column window
00227 
00228   _i2c->start();
00229   _i2c->write(_writeOpcode);
00230   _i2c->write(DATA_MODE);  
00231   for (int i=0; i<count; i++) {
00232     _i2c->write(data[i]);  // Write Data       
00233   }
00234   _i2c->stop();
00235 
00236   //setDisplayOn();
00237 }
00238 
00239 #endif
00240 
00241 
00242 /** @brief write a progressbar to the display, Width is (PRG_MAX_SCALE + 2) pixels
00243  *  @param uint8_t page begin page   (0..MAX_PAGE)
00244  *  @param uint8_t col  begin column (0..MAX_COL)
00245  *  @param int percentage value      (0..100)
00246 */
00247 #define PRG_MAX_SCALE     50
00248 #define PRG_LEFT_EDGE   0xFF
00249 #define PRG_RIGHT_EDGE  0xFF
00250 #define PRG_ACTIVE      0xFF
00251 //#define PRG_ACTIVE      0xBD
00252 #define PRG_NOT_ACTIVE  0x81
00253 
00254 #if (I2C_OPTIMIZE == 0)
00255 //Standard version
00256 void SSD1308::writeProgressBar(uint8_t page, uint8_t col, int percentage) {
00257   uint8_t scale_value;
00258   
00259   if (percentage <= 0) {
00260     scale_value = 0;
00261   } else if (percentage >= 100) {
00262       scale_value = PRG_MAX_SCALE - 1;
00263   }
00264   else {
00265     scale_value = (percentage * PRG_MAX_SCALE) / 100; 
00266   }      
00267       
00268   //setDisplayOff();
00269   setPageAddress (page, page);  
00270   setColumnAddress (col, MAX_COL); 
00271   
00272   _sendData(PRG_LEFT_EDGE);
00273 
00274   for (uint8_t col = 0; col < scale_value; col++) {
00275       _sendData(PRG_ACTIVE);
00276   }
00277       
00278   _sendData(PRG_ACTIVE);
00279   
00280   for (uint8_t col = (scale_value+1); col < PRG_MAX_SCALE; col++) {
00281       _sendData(PRG_NOT_ACTIVE);
00282   }
00283 
00284   _sendData(PRG_RIGHT_EDGE);    
00285   
00286   //setDisplayOn();
00287 }
00288 #else
00289 
00290 //Optimised version
00291 // Save lots of I2C S,P, address and datacommands:
00292 // Send S, address, DATA_MODE, data, data, data,...., P
00293 //
00294 void SSD1308::writeProgressBar(uint8_t page, uint8_t col, int percentage) {
00295   uint8_t scale_value;
00296   
00297   if (percentage <= 0) {
00298     scale_value = 0;
00299   } else if (percentage >= 100) {
00300       scale_value = PRG_MAX_SCALE - 1 ;
00301   }
00302   else {
00303     scale_value = (percentage * PRG_MAX_SCALE) / 100; 
00304   }      
00305       
00306   //setDisplayOff();
00307   setPageAddress (page, page);  
00308   setColumnAddress (col, MAX_COL); 
00309 
00310   _i2c->start();
00311   _i2c->write(_writeOpcode);
00312   _i2c->write(DATA_MODE);  
00313 
00314   _i2c->write(PRG_LEFT_EDGE);  // Write Data         
00315 
00316   for (uint8_t col = 0; col < scale_value; col++) {
00317      _i2c->write(PRG_ACTIVE);  // Write Data                       
00318   }
00319 
00320   _i2c->write(PRG_ACTIVE);  // Write Data                       
00321      
00322   for (uint8_t col = (scale_value+1); col < PRG_MAX_SCALE; col++) {
00323      _i2c->write(PRG_NOT_ACTIVE);  // Write Data                 
00324   }
00325 
00326   _i2c->write(PRG_RIGHT_EDGE);  // Write Data           
00327 
00328   _i2c->stop();
00329     
00330   //setDisplayOn();
00331 }
00332 #endif
00333 
00334 /** @brief write a level meter to the display, Width is (PRG_MAX_SCALE + 2) pixels
00335  *  @param uint8_t page begin page   (0..MAX_PAGE)
00336  *  @param uint8_t col  begin column (0..MAX_COL)
00337  *  @param int percentage value      (0..100)
00338 */
00339 #if (I2C_OPTIMIZE == 0)
00340 void SSD1308::writeLevelBar(uint8_t page, uint8_t col, int percentage) {
00341   uint8_t scale_value;
00342   
00343   if (percentage <= 0) {
00344     scale_value = 0;
00345   } else if (percentage >= 100) {
00346       scale_value = PRG_MAX_SCALE - 1;
00347   }
00348   else {
00349     scale_value = (percentage * PRG_MAX_SCALE) / 100; 
00350   }      
00351       
00352   //setDisplayOff();
00353   setPageAddress (page, page);  
00354   setColumnAddress (col, MAX_COL); 
00355  
00356   _sendData(PRG_LEFT_EDGE);   
00357 
00358   for (uint8_t col = 0; col < scale_value; col++) {
00359      _sendData(PRG_NOT_ACTIVE);  // Write Data                       
00360   }
00361 
00362   _sendData(PRG_ACTIVE);  // Write Data at active meterlevel
00363 
00364   for (uint8_t col = scale_value+1; col < PRG_MAX_SCALE; col++) {
00365       _sendData(PRG_NOT_ACTIVE);                
00366   }
00367          
00368   _sendData(PRG_RIGHT_EDGE);
00369     
00370   //setDisplayOn();
00371 }
00372 #else
00373 //Optimised version
00374 // Save lots of I2C S,P, address and datacommands:
00375 // Send S, address, DATA_MODE, data, data, data,...., P
00376 //
00377 void SSD1308::writeLevelBar(uint8_t page, uint8_t col, int percentage) {
00378   uint8_t scale_value;
00379   
00380   if (percentage <= 0) {
00381     scale_value = 0;
00382   } else if (percentage >= 100) {
00383       scale_value = PRG_MAX_SCALE - 1;
00384   }
00385   else {
00386     scale_value = (percentage * PRG_MAX_SCALE) / 100; 
00387   }      
00388       
00389   //setDisplayOff();
00390   setPageAddress (page, page);  
00391   setColumnAddress (col, MAX_COL); 
00392 
00393   _i2c->start();
00394   _i2c->write(_writeOpcode);
00395   _i2c->write(DATA_MODE);  
00396 
00397   _i2c->write(PRG_LEFT_EDGE);  // Write Data         
00398 
00399   for (uint8_t col = 0; col < scale_value; col++) {
00400      _i2c->write(PRG_NOT_ACTIVE);  // Write Data                       
00401   }
00402 
00403   _i2c->write(PRG_ACTIVE);  // Write Data at active meterlevel
00404   
00405   for (uint8_t col = scale_value+1; col < PRG_MAX_SCALE; col++) {
00406      _i2c->write(PRG_NOT_ACTIVE);  // Write Data                 
00407   }
00408 
00409   _i2c->write(PRG_RIGHT_EDGE);  // Write Data           
00410 
00411   _i2c->stop();
00412     
00413   //setDisplayOn();
00414 }
00415 #endif
00416 
00417 /** @brief Write single character to the display using the 8x8 fontable
00418  *  @brief Start at current cursor location
00419  *  @param char chr character to write
00420 */
00421 void SSD1308::writeChar(char chr) {
00422 
00423   const uint8_t char_index = chr - 0x20;
00424 
00425   for (uint8_t i = 0; i < 8; i++) {
00426      if (_inverted) {
00427        _sendData( ~font_8x8[char_index][i] );           
00428      }
00429      else {
00430        _sendData( font_8x8[char_index][i] );
00431      }  
00432   }
00433 
00434 }
00435 
00436 
00437 /** @brief Write a string to the display using the 8x8 font
00438  *  @brief Start at selected cursor location, text will wrap around until it is done
00439  *  @param uint8_t row  row number    (0...ROWS/FONT_HEIGHT)
00440  *  @param uint8_t col  column number (0...COLUMNS/FONT_WIDTH)
00441  *  @param const char * text pointer to text
00442  */
00443 void SSD1308::writeString(uint8_t row, uint8_t col, const char * text) {
00444   uint16_t index = 0;
00445   uint16_t len = strlen(text);
00446   
00447   setPageAddress (row, MAX_PAGE);
00448   const uint8_t col_addr = FONT8x8_WIDTH*col;
00449   setColumnAddress (col_addr, MAX_COL);
00450 
00451   while ((col+index) < CHARS && (index < len)) {
00452      // write first line, starting at given position
00453      writeChar(text[index++]);
00454   }
00455 
00456   // write remaining lines
00457   // write until the end of memory
00458   // then wrap around again from the top.
00459   if (index + 1 < len) {
00460     setPageAddress (row + 1, MAX_PAGE);
00461     setColumnAddress (0, MAX_COL);
00462     bool wrapEntireScreen = false;
00463     while (index + 1 < len) {
00464        writeChar(text[index++]);
00465        // if we've written the last character space on the screen, 
00466        // reset the page and column address so that it wraps around from the top again
00467        if (!wrapEntireScreen && (row*CHARS + col + index) > 127) {
00468          setPageAddress (0, MAX_PAGE);
00469          setColumnAddress (0, MAX_COL);
00470          wrapEntireScreen = true;
00471        }
00472     }
00473   }
00474 }
00475 
00476 
00477 
00478 /** @brief Write large character (16x24 font)
00479  *  @param uint8_t row  row number    (0...MAX_ROW)
00480  *  @param uint8_t col  column number (0...MAX_COL)
00481  *  @param char chr     Used for displaying numbers 0 - 9 and '+', '-', '.'
00482  */
00483 void SSD1308::writeBigChar(uint8_t row, uint8_t col, char chr) {
00484 
00485   writeBitmap((uint8_t*) font_16x24[int(chr) - FONT16x24_START],
00486               row, (row + FONT16x24_BYTES - 1),
00487               col, (col + FONT16x24_WIDTH - 1));
00488 }
00489 
00490 
00491 /** @brief Write command that has no parameters
00492 */ 
00493 void SSD1308::_sendCommand(uint8_t command) {
00494 //  I2Cdev::writeByte(m_devAddr, COMMAND_MODE, command);
00495 
00496 #if (I2C_OPTIMIZE == 0)
00497   char databytes[2];
00498     
00499   databytes[0] = COMMAND_MODE;
00500   databytes[1] = command;    
00501   _i2c->write(_writeOpcode, databytes, 2);    // Write command   
00502 #else  
00503 
00504   _i2c->start();
00505   _i2c->write(_writeOpcode);
00506   
00507   _i2c->write(COMMAND_MODE);      
00508   _i2c->write(command);       // Write Command   
00509 
00510   _i2c->stop();  
00511 #endif
00512 }
00513 
00514 /** @brief Write command that has one parameter
00515 */ 
00516 void SSD1308::_sendCommand(uint8_t command, uint8_t param1) {
00517 
00518 //  Note continuationbit is set, so COMMAND_MODE must be
00519 //  repeated before each databyte that serves as parameter!
00520 #if (I2C_OPTIMIZE == 0)
00521   char databytes[4];
00522     
00523   databytes[0] = COMMAND_MODE;
00524   databytes[1] = command;    
00525   databytes[2] = COMMAND_MODE;
00526   databytes[3] = param1; 
00527   _i2c->write(_writeOpcode, databytes, 4);    // Write command   
00528 #else  
00529 
00530   _i2c->start();
00531   _i2c->write(_writeOpcode);
00532   
00533   _i2c->write(COMMAND_MODE);      
00534   _i2c->write(command);       // Write Command   
00535   _i2c->write(COMMAND_MODE);      
00536   _i2c->write(param1);        // Write Param1   
00537 
00538   _i2c->stop();
00539 #endif  
00540 }
00541 
00542 /** @brief Write command that has two parameters
00543 */ 
00544 void SSD1308::_sendCommand(uint8_t command, uint8_t param1, uint8_t param2) {
00545 
00546 //  Note continuationbit is set, so COMMAND_MODE must be
00547 //  repeated before each databyte that serves as parameter!
00548 #if (I2C_OPTIMIZE == 0)
00549   char databytes[6];
00550     
00551   databytes[0] = COMMAND_MODE;
00552   databytes[1] = command;    
00553   databytes[2] = COMMAND_MODE;
00554   databytes[3] = param1; 
00555   databytes[4] = COMMAND_MODE;
00556   databytes[5] = param2; 
00557   _i2c->write(_writeOpcode, databytes, 6);    // Write command   
00558 #else  
00559   _i2c->start();
00560   _i2c->write(_writeOpcode);
00561   
00562   _i2c->write(COMMAND_MODE);      
00563   _i2c->write(command);       // Write Command   
00564   _i2c->write(COMMAND_MODE);      
00565   _i2c->write(param1);        // Write Param1   
00566   _i2c->write(COMMAND_MODE);      
00567   _i2c->write(param2);        // Write Param2   
00568 
00569   _i2c->stop();
00570  #endif 
00571 }
00572 
00573 /** @brief Write command that has five parameters
00574 */ 
00575 void SSD1308::_sendCommand(uint8_t command, uint8_t param1, uint8_t param2,
00576                                             uint8_t param3, uint8_t param4,
00577                                             uint8_t param5) {
00578 
00579 //  Note continuationbit is set, so COMMAND_MODE must be
00580 //  repeated before each databyte that serves as parameter!
00581 #if (I2C_OPTIMIZE == 0)
00582   char databytes[12];
00583     
00584   databytes[0] = COMMAND_MODE;
00585   databytes[1] = command;    
00586   databytes[2] = COMMAND_MODE;
00587   databytes[3] = param1; 
00588   databytes[4] = COMMAND_MODE;
00589   databytes[5] = param2; 
00590   databytes[6] = COMMAND_MODE;
00591   databytes[7] = param3; 
00592   databytes[8] = COMMAND_MODE;
00593   databytes[9] = param4; 
00594   databytes[10] = COMMAND_MODE;
00595   databytes[11] = param5;       
00596   _i2c->write(_writeOpcode, databytes, 12);    // Write command   
00597 #else  
00598   _i2c->start();
00599   _i2c->write(_writeOpcode);
00600   
00601   _i2c->write(COMMAND_MODE);      
00602   _i2c->write(command);       // Write Command   
00603   _i2c->write(COMMAND_MODE);      
00604   _i2c->write(param1);        // Write Param1   
00605   _i2c->write(COMMAND_MODE);      
00606   _i2c->write(param2);        // Write Param2   
00607   _i2c->write(COMMAND_MODE);      
00608   _i2c->write(param3);        // Write Param3   
00609   _i2c->write(COMMAND_MODE);      
00610   _i2c->write(param4);        // Write Param4   
00611   _i2c->write(COMMAND_MODE);      
00612   _i2c->write(param5);        // Write Param5   
00613 
00614   _i2c->stop();
00615 #endif  
00616 }
00617 
00618 
00619 /** @brief Write command that has six parameters
00620 */ 
00621 void SSD1308::_sendCommand(uint8_t command, uint8_t param1, uint8_t param2,
00622                                             uint8_t param3, uint8_t param4,
00623                                             uint8_t param5, uint8_t param6) {
00624 
00625 //  Note continuationbit is set, so COMMAND_MODE must be
00626 //  repeated before each databyte that serves as parameter!
00627 #if (I2C_OPTIMIZE == 0)
00628   char databytes[14];
00629     
00630   databytes[0] = COMMAND_MODE;
00631   databytes[1] = command;    
00632   databytes[2] = COMMAND_MODE;
00633   databytes[3] = param1; 
00634   databytes[4] = COMMAND_MODE;
00635   databytes[5] = param2; 
00636   databytes[6] = COMMAND_MODE;
00637   databytes[7] = param3; 
00638   databytes[8] = COMMAND_MODE;
00639   databytes[9] = param4; 
00640   databytes[10] = COMMAND_MODE;
00641   databytes[11] = param5;   
00642   databytes[12] = COMMAND_MODE;
00643   databytes[13] = param6;       
00644   _i2c->write(_writeOpcode, databytes, 14);    // Write command   
00645 #else  
00646   _i2c->start();
00647   _i2c->write(_writeOpcode);
00648   
00649   _i2c->write(COMMAND_MODE);      
00650   _i2c->write(command);       // Write Command   
00651   _i2c->write(COMMAND_MODE);      
00652   _i2c->write(param1);        // Write Param1   
00653   _i2c->write(COMMAND_MODE);      
00654   _i2c->write(param2);        // Write Param2   
00655   _i2c->write(COMMAND_MODE);      
00656   _i2c->write(param3);        // Write Param3   
00657   _i2c->write(COMMAND_MODE);      
00658   _i2c->write(param4);        // Write Param4   
00659   _i2c->write(COMMAND_MODE);      
00660   _i2c->write(param5);        // Write Param5   
00661   _i2c->write(COMMAND_MODE);      
00662   _i2c->write(param6);        // Write Param6   
00663 
00664   _i2c->stop();
00665 #endif  
00666 }
00667 
00668 
00669 #if(0)
00670 /** @brief Write command that has multiple parameters
00671 */ 
00672 void SSD1308::_sendCommands(uint8_t len, uint8_t* commands) {
00673 
00674 //  I2Cdev::writeBytes(m_devAddr, COMMAND_MODE, len, commands);
00675 //  Note this original code is not correct, continuationbit is set, 
00676 //  so COMMAND_MODE must be repeated before each databyte that serves as parameter!
00677 
00678   _i2c->start();
00679   _i2c->write(_writeOpcode);
00680   
00681   for (int i=0; i<len ; i++) {
00682     _i2c->write(COMMAND_MODE);      
00683     _i2c->write(commands[i]);  // Write Commands   
00684   }
00685   _i2c->stop();
00686   
00687 }
00688 #endif
00689 
00690 /** @brief Write databyte to display
00691  *  @brief Start at current cursor location
00692  *  @param uint8_t data databyte to write
00693 */
00694 void SSD1308::_sendData(uint8_t data){
00695 
00696 #if (I2C_OPTIMIZE == 0)
00697 //I2C Blockwrite versions dont seem to work ?
00698 //That may be related to fact that the SSD1308/SSD1306 does NOT return an acknowledge: blockwrite may abort the operation
00699 //Noted for mbed lib v63 on 20/7/13 
00700   char databytes[2];
00701     
00702   databytes[0] = DATA_MODE;
00703   databytes[1] = data;    
00704   _i2c->write(_writeOpcode, databytes, 2);    // Write Data   
00705 
00706 #else
00707   _i2c->start();
00708   _i2c->write(_writeOpcode);
00709   _i2c->write(DATA_MODE);  
00710   _i2c->write(data); 
00711   _i2c->stop();  
00712 #endif
00713 
00714 }
00715 
00716 /** @brief Write len bytes from buffer data to display, 
00717  *  @brief Start at current cursor location
00718  *  @param uint8_t len number of bytes to write 
00719  *  @param uint8_t* data pointer to data
00720 */
00721 void SSD1308::_sendData(uint8_t len, uint8_t* data) {
00722 //  I2Cdev::writeBytes(m_devAddr, DATA_MODE, len, data);
00723 #if (I2C_OPTIMIZE == 0)
00724   for (int i=0; i<len ; i++) {
00725     _sendData(data[i]);  // Write Data   
00726   }
00727 #else  
00728   _i2c->start();
00729   _i2c->write(_writeOpcode);
00730   _i2c->write(DATA_MODE);  
00731   for (int i=0; i<len ; i++) {
00732     _i2c->write(data[i]);  // Write Data   
00733   }
00734   _i2c->stop();
00735 #endif 
00736 }
00737 
00738 
00739 /** @brief Set Horizontal Addressing Mode (cursor incr left-to-right, top-to-bottom)
00740  * 
00741  */
00742 void SSD1308::setHorizontalAddressingMode(){
00743   setMemoryAddressingMode(HORIZONTAL_ADDRESSING_MODE); 
00744 }
00745 
00746 /** @brief Set Vertical Addressing Mode  (cursor incr top-to-bottom, left-to-right)
00747  * 
00748  */
00749 void SSD1308::setVerticalAddressingMode() {
00750   setMemoryAddressingMode(VERTICAL_ADDRESSING_MODE); 
00751 }
00752 
00753 /** @brief Set Page Addressing Mode  (cursor incr left-to-right)
00754  * 
00755  */
00756 void SSD1308::setPageAddressingMode(){
00757   setMemoryAddressingMode(PAGE_ADDRESSING_MODE); 
00758 }
00759     
00760 /** @brief Set Addressing Mode
00761  *  @param uint8_t mode 
00762  */
00763 void SSD1308::setMemoryAddressingMode(uint8_t mode){
00764 
00765   _sendCommand(SET_MEMORY_ADDRESSING_MODE, mode);   
00766 }
00767 
00768 
00769 /** @param uint8_t start startpage (valid range 0..MAX_PAGE)
00770  *  @param uint8_t end   endpage   (valid range start..MAX_PAGE)
00771  */
00772 void SSD1308::setPageAddress (uint8_t start, uint8_t end) {
00773 
00774   _sendCommand(SET_PAGE_ADDRESS, start, end);   
00775 }
00776 
00777 
00778 /** @param uint8_t start startcolumn (valid range 0..MAX_COL)
00779  *  @param uint8_t end   endcolumn   (valid range start..MAX_COL)
00780  */
00781 void SSD1308::setColumnAddress (uint8_t start, uint8_t end) {
00782 
00783   _sendCommand(SET_COLUMN_ADDRESS, start, end);     
00784 }
00785 
00786 /** 
00787  *  @brief Set Display StartLine, takes one byte, 0x00-0x3F
00788  *  @param uint8_t line startline (valid range 0..MAX_ROWS)
00789  */  
00790 void SSD1308::setDisplayStartLine(uint8_t line) {
00791 
00792   line = line & MAX_ROW;
00793    
00794   _sendCommand(SET_DISPLAY_START_LINE | line);     
00795 }
00796 
00797 
00798 /** 
00799  *  @brief Set Column Start (for Page Addressing Mode only)
00800  *  @param uint8_t column column start (valid range 0..MAX_COL)
00801  */  
00802 void SSD1308::setColumnStartForPageAddressingMode(uint8_t column) {
00803 
00804   column = column & MAX_COL;
00805 
00806   _sendCommand(SET_LOWER_COLUMN  | ( column     & 0x0F));  // lower nibble   
00807   _sendCommand(SET_HIGHER_COLUMN | ((column>>4) & 0x0F));  // higher nibble     
00808 }
00809 
00810 
00811 /** 
00812  *  @brief Set Page Start (for Page Addressing Mode only)
00813  *  @param uint8_t page page start (valid range PAGE0 - PAGE7)
00814  */    
00815 void SSD1308::setPageStartForPageAddressingMode(uint8_t page) {
00816 
00817   page = page & MAX_PAGE;
00818 
00819   _sendCommand(SET_PAGE_START_ADDRESS | page);
00820  
00821 }
00822 
00823 
00824 /** @brief Set Contrast
00825  *  @param uint8_t contrast (valid range 0x00 (lowest) - 0xFF (highest))
00826 */
00827 void SSD1308::setContrastControl(uint8_t contrast) {
00828   
00829     _sendCommand(SET_CONTRAST, contrast);  
00830 } 
00831 
00832 /** @brief Enable Display
00833 */ 
00834 void SSD1308::setDisplayOn() {
00835   _sendCommand(SET_DISPLAY_POWER_ON);
00836 }
00837 
00838 /** @brief Disable Display
00839 */ 
00840 void SSD1308::setDisplayOff() {
00841   _sendCommand(SET_DISPLAY_POWER_OFF);
00842 }
00843 
00844 /** @brief Enable or Disable Display
00845  *  @param bool on
00846  */
00847 void SSD1308::setDisplayPower(bool on) {
00848   if (on) {
00849     setDisplayOn();
00850   } else {
00851     setDisplayOff();
00852   }
00853 }
00854 
00855 /** @brief Show White pixels on Black background
00856  */ 
00857 void SSD1308::setDisplayNormal() {
00858   _sendCommand(SET_NORMAL_DISPLAY);
00859 }
00860 
00861 /** @brief Show Black pixels on White background
00862  */ 
00863 void SSD1308::setDisplayInverse() {
00864   _sendCommand(SET_INVERSE_DISPLAY);
00865 }
00866 
00867 /** @brief Blink display by fading in and out over a set number of frames
00868  *  @param bool on
00869  */
00870 void SSD1308::setDisplayBlink(bool on){
00871   if (on) {
00872     _sendCommand(SET_FADE_BLINK, (BLINK_ENABLE | FADE_INTERVAL_128_FRAMES));
00873   }
00874   else {  
00875     _sendCommand(SET_FADE_BLINK, FADE_BLINK_DISABLE);  
00876   }
00877 }       
00878 
00879 
00880 /** @brief Fade out display in set number of frames
00881  *  @param bool on
00882  */
00883 void SSD1308::setDisplayFade(bool on) {
00884   if (on) {
00885     _sendCommand(SET_FADE_BLINK, (FADE_OUT_ENABLE | FADE_INTERVAL_128_FRAMES));
00886   }
00887   else {  
00888     _sendCommand(SET_FADE_BLINK, FADE_BLINK_DISABLE);  
00889   }
00890 }    
00891 
00892 /** @brief Display Flip (Left/Right, Up/Down)
00893  *  @param bool left flip Left/Right
00894  *  @param bool down flip Up/Down
00895  */
00896 void SSD1308::setDisplayFlip(bool left, bool down) {
00897   if (left) {
00898     // column address   0 is mapped to SEG0 (Reset)    
00899     _sendCommand(SET_SEGMENT_REMAP_0);
00900   }
00901   else {
00902     // column address 127 is mapped to SEG0    
00903     _sendCommand(SET_SEGMENT_REMAP_127);
00904   }  
00905 
00906   if (down) {
00907     // Reset mode
00908     _sendCommand(SET_COMMON_REMAP_0);    
00909   }
00910   else {
00911     // Flip Up/Down (Need to rewrite display before H effect shows)
00912     _sendCommand(SET_COMMON_REMAP_63);        
00913   }  
00914 
00915 }
00916 
00917 /** @brief Sets Internal Iref
00918  */
00919 void SSD1308::setInternalIref() {
00920 //  uint8_t cmds[2] = {SET_IREF_SELECTION, INTERNAL_IREF};
00921 //  _sendCommands(2, cmds); 
00922   
00923   _sendCommand(SET_IREF_SELECTION, INTERNAL_IREF);   
00924 }
00925 
00926 /** @brief Sets External Iref (default)
00927  */
00928 void SSD1308::setExternalIref() {
00929 //  uint8_t cmds[2] = {SET_IREF_SELECTION, EXTERNAL_IREF};
00930 //  _sendCommands(2, cmds); 
00931   _sendCommand(SET_IREF_SELECTION, EXTERNAL_IREF); 
00932 }
00933 
00934 
00935 /** @brief Shows All Pixels On
00936  */
00937 void SSD1308::setEntireDisplayOn(){
00938   _sendCommand(SET_ENTIRE_DISPLAY_ON); 
00939 }
00940 
00941 /** @brief Shows Pixels as RAM content
00942  */
00943 void SSD1308::setEntireDisplayRAM(){
00944   _sendCommand(SET_DISPLAY_GDDRAM); 
00945 }
00946 
00947 /** @brief Shows Pixels On or as RAM content
00948  *  @param bool on (true is All on, false is RAM content)
00949  */
00950 void SSD1308::setEntireDisplay(bool on){
00951   if (on) {
00952     setEntireDisplayOn();  // All Pixels on
00953   }
00954   else {  
00955     setEntireDisplayRAM(); // Pixels are RAM content
00956   }
00957 }
00958 
00959 
00960 /** @brief Horizontal scroll by one column per interval
00961  *  @param bool left select Left/Right scroll
00962  *  @param uint8_t start_page begin page   (0..MAX_PAGE)
00963  *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)                     
00964  *  @param uint8_t interval   scroll interval in frames (see codes above)                      
00965  */  
00966 void SSD1308::setContinuousHorizontalScroll(bool left, uint8_t start_page, uint8_t end_page, uint8_t interval) {
00967   if (left) {
00968     _sendCommand(SET_LEFT_HOR_SCROLL, 0x00, start_page, interval, end_page, 0x00, 0xFF);  // Scroll Left
00969   }
00970   else {  
00971     _sendCommand(SET_RIGHT_HOR_SCROLL, 0x00, start_page, interval, end_page, 0x00, 0xFF); // Scroll Right  
00972   }
00973 
00974 }
00975 
00976 
00977 /** @brief Horizontal and Vertical scroll by one column per interval
00978  *  @param bool left select Left/Right scroll
00979  *  @param uint8_t start_page begin page   (0..MAX_PAGE)
00980  *  @param uint8_t end_page   end page     (start_page..MAX_PAGE)                     
00981  *  @param uint8_t offset     vert offset  (0x01..0x63)                       
00982  *  @param uint8_t interval   scroll interval in frames (see codes above)                       
00983  */  
00984 void SSD1308::setContinuousVerticalAndHorizontalScroll(bool left, uint8_t start_page, uint8_t end_page, 
00985                                                        uint8_t offset, uint8_t interval) {
00986   if (left) {
00987     _sendCommand(SET_VERT_LEFT_HOR_SCROLL, 0x00, start_page, interval, end_page, offset);  // Scroll Left
00988   }
00989   else {  
00990     _sendCommand(SET_VERT_RIGHT_HOR_SCROLL, 0x00, start_page, interval, end_page, offset); // Scroll Right  
00991   }
00992                                                        
00993 }    
00994 
00995 /** @brief Set Vertical scroll area
00996  *  @param uint8_t topRowsFixed      fixed rows   (0..MAX_ROW)                     
00997  *  @param uint8_t scrollRowsoffset  scroll rows  (topRowsFixed..ROWS)                       
00998  */  
00999 void SSD1308::setVerticalScrollArea(uint8_t topRowsFixed, uint8_t scrollRows) { 
01000    
01001   if ((topRowsFixed + scrollRows) > ROWS) {
01002      scrollRows = ROWS - topRowsFixed; 
01003   };
01004   
01005   _sendCommand(SET_VERTICAL_SCROLL_AREA, topRowsFixed, scrollRows); 
01006 }
01007 
01008 /** @brief Activate or Deactivate Horizontal and Vertical scroll
01009  *  @brief Note: after deactivating scrolling, the RAM data needs to be rewritten
01010  *  @param bool on activate scroll 
01011  */  
01012 void SSD1308::setDisplayScroll(bool on) {
01013   if (on) {
01014     _sendCommand(SET_ACTIVATE_SCROLL);   // Scroll on
01015   }
01016   else {  
01017     _sendCommand(SET_DEACTIVATE_SCROLL); // Scroll off  
01018   }
01019 }
01020 
01021 
01022 
01023 /** @brief Low level Init
01024  *  @brief Init the configuration registers in accordance with the datasheet
01025  */
01026 void SSD1308::_init() {
01027 
01028   _sendCommand(SET_DISPLAY_POWER_OFF);      // 0xAE
01029   
01030   // column address   0 is mapped to SEG0 (Reset)    
01031   // row address   0 is mapped to COM0 (Reset)      
01032   _sendCommand(SET_SEGMENT_REMAP_0);        // 0xA0 (Reset)
01033   _sendCommand(SET_COMMON_REMAP_0);         // 0xC0 (Reset) 
01034 
01035   setDisplayStartLine(0);                   // 0x40 (Reset) 
01036   
01037   _sendCommand(SET_COMMON_CONF, COMMON_BASE | COMMON_ALTERNATIVE | COMMON_LEFTRIGHT_NORMAL); // 0xDA, 0x12 (Reset)
01038 
01039   // Pagemode or Horizontal mode
01040 //  setPageAddressingMode();                  // 0x20, 0x02 (Reset)  
01041 //  setColumnStartForPageAddressingMode(0);   // 0x00, 0x10 (Reset = Column 0)
01042 //  setPageStartForPageAddressingMode(PAGE_0);// 0xBO       (Reset = Page 0)
01043   setHorizontalAddressingMode();            // 0x20, 0x00 (Non-Reset)
01044   setColumnAddress (0, MAX_COL);             // 0x21, 0x00, 0x37 (Reset)
01045   setPageAddress (0, MAX_PAGE);              // 0x22, 0x00, 0x07 (Reset)
01046 
01047   setExternalIref();                        // 0xAD, 0x10 (Reset)
01048   
01049   _sendCommand(SET_DISPLAY_CLOCK, 0x70);    // 0xD5, 0x70 (Reset = 0x80)
01050   _sendCommand(SET_PRECHARGE_TIME, 0x21);   // 0xD9, 0x21 (Reset = 0x22)
01051   _sendCommand(SET_VCOMH_DESELECT_LEVEL, 0x30); // 0xDB, 0x30 (Reset = 0x20)  
01052   _sendCommand(SET_MULTIPLEX_RATIO, 0x3F);  // 0xA8, 0x3F (Reset)  
01053   _sendCommand(SET_DISPLAY_OFFSET, 0x00);   // 0xD3, 0x00 (Reset)  
01054   
01055   _sendCommand(SET_CONTRAST, 0x7F);         // 0x81, 0x7F (Reset)
01056 
01057   _sendCommand(SET_NORMAL_DISPLAY);         // 0xA6 (Reset)
01058   
01059   setEntireDisplayRAM();                    // 0xA4 (Reset)
01060   setDisplayScroll(false);
01061   
01062   clearDisplay();   
01063   
01064   _sendCommand(SET_DISPLAY_POWER_ON);       // 0xAF
01065 }
01066