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:
Tue Dec 10 15:48:54 2013 +0000
Revision:
5:0d518115e76c
Parent:
4:a675a19c16f0
fontByteMaker fix

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 4:a675a19c16f0 160 void SPKDisplay::characterToBuffer(char character, int x, int row)
tobyspark 4:a675a19c16f0 161 {
tobyspark 4:a675a19c16f0 162 // Font check
tobyspark 4:a675a19c16f0 163 if (NULL == fontCharacters) return;
tobyspark 4:a675a19c16f0 164 if (NULL == fontStartCharacter || NULL == fontEndCharacter) return;
tobyspark 4:a675a19c16f0 165
tobyspark 4:a675a19c16f0 166 // Range check
tobyspark 4:a675a19c16f0 167 if (row >= 8) row = 7;
tobyspark 4:a675a19c16f0 168 int bStart = row*bufferWidth;
tobyspark 4:a675a19c16f0 169 int bEnd = bStart + pixelWidth;
tobyspark 4:a675a19c16f0 170
tobyspark 4:a675a19c16f0 171 int bPos = bStart + x;
tobyspark 4:a675a19c16f0 172
tobyspark 4:a675a19c16f0 173 // Is it outside the range we have glyphs for?
tobyspark 4:a675a19c16f0 174 if ((character < *fontStartCharacter) || (character > *fontEndCharacter))
tobyspark 4:a675a19c16f0 175 {
tobyspark 4:a675a19c16f0 176 if (debug)
tobyspark 4:a675a19c16f0 177 {
tobyspark 4:a675a19c16f0 178 if (character != ' ') debug->printf("No glyph for character %c", character);
tobyspark 4:a675a19c16f0 179 }
tobyspark 4:a675a19c16f0 180 }
tobyspark 4:a675a19c16f0 181 // If not, typeset it!
tobyspark 4:a675a19c16f0 182 else
tobyspark 4:a675a19c16f0 183 {
tobyspark 4:a675a19c16f0 184 // Shift into our array's indexing
tobyspark 4:a675a19c16f0 185 character -= *fontStartCharacter;
tobyspark 4:a675a19c16f0 186
tobyspark 4:a675a19c16f0 187 // Write each byte's vertical column of 8bits into the buffer.
tobyspark 4:a675a19c16f0 188 for (int j = 0; j < fontCharacters[character][0]; j++)
tobyspark 4:a675a19c16f0 189 {
tobyspark 4:a675a19c16f0 190 if (bPos >= bEnd) break;
tobyspark 4:a675a19c16f0 191 buffer[bPos++] = fontCharacters[character][j+1];
tobyspark 4:a675a19c16f0 192 }
tobyspark 4:a675a19c16f0 193 }
tobyspark 4:a675a19c16f0 194
tobyspark 4:a675a19c16f0 195 bufferHasChanged = true;
tobyspark 4:a675a19c16f0 196 }
tobyspark 4:a675a19c16f0 197
tobyspark 0:76bb084fa033 198 void SPKDisplay::sendBuffer()
tobyspark 0:76bb084fa033 199 {
tobyspark 0:76bb084fa033 200 if (bufferHasChanged)
tobyspark 0:76bb084fa033 201 {
tobyspark 0:76bb084fa033 202 // Select the device by seting chip select low
tobyspark 0:76bb084fa033 203 *cs = 0;
tobyspark 0:76bb084fa033 204
tobyspark 0:76bb084fa033 205 // Set to receive DATA not commands
tobyspark 0:76bb084fa033 206 *dc = 1;
tobyspark 0:76bb084fa033 207
tobyspark 0:76bb084fa033 208 for (int i = 0; i < bufferCount; i++)
tobyspark 0:76bb084fa033 209 {
tobyspark 0:76bb084fa033 210 spi->write(buffer[i]);
tobyspark 0:76bb084fa033 211 }
tobyspark 0:76bb084fa033 212
tobyspark 0:76bb084fa033 213 // Deselect the device
tobyspark 0:76bb084fa033 214 *cs = 1;
tobyspark 0:76bb084fa033 215
tobyspark 0:76bb084fa033 216 bufferHasChanged = false;
tobyspark 0:76bb084fa033 217 }
tobyspark 0:76bb084fa033 218 }
tobyspark 0:76bb084fa033 219
tobyspark 0:76bb084fa033 220 void SPKDisplay::setup()
tobyspark 0:76bb084fa033 221 {
tobyspark 0:76bb084fa033 222 // TASK: SCREEN OFF, Run pre-flight
tobyspark 0:76bb084fa033 223
tobyspark 0:76bb084fa033 224 // Hard reset the OLED
tobyspark 0:76bb084fa033 225 *res = 0;
tobyspark 0:76bb084fa033 226 wait_ms(1);
tobyspark 0:76bb084fa033 227 *res = 1;
tobyspark 0:76bb084fa033 228
tobyspark 0:76bb084fa033 229 // Select the device by seting chip select low
tobyspark 0:76bb084fa033 230 *cs = 0;
tobyspark 0:76bb084fa033 231
tobyspark 0:76bb084fa033 232 // Set to receive COMMANDS not data
tobyspark 0:76bb084fa033 233 *dc = 0;
tobyspark 0:76bb084fa033 234
tobyspark 0:76bb084fa033 235 spi->write(0xAE); // set display off
tobyspark 0:76bb084fa033 236 spi->write(0xD5); // set display clock divide ratio
tobyspark 0:76bb084fa033 237 spi->write(0xA0);
tobyspark 0:76bb084fa033 238 spi->write(0xA8); // set multiplex ratio
tobyspark 0:76bb084fa033 239 spi->write(0x3F);
tobyspark 0:76bb084fa033 240 spi->write(0xD3); // set display offset
tobyspark 0:76bb084fa033 241 spi->write(0x00);
tobyspark 0:76bb084fa033 242 spi->write(0x40); // set display start line
tobyspark 0:76bb084fa033 243 spi->write(0xAD); // set master configuration
tobyspark 0:76bb084fa033 244 spi->write(0x8E);
tobyspark 0:76bb084fa033 245 spi->write(0xD8); // set area color mode
tobyspark 0:76bb084fa033 246 spi->write(0x05);
tobyspark 0:76bb084fa033 247 spi->write(0xA1); // set segment re-map
tobyspark 0:76bb084fa033 248 spi->write(0xC8); // set com output scan direction
tobyspark 0:76bb084fa033 249 spi->write(0xDA); // set com pins hardware configuration
tobyspark 0:76bb084fa033 250 spi->write(0x12);
tobyspark 0:76bb084fa033 251 spi->write(0x91); // set look-up table
tobyspark 0:76bb084fa033 252 spi->write(0x3F);
tobyspark 0:76bb084fa033 253 spi->write(0x3F);
tobyspark 0:76bb084fa033 254 spi->write(0x3F);
tobyspark 0:76bb084fa033 255 spi->write(0x3F);
tobyspark 0:76bb084fa033 256 spi->write(0x81); // set current control for bank 0
tobyspark 0:76bb084fa033 257 spi->write(0x8F);
tobyspark 0:76bb084fa033 258 spi->write(0xD9); // set pre-charge period
tobyspark 0:76bb084fa033 259 spi->write(0xD2);
tobyspark 0:76bb084fa033 260 spi->write(0xDB); //set vcomh deselect level
tobyspark 0:76bb084fa033 261 spi->write(0x34);
tobyspark 0:76bb084fa033 262 spi->write(0xA4); // set entire display on/off
tobyspark 0:76bb084fa033 263 spi->write(0xA6); // set normal/inverse display
tobyspark 0:76bb084fa033 264
tobyspark 0:76bb084fa033 265 spi->write(0x20); // page mode
tobyspark 0:76bb084fa033 266 spi->write(0x00);
tobyspark 0:76bb084fa033 267
tobyspark 0:76bb084fa033 268 // TASK: Clear screen's content buffer
tobyspark 0:76bb084fa033 269
tobyspark 0:76bb084fa033 270 // Is this neccessary when switching command/data?
tobyspark 0:76bb084fa033 271 *cs = 1;
tobyspark 0:76bb084fa033 272 wait_ms(1);
tobyspark 0:76bb084fa033 273 *cs = 0;
tobyspark 0:76bb084fa033 274
tobyspark 0:76bb084fa033 275 // Set to receive DATA not commands
tobyspark 0:76bb084fa033 276 *dc = 1;
tobyspark 0:76bb084fa033 277
tobyspark 0:76bb084fa033 278 for (int i = 0; i < bufferCount; i++)
tobyspark 0:76bb084fa033 279 {
tobyspark 0:76bb084fa033 280 spi->write(0x00);
tobyspark 0:76bb084fa033 281 }
tobyspark 0:76bb084fa033 282
tobyspark 0:76bb084fa033 283 // TASK: SCREEN ON
tobyspark 0:76bb084fa033 284
tobyspark 0:76bb084fa033 285 // Is this neccessary when switching command/data?
tobyspark 0:76bb084fa033 286 *cs = 1;
tobyspark 0:76bb084fa033 287 wait_ms(1);
tobyspark 0:76bb084fa033 288 *cs = 0;
tobyspark 0:76bb084fa033 289
tobyspark 0:76bb084fa033 290 // Set to receive COMMANDS not data
tobyspark 0:76bb084fa033 291 *dc = 0;
tobyspark 0:76bb084fa033 292
tobyspark 0:76bb084fa033 293 spi->write(0xAF); // set display on
tobyspark 0:76bb084fa033 294
tobyspark 0:76bb084fa033 295 // Deselect the device
tobyspark 0:76bb084fa033 296 *cs = 1;
tobyspark 0:76bb084fa033 297 }