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:
Sun Apr 15 19:39:17 2012 +0000
Revision:
1:dd3faa2ab1dd
Parent:
0:76bb084fa033
Child:
3:ade83210ecf6
Image and font are fully external to class, ie. it will compile for others!

Who changed what in which revision?

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