SPKDisplay - A mbed display class and processing imaging tools for 128x64 OLEDs using the SSD1305 driver, connected via SPI.

Dependents:   SPK-DVIMXR SPK-DMXer

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers spk_oled_ssd1305.cpp Source File

spk_oled_ssd1305.cpp

00001 // OLED display using SSD1305 driver
00002 // A library by *spark audio-visual
00003 
00004 /* Copyright (c) 2011 Toby Harris, MIT License
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
00007  * and associated documentation files (the "Software"), to deal in the Software without restriction, 
00008  * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
00009  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
00010  * furnished to do so, subject to the following conditions:
00011  *
00012  * The above copyright notice and this permission notice shall be included in all copies or 
00013  * substantial portions of the Software.
00014  *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
00016  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
00017  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
00018  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
00019  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00020  */
00021  
00022 #include "spk_oled_ssd1305.h"
00023 #include "mbed.h"
00024 
00025 SPKDisplay::SPKDisplay(PinName mosiPin, PinName clkPin, PinName csPin, PinName dcPin, PinName resPin, Serial *debugSerial)
00026 {
00027     bufferHasChanged = false;
00028     
00029     fontStartCharacter = NULL;
00030     fontEndCharacter = NULL;
00031     fontCharacters = NULL;
00032     
00033     spi = new SPI(mosiPin, NC, clkPin);
00034     spi->format(8,3);
00035     spi->frequency(2000000);
00036     
00037     cs = new DigitalOut(csPin);
00038     dc = new DigitalOut(dcPin);
00039     res = new DigitalOut(resPin);
00040     
00041     // Link up debug Serial object
00042     // Passing in shared object as debugging is shared between all DVI mixer functions
00043     debug = debugSerial;
00044     
00045     setup();
00046     
00047     clearBuffer();
00048     
00049     if (debug) debug->printf("SPKDisplay loaded\n\r");
00050 }
00051 
00052 void SPKDisplay::clearBuffer()
00053 {
00054     memset(buffer, 0, bufferCount);
00055     bufferHasChanged = true;
00056 }
00057 
00058 void SPKDisplay::imageToBuffer(const uint8_t* image)
00059 {
00060     memcpy(buffer, image, bufferCount);
00061     bufferHasChanged = true;
00062 }
00063 
00064 void SPKDisplay::clearBufferRow(int row)
00065 {
00066     // Range check
00067     if (row >= 8)
00068     {
00069         if (debug) debug->printf("SPKDisplay::clearBufferRow sent out of bounds row");
00070         return;
00071     }
00072     int bStart = row*bufferWidth;
00073     int bEnd = bStart + pixelWidth;
00074 
00075     for (int bPos = bStart; bPos <= bEnd; bPos++)
00076     {
00077         buffer[bPos] = 0x00;
00078     }
00079     
00080     bufferHasChanged = true;
00081 }
00082 
00083 void SPKDisplay::horizLineToBuffer(int y)
00084 {
00085     if (y >= pixelHeight)
00086     {
00087         if (debug) debug->printf("SPKDisplay::clearBufferRow sent out of bounds y");
00088         return;
00089     }
00090     
00091     int row = (y*pixInPage) / pixelHeight;
00092     int posInRow = y % pixInPage;
00093     
00094     int bStart = row*bufferWidth;
00095     int bEnd = bStart + pixelWidth;
00096     
00097     for (int bPos = bStart; bPos <= bEnd; bPos++)
00098     {
00099         // Need to bitwise OR as setting single bit (the line) in byte (the row)
00100         buffer[bPos] = buffer[bPos] | 0x01 << posInRow;
00101     } 
00102     
00103     bufferHasChanged = true;
00104 }
00105 
00106 void SPKDisplay::textToBuffer(std::string message, int row)
00107 {
00108     // Font check
00109     if (NULL == fontCharacters) return;
00110     if (NULL == fontStartCharacter || NULL == fontEndCharacter) return;    
00111 
00112     // Range check
00113     if (row >= 8) row = 7;
00114     int bStart = row*bufferWidth;
00115     int bEnd = bStart + pixelWidth;
00116 
00117     int bPos = bStart;
00118     for (int i = 0; i < message.size(); i++)
00119     {
00120         char character = message.at(i);
00121         
00122         // Is it outside the range we have glyphs for?
00123         if ((character < *fontStartCharacter) || (character > *fontEndCharacter))
00124         {
00125             // Treat as a space
00126             for (int j = 0; j < 5; j++)
00127             {
00128                 if (bPos >= bEnd) break;
00129                 buffer[bPos++] = 0x00;
00130             }
00131             
00132             // Warn if not
00133             if (debug)
00134             {
00135                 if (character != ' ') debug->printf("No glyph for character %c at position %i", character, i);
00136             }
00137         }
00138         // If not, typeset it!
00139         else 
00140         {
00141             // Shift into our array's indexing
00142             character -= *fontStartCharacter;
00143             
00144             // Write each byte's vertical column of 8bits into the buffer.
00145             for (int j = 0; j < fontCharacters[character][0]; j++)
00146             {
00147                 if (bPos >= bEnd) break;
00148                 buffer[bPos++] = fontCharacters[character][j+1];
00149             }
00150             
00151             // Put 1px letter spacing at end
00152             if (bPos >= bEnd) break;
00153             buffer[bPos++] = 0x00; // 1 px letter spacing
00154         }
00155     }
00156     
00157     bufferHasChanged = true;
00158 }
00159 
00160 void SPKDisplay::characterToBuffer(char character, int x, int row)
00161 {
00162         // Font check
00163     if (NULL == fontCharacters) return;
00164     if (NULL == fontStartCharacter || NULL == fontEndCharacter) return;    
00165 
00166     // Range check
00167     if (row >= 8) row = 7;
00168     int bStart = row*bufferWidth;
00169     int bEnd = bStart + pixelWidth;
00170 
00171     int bPos = bStart + x;
00172         
00173     // Is it outside the range we have glyphs for?
00174     if ((character < *fontStartCharacter) || (character > *fontEndCharacter))
00175     {
00176         if (debug)
00177         {
00178             if (character != ' ') debug->printf("No glyph for character %c", character);
00179         }
00180     }
00181     // If not, typeset it!
00182     else 
00183     {
00184         // Shift into our array's indexing
00185         character -= *fontStartCharacter;
00186         
00187         // Write each byte's vertical column of 8bits into the buffer.
00188         for (int j = 0; j < fontCharacters[character][0]; j++)
00189         {
00190             if (bPos >= bEnd) break;
00191             buffer[bPos++] = fontCharacters[character][j+1];
00192         }
00193     }
00194 
00195     bufferHasChanged = true;
00196 }
00197 
00198 void SPKDisplay::sendBuffer()
00199 {
00200     if (bufferHasChanged)
00201     {
00202         // Select the device by seting chip select low
00203         *cs = 0;
00204     
00205         // Set to receive DATA not commands
00206         *dc = 1;
00207     
00208         for (int i = 0; i < bufferCount; i++)
00209         {
00210             spi->write(buffer[i]);
00211         }
00212         
00213         // Deselect the device
00214         *cs = 1;
00215         
00216         bufferHasChanged = false;
00217     }
00218 }
00219 
00220 void SPKDisplay::setup()
00221 {
00222     // TASK: SCREEN OFF, Run pre-flight
00223     
00224     // Hard reset the OLED
00225     *res = 0;
00226     wait_ms(1);
00227     *res = 1;
00228 
00229     // Select the device by seting chip select low
00230     *cs = 0;
00231     
00232     // Set to receive COMMANDS not data
00233     *dc = 0;
00234 
00235     spi->write(0xAE); // set display off
00236     spi->write(0xD5); // set display clock divide ratio
00237     spi->write(0xA0);
00238     spi->write(0xA8); // set multiplex ratio
00239     spi->write(0x3F); 
00240     spi->write(0xD3); // set display offset
00241     spi->write(0x00);
00242     spi->write(0x40); // set display start line
00243     spi->write(0xAD); // set master configuration
00244     spi->write(0x8E);
00245     spi->write(0xD8); // set area color mode
00246     spi->write(0x05);
00247     spi->write(0xA1); // set segment re-map
00248     spi->write(0xC8); // set com output scan direction
00249     spi->write(0xDA); // set com pins hardware configuration
00250     spi->write(0x12);
00251     spi->write(0x91); // set look-up table
00252     spi->write(0x3F);
00253     spi->write(0x3F);
00254     spi->write(0x3F);
00255     spi->write(0x3F);
00256     spi->write(0x81); // set current control for bank 0
00257     spi->write(0x8F);
00258     spi->write(0xD9); // set pre-charge period
00259     spi->write(0xD2);
00260     spi->write(0xDB); //set vcomh deselect level
00261     spi->write(0x34);
00262     spi->write(0xA4); // set entire display on/off
00263     spi->write(0xA6); // set normal/inverse display
00264     
00265     spi->write(0x20); // page mode
00266     spi->write(0x00);
00267     
00268     // TASK: Clear screen's content buffer
00269     
00270     // Is this neccessary when switching command/data?
00271     *cs = 1;
00272     wait_ms(1);
00273     *cs = 0;
00274     
00275     // Set to receive DATA not commands
00276     *dc = 1;
00277         
00278     for (int i = 0; i < bufferCount; i++)
00279     {
00280         spi->write(0x00);
00281     }
00282     
00283     // TASK: SCREEN ON
00284     
00285     // Is this neccessary when switching command/data?
00286     *cs = 1;
00287     wait_ms(1);
00288     *cs = 0;
00289     
00290     // Set to receive COMMANDS not data
00291     *dc = 0;
00292     
00293     spi->write(0xAF); // set display on
00294   
00295     // Deselect the device
00296     *cs = 1;
00297 }