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