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

Dependents:   SPK-DVIMXR SPK-DMXer

Committer:
tobyspark
Date:
Thu Aug 02 13:26:18 2012 +0000
Revision:
3:ade83210ecf6
Parent:
1:dd3faa2ab1dd
Child:
4:a675a19c16f0
MIT License as per MBED guideline

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tobyspark 0:76bb084fa033 1 // OLED display using SSD1305 driver
tobyspark 3:ade83210ecf6 2 // A library by *spark audio-visual
tobyspark 3:ade83210ecf6 3
tobyspark 3:ade83210ecf6 4 /* Copyright (c) 2011 Toby Harris, MIT License
tobyspark 3:ade83210ecf6 5 *
tobyspark 3:ade83210ecf6 6 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
tobyspark 3:ade83210ecf6 7 * and associated documentation files (the "Software"), to deal in the Software without restriction,
tobyspark 3:ade83210ecf6 8 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
tobyspark 3:ade83210ecf6 9 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
tobyspark 3:ade83210ecf6 10 * furnished to do so, subject to the following conditions:
tobyspark 3:ade83210ecf6 11 *
tobyspark 3:ade83210ecf6 12 * The above copyright notice and this permission notice shall be included in all copies or
tobyspark 3:ade83210ecf6 13 * substantial portions of the Software.
tobyspark 3:ade83210ecf6 14 *
tobyspark 3:ade83210ecf6 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
tobyspark 3:ade83210ecf6 16 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
tobyspark 3:ade83210ecf6 17 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
tobyspark 3:ade83210ecf6 18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
tobyspark 3:ade83210ecf6 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
tobyspark 3:ade83210ecf6 20 */
tobyspark 1:dd3faa2ab1dd 21
tobyspark 0:76bb084fa033 22 #include "spk_oled_ssd1305.h"
tobyspark 0:76bb084fa033 23 #include "mbed.h"
tobyspark 0:76bb084fa033 24
tobyspark 0:76bb084fa033 25 SPKDisplay::SPKDisplay(PinName mosiPin, PinName clkPin, PinName csPin, PinName dcPin, PinName resPin, Serial *debugSerial)
tobyspark 0:76bb084fa033 26 {
tobyspark 0:76bb084fa033 27 bufferHasChanged = false;
tobyspark 0:76bb084fa033 28
tobyspark 1:dd3faa2ab1dd 29 fontStartCharacter = NULL;
tobyspark 1:dd3faa2ab1dd 30 fontEndCharacter = NULL;
tobyspark 1:dd3faa2ab1dd 31 fontCharacters = NULL;
tobyspark 1:dd3faa2ab1dd 32
tobyspark 0:76bb084fa033 33 spi = new SPI(mosiPin, NC, clkPin);
tobyspark 0:76bb084fa033 34 spi->format(8,3);
tobyspark 0:76bb084fa033 35 spi->frequency(2000000);
tobyspark 0:76bb084fa033 36
tobyspark 0:76bb084fa033 37 cs = new DigitalOut(csPin);
tobyspark 0:76bb084fa033 38 dc = new DigitalOut(dcPin);
tobyspark 0:76bb084fa033 39 res = new DigitalOut(resPin);
tobyspark 0:76bb084fa033 40
tobyspark 0:76bb084fa033 41 // Link up debug Serial object
tobyspark 0:76bb084fa033 42 // Passing in shared object as debugging is shared between all DVI mixer functions
tobyspark 0:76bb084fa033 43 debug = debugSerial;
tobyspark 0:76bb084fa033 44
tobyspark 0:76bb084fa033 45 setup();
tobyspark 0:76bb084fa033 46
tobyspark 0:76bb084fa033 47 clearBuffer();
tobyspark 0:76bb084fa033 48
tobyspark 0:76bb084fa033 49 if (debug) debug->printf("SPKDisplay loaded\n\r");
tobyspark 0:76bb084fa033 50 }
tobyspark 0:76bb084fa033 51
tobyspark 0:76bb084fa033 52 void SPKDisplay::clearBuffer()
tobyspark 0:76bb084fa033 53 {
tobyspark 0:76bb084fa033 54 memset(buffer, 0, bufferCount);
tobyspark 0:76bb084fa033 55 bufferHasChanged = true;
tobyspark 0:76bb084fa033 56 }
tobyspark 0:76bb084fa033 57
tobyspark 1:dd3faa2ab1dd 58 void SPKDisplay::imageToBuffer(const uint8_t* image)
tobyspark 0:76bb084fa033 59 {
tobyspark 0:76bb084fa033 60 memcpy(buffer, image, bufferCount);
tobyspark 0:76bb084fa033 61 bufferHasChanged = true;
tobyspark 0:76bb084fa033 62 }
tobyspark 0:76bb084fa033 63
tobyspark 0:76bb084fa033 64 void SPKDisplay::clearBufferRow(int row)
tobyspark 0:76bb084fa033 65 {
tobyspark 0:76bb084fa033 66 // Range check
tobyspark 0:76bb084fa033 67 if (row >= 8)
tobyspark 0:76bb084fa033 68 {
tobyspark 0:76bb084fa033 69 if (debug) debug->printf("SPKDisplay::clearBufferRow sent out of bounds row");
tobyspark 0:76bb084fa033 70 return;
tobyspark 0:76bb084fa033 71 }
tobyspark 0:76bb084fa033 72 int bStart = row*bufferWidth;
tobyspark 0:76bb084fa033 73 int bEnd = bStart + pixelWidth;
tobyspark 0:76bb084fa033 74
tobyspark 0:76bb084fa033 75 for (int bPos = bStart; bPos <= bEnd; bPos++)
tobyspark 0:76bb084fa033 76 {
tobyspark 0:76bb084fa033 77 buffer[bPos] = 0x00;
tobyspark 0:76bb084fa033 78 }
tobyspark 0:76bb084fa033 79
tobyspark 0:76bb084fa033 80 bufferHasChanged = true;
tobyspark 0:76bb084fa033 81 }
tobyspark 0:76bb084fa033 82
tobyspark 0:76bb084fa033 83 void SPKDisplay::horizLineToBuffer(int y)
tobyspark 0:76bb084fa033 84 {
tobyspark 0:76bb084fa033 85 if (y >= pixelHeight)
tobyspark 0:76bb084fa033 86 {
tobyspark 0:76bb084fa033 87 if (debug) debug->printf("SPKDisplay::clearBufferRow sent out of bounds y");
tobyspark 0:76bb084fa033 88 return;
tobyspark 0:76bb084fa033 89 }
tobyspark 0:76bb084fa033 90
tobyspark 0:76bb084fa033 91 int row = (y*pixInPage) / pixelHeight;
tobyspark 0:76bb084fa033 92 int posInRow = y % pixInPage;
tobyspark 0:76bb084fa033 93
tobyspark 0:76bb084fa033 94 int bStart = row*bufferWidth;
tobyspark 0:76bb084fa033 95 int bEnd = bStart + pixelWidth;
tobyspark 0:76bb084fa033 96
tobyspark 0:76bb084fa033 97 for (int bPos = bStart; bPos <= bEnd; bPos++)
tobyspark 0:76bb084fa033 98 {
tobyspark 0:76bb084fa033 99 // Need to bitwise OR as setting single bit (the line) in byte (the row)
tobyspark 0:76bb084fa033 100 buffer[bPos] = buffer[bPos] | 0x01 << posInRow;
tobyspark 0:76bb084fa033 101 }
tobyspark 0:76bb084fa033 102
tobyspark 0:76bb084fa033 103 bufferHasChanged = true;
tobyspark 0:76bb084fa033 104 }
tobyspark 0:76bb084fa033 105
tobyspark 0:76bb084fa033 106 void SPKDisplay::textToBuffer(std::string message, int row)
tobyspark 0:76bb084fa033 107 {
tobyspark 1:dd3faa2ab1dd 108 // Font check
tobyspark 1:dd3faa2ab1dd 109 if (NULL == fontCharacters) return;
tobyspark 1:dd3faa2ab1dd 110 if (NULL == fontStartCharacter || NULL == fontEndCharacter) return;
tobyspark 1:dd3faa2ab1dd 111
tobyspark 0:76bb084fa033 112 // Range check
tobyspark 0:76bb084fa033 113 if (row >= 8) row = 7;
tobyspark 0:76bb084fa033 114 int bStart = row*bufferWidth;
tobyspark 0:76bb084fa033 115 int bEnd = bStart + pixelWidth;
tobyspark 0:76bb084fa033 116
tobyspark 0:76bb084fa033 117 int bPos = bStart;
tobyspark 0:76bb084fa033 118 for (int i = 0; i < message.size(); i++)
tobyspark 0:76bb084fa033 119 {
tobyspark 0:76bb084fa033 120 char character = message.at(i);
tobyspark 0:76bb084fa033 121
tobyspark 0:76bb084fa033 122 // Is it outside the range we have glyphs for?
tobyspark 1:dd3faa2ab1dd 123 if ((character < *fontStartCharacter) || (character > *fontEndCharacter))
tobyspark 0:76bb084fa033 124 {
tobyspark 0:76bb084fa033 125 // Treat as a space
tobyspark 0:76bb084fa033 126 for (int j = 0; j < 5; j++)
tobyspark 0:76bb084fa033 127 {
tobyspark 0:76bb084fa033 128 if (bPos >= bEnd) break;
tobyspark 0:76bb084fa033 129 buffer[bPos++] = 0x00;
tobyspark 0:76bb084fa033 130 }
tobyspark 0:76bb084fa033 131
tobyspark 0:76bb084fa033 132 // Warn if not
tobyspark 0:76bb084fa033 133 if (debug)
tobyspark 0:76bb084fa033 134 {
tobyspark 0:76bb084fa033 135 if (character != ' ') debug->printf("No glyph for character %c at position %i", character, i);
tobyspark 0:76bb084fa033 136 }
tobyspark 0:76bb084fa033 137 }
tobyspark 0:76bb084fa033 138 // If not, typeset it!
tobyspark 0:76bb084fa033 139 else
tobyspark 0:76bb084fa033 140 {
tobyspark 0:76bb084fa033 141 // Shift into our array's indexing
tobyspark 1:dd3faa2ab1dd 142 character -= *fontStartCharacter;
tobyspark 0:76bb084fa033 143
tobyspark 0:76bb084fa033 144 // Write each byte's vertical column of 8bits into the buffer.
tobyspark 1:dd3faa2ab1dd 145 for (int j = 0; j < fontCharacters[character][0]; j++)
tobyspark 0:76bb084fa033 146 {
tobyspark 0:76bb084fa033 147 if (bPos >= bEnd) break;
tobyspark 1:dd3faa2ab1dd 148 buffer[bPos++] = fontCharacters[character][j+1];
tobyspark 0:76bb084fa033 149 }
tobyspark 0:76bb084fa033 150
tobyspark 0:76bb084fa033 151 // Put 1px letter spacing at end
tobyspark 0:76bb084fa033 152 if (bPos >= bEnd) break;
tobyspark 0:76bb084fa033 153 buffer[bPos++] = 0x00; // 1 px letter spacing
tobyspark 0:76bb084fa033 154 }
tobyspark 0:76bb084fa033 155 }
tobyspark 0:76bb084fa033 156
tobyspark 0:76bb084fa033 157 bufferHasChanged = true;
tobyspark 0:76bb084fa033 158 }
tobyspark 0:76bb084fa033 159
tobyspark 0:76bb084fa033 160 void SPKDisplay::sendBuffer()
tobyspark 0:76bb084fa033 161 {
tobyspark 0:76bb084fa033 162 if (bufferHasChanged)
tobyspark 0:76bb084fa033 163 {
tobyspark 0:76bb084fa033 164 // Select the device by seting chip select low
tobyspark 0:76bb084fa033 165 *cs = 0;
tobyspark 0:76bb084fa033 166
tobyspark 0:76bb084fa033 167 // Set to receive DATA not commands
tobyspark 0:76bb084fa033 168 *dc = 1;
tobyspark 0:76bb084fa033 169
tobyspark 0:76bb084fa033 170 for (int i = 0; i < bufferCount; i++)
tobyspark 0:76bb084fa033 171 {
tobyspark 0:76bb084fa033 172 spi->write(buffer[i]);
tobyspark 0:76bb084fa033 173 }
tobyspark 0:76bb084fa033 174
tobyspark 0:76bb084fa033 175 // Deselect the device
tobyspark 0:76bb084fa033 176 *cs = 1;
tobyspark 0:76bb084fa033 177
tobyspark 0:76bb084fa033 178 bufferHasChanged = false;
tobyspark 0:76bb084fa033 179 }
tobyspark 0:76bb084fa033 180 }
tobyspark 0:76bb084fa033 181
tobyspark 0:76bb084fa033 182 void SPKDisplay::setup()
tobyspark 0:76bb084fa033 183 {
tobyspark 0:76bb084fa033 184 // TASK: SCREEN OFF, Run pre-flight
tobyspark 0:76bb084fa033 185
tobyspark 0:76bb084fa033 186 // Hard reset the OLED
tobyspark 0:76bb084fa033 187 *res = 0;
tobyspark 0:76bb084fa033 188 wait_ms(1);
tobyspark 0:76bb084fa033 189 *res = 1;
tobyspark 0:76bb084fa033 190
tobyspark 0:76bb084fa033 191 // Select the device by seting chip select low
tobyspark 0:76bb084fa033 192 *cs = 0;
tobyspark 0:76bb084fa033 193
tobyspark 0:76bb084fa033 194 // Set to receive COMMANDS not data
tobyspark 0:76bb084fa033 195 *dc = 0;
tobyspark 0:76bb084fa033 196
tobyspark 0:76bb084fa033 197 spi->write(0xAE); // set display off
tobyspark 0:76bb084fa033 198 spi->write(0xD5); // set display clock divide ratio
tobyspark 0:76bb084fa033 199 spi->write(0xA0);
tobyspark 0:76bb084fa033 200 spi->write(0xA8); // set multiplex ratio
tobyspark 0:76bb084fa033 201 spi->write(0x3F);
tobyspark 0:76bb084fa033 202 spi->write(0xD3); // set display offset
tobyspark 0:76bb084fa033 203 spi->write(0x00);
tobyspark 0:76bb084fa033 204 spi->write(0x40); // set display start line
tobyspark 0:76bb084fa033 205 spi->write(0xAD); // set master configuration
tobyspark 0:76bb084fa033 206 spi->write(0x8E);
tobyspark 0:76bb084fa033 207 spi->write(0xD8); // set area color mode
tobyspark 0:76bb084fa033 208 spi->write(0x05);
tobyspark 0:76bb084fa033 209 spi->write(0xA1); // set segment re-map
tobyspark 0:76bb084fa033 210 spi->write(0xC8); // set com output scan direction
tobyspark 0:76bb084fa033 211 spi->write(0xDA); // set com pins hardware configuration
tobyspark 0:76bb084fa033 212 spi->write(0x12);
tobyspark 0:76bb084fa033 213 spi->write(0x91); // set look-up table
tobyspark 0:76bb084fa033 214 spi->write(0x3F);
tobyspark 0:76bb084fa033 215 spi->write(0x3F);
tobyspark 0:76bb084fa033 216 spi->write(0x3F);
tobyspark 0:76bb084fa033 217 spi->write(0x3F);
tobyspark 0:76bb084fa033 218 spi->write(0x81); // set current control for bank 0
tobyspark 0:76bb084fa033 219 spi->write(0x8F);
tobyspark 0:76bb084fa033 220 spi->write(0xD9); // set pre-charge period
tobyspark 0:76bb084fa033 221 spi->write(0xD2);
tobyspark 0:76bb084fa033 222 spi->write(0xDB); //set vcomh deselect level
tobyspark 0:76bb084fa033 223 spi->write(0x34);
tobyspark 0:76bb084fa033 224 spi->write(0xA4); // set entire display on/off
tobyspark 0:76bb084fa033 225 spi->write(0xA6); // set normal/inverse display
tobyspark 0:76bb084fa033 226
tobyspark 0:76bb084fa033 227 spi->write(0x20); // page mode
tobyspark 0:76bb084fa033 228 spi->write(0x00);
tobyspark 0:76bb084fa033 229
tobyspark 0:76bb084fa033 230 // TASK: Clear screen's content buffer
tobyspark 0:76bb084fa033 231
tobyspark 0:76bb084fa033 232 // Is this neccessary when switching command/data?
tobyspark 0:76bb084fa033 233 *cs = 1;
tobyspark 0:76bb084fa033 234 wait_ms(1);
tobyspark 0:76bb084fa033 235 *cs = 0;
tobyspark 0:76bb084fa033 236
tobyspark 0:76bb084fa033 237 // Set to receive DATA not commands
tobyspark 0:76bb084fa033 238 *dc = 1;
tobyspark 0:76bb084fa033 239
tobyspark 0:76bb084fa033 240 for (int i = 0; i < bufferCount; i++)
tobyspark 0:76bb084fa033 241 {
tobyspark 0:76bb084fa033 242 spi->write(0x00);
tobyspark 0:76bb084fa033 243 }
tobyspark 0:76bb084fa033 244
tobyspark 0:76bb084fa033 245 // TASK: SCREEN ON
tobyspark 0:76bb084fa033 246
tobyspark 0:76bb084fa033 247 // Is this neccessary when switching command/data?
tobyspark 0:76bb084fa033 248 *cs = 1;
tobyspark 0:76bb084fa033 249 wait_ms(1);
tobyspark 0:76bb084fa033 250 *cs = 0;
tobyspark 0:76bb084fa033 251
tobyspark 0:76bb084fa033 252 // Set to receive COMMANDS not data
tobyspark 0:76bb084fa033 253 *dc = 0;
tobyspark 0:76bb084fa033 254
tobyspark 0:76bb084fa033 255 spi->write(0xAF); // set display on
tobyspark 0:76bb084fa033 256
tobyspark 0:76bb084fa033 257 // Deselect the device
tobyspark 0:76bb084fa033 258 *cs = 1;
tobyspark 0:76bb084fa033 259 }