Joseph Kim / Mbed 2 deprecated SSD1306-I2C3

Dependencies:   mbed

Committer:
eggsylah
Date:
Thu Jun 15 15:01:14 2017 +0000
Revision:
0:b0151666c710
Child:
1:9bc80b7d947c
First working i2c version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
eggsylah 0:b0151666c710 1 /*
eggsylah 0:b0151666c710 2 * SSD1306-Library.cpp
eggsylah 0:b0151666c710 3 *
eggsylah 0:b0151666c710 4 * Created on: 19 Apr 2017
eggsylah 0:b0151666c710 5 * Author: ebj
eggsylah 0:b0151666c710 6 *
eggsylah 0:b0151666c710 7 * I2C version
eggsylah 0:b0151666c710 8 * CS GND
eggsylah 0:b0151666c710 9 * DC GND for i2c addr 0x3C, VCC for addr 0x3D
eggsylah 0:b0151666c710 10 * RES Vcc
eggsylah 0:b0151666c710 11 */
eggsylah 0:b0151666c710 12
eggsylah 0:b0151666c710 13 #include "mbed.h"
eggsylah 0:b0151666c710 14
eggsylah 0:b0151666c710 15 #include "SSD1306-Library.h"
eggsylah 0:b0151666c710 16
eggsylah 0:b0151666c710 17 extern Serial pc;
eggsylah 0:b0151666c710 18
eggsylah 0:b0151666c710 19 extern "C" {
eggsylah 0:b0151666c710 20 }
eggsylah 0:b0151666c710 21
eggsylah 0:b0151666c710 22 #define NUM_ELEMENTS(x) ((sizeof x)/(sizeof x[0]))
eggsylah 0:b0151666c710 23
eggsylah 0:b0151666c710 24
eggsylah 0:b0151666c710 25 I2C i2c(I2C_SDA, I2C_SCL);
eggsylah 0:b0151666c710 26 DigitalOut rst(PTD1); //D13); //reset pin on D13
eggsylah 0:b0151666c710 27
eggsylah 0:b0151666c710 28
eggsylah 0:b0151666c710 29 // the memory buffer for the LCD
eggsylah 0:b0151666c710 30 static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8];
eggsylah 0:b0151666c710 31
eggsylah 0:b0151666c710 32 volatile uint8_t dma_pause = 0;
eggsylah 0:b0151666c710 33
eggsylah 0:b0151666c710 34 SSD1306::SSD1306(int16_t w, int16_t h) : Adafruit_GFX(w, h) {
eggsylah 0:b0151666c710 35 }
eggsylah 0:b0151666c710 36
eggsylah 0:b0151666c710 37 #define ssd1306_swap(a, b) { int16_t t = a; a = b; b = t; }
eggsylah 0:b0151666c710 38
eggsylah 0:b0151666c710 39 void SSD1306::hw_setup() {
eggsylah 0:b0151666c710 40 i2c.frequency(400000);
eggsylah 0:b0151666c710 41 }
eggsylah 0:b0151666c710 42
eggsylah 0:b0151666c710 43
eggsylah 0:b0151666c710 44 // the most basic function, set a single pixel
eggsylah 0:b0151666c710 45 void SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
eggsylah 0:b0151666c710 46 if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
eggsylah 0:b0151666c710 47 return;
eggsylah 0:b0151666c710 48
eggsylah 0:b0151666c710 49 // check rotation, move pixel around if necessary
eggsylah 0:b0151666c710 50 switch (rotation) {
eggsylah 0:b0151666c710 51 case 1:
eggsylah 0:b0151666c710 52 ssd1306_swap(x, y);
eggsylah 0:b0151666c710 53 x = WIDTH - x - 1;
eggsylah 0:b0151666c710 54 break;
eggsylah 0:b0151666c710 55 case 2:
eggsylah 0:b0151666c710 56 x = WIDTH - x - 1;
eggsylah 0:b0151666c710 57 y = HEIGHT - y - 1;
eggsylah 0:b0151666c710 58 break;
eggsylah 0:b0151666c710 59 case 3:
eggsylah 0:b0151666c710 60 ssd1306_swap(x, y);
eggsylah 0:b0151666c710 61 y = HEIGHT - y - 1;
eggsylah 0:b0151666c710 62 break;
eggsylah 0:b0151666c710 63 }
eggsylah 0:b0151666c710 64
eggsylah 0:b0151666c710 65 // x is which column
eggsylah 0:b0151666c710 66 uint8_t *p = &buffer[x + (y/8)*SSD1306_LCDWIDTH];
eggsylah 0:b0151666c710 67 uint8_t v = 1 << (y & 7);
eggsylah 0:b0151666c710 68
eggsylah 0:b0151666c710 69 switch (color) {
eggsylah 0:b0151666c710 70 case WHITE:
eggsylah 0:b0151666c710 71 *p |= v;
eggsylah 0:b0151666c710 72 break;
eggsylah 0:b0151666c710 73 case BLACK:
eggsylah 0:b0151666c710 74 *p &= ~v;
eggsylah 0:b0151666c710 75 break;
eggsylah 0:b0151666c710 76 case INVERSE:
eggsylah 0:b0151666c710 77 *p ^= v;
eggsylah 0:b0151666c710 78 break;
eggsylah 0:b0151666c710 79 }
eggsylah 0:b0151666c710 80
eggsylah 0:b0151666c710 81 }
eggsylah 0:b0151666c710 82
eggsylah 0:b0151666c710 83 void SSD1306::_sendData(const uint8_t *blk, uint32_t len, bool isData) {
eggsylah 0:b0151666c710 84 const uint8_t *p = blk;
eggsylah 0:b0151666c710 85
eggsylah 0:b0151666c710 86 //pc.printf("SendData...\r\n");
eggsylah 0:b0151666c710 87 // now send the data
eggsylah 0:b0151666c710 88 uint8_t control = 0x00 | (isData ? 0x40 : 0x00);
eggsylah 0:b0151666c710 89
eggsylah 0:b0151666c710 90
eggsylah 0:b0151666c710 91 if (isData) {
eggsylah 0:b0151666c710 92 i2c.start();
eggsylah 0:b0151666c710 93 //pc.printf("%0.2x ", *p);
eggsylah 0:b0151666c710 94 i2c.write(0x3C<<1);
eggsylah 0:b0151666c710 95
eggsylah 0:b0151666c710 96 //control |= 0x80;
eggsylah 0:b0151666c710 97 i2c.write(control);
eggsylah 0:b0151666c710 98
eggsylah 0:b0151666c710 99 for (int32_t i=0; i<len; i++, p++) {
eggsylah 0:b0151666c710 100 //pc.printf("%0.2x ", *p);
eggsylah 0:b0151666c710 101 int error = i2c.write(*p);
eggsylah 0:b0151666c710 102 //int error = 1;
eggsylah 0:b0151666c710 103 //wait(0.1);
eggsylah 0:b0151666c710 104 if (error != 1)
eggsylah 0:b0151666c710 105 pc.printf("I2C error: %0.2d\r\n", error);
eggsylah 0:b0151666c710 106 }
eggsylah 0:b0151666c710 107 i2c.stop();
eggsylah 0:b0151666c710 108
eggsylah 0:b0151666c710 109 } else {
eggsylah 0:b0151666c710 110 for (int32_t i=0; i<len; i++, p++) {
eggsylah 0:b0151666c710 111 i2c.start();
eggsylah 0:b0151666c710 112 //pc.printf("%0.2x ", *p);
eggsylah 0:b0151666c710 113 i2c.write(0x3C<<1);
eggsylah 0:b0151666c710 114 i2c.write(control);
eggsylah 0:b0151666c710 115 int error = i2c.write(*p);
eggsylah 0:b0151666c710 116 //int error = 1;
eggsylah 0:b0151666c710 117 //wait(0.1);
eggsylah 0:b0151666c710 118 i2c.stop();
eggsylah 0:b0151666c710 119 if (error != 1)
eggsylah 0:b0151666c710 120 pc.printf("I2C error: %0.2d\r\n", error);
eggsylah 0:b0151666c710 121 }
eggsylah 0:b0151666c710 122 }
eggsylah 0:b0151666c710 123 }
eggsylah 0:b0151666c710 124
eggsylah 0:b0151666c710 125 void SSD1306::sendCommands(const uint8_t *blk, uint32_t len) {
eggsylah 0:b0151666c710 126 _sendData(blk, len, false);
eggsylah 0:b0151666c710 127 }
eggsylah 0:b0151666c710 128
eggsylah 0:b0151666c710 129 void SSD1306::sendData(const uint8_t *blk, uint32_t len) {
eggsylah 0:b0151666c710 130 _sendData(blk, len, true);
eggsylah 0:b0151666c710 131 }
eggsylah 0:b0151666c710 132
eggsylah 0:b0151666c710 133 void SSD1306::begin(bool reset) {
eggsylah 0:b0151666c710 134 if (reset) { //pulse the reset pin -- maybe replace with RC network
eggsylah 0:b0151666c710 135 rst = 1;
eggsylah 0:b0151666c710 136 wait_ms(1);
eggsylah 0:b0151666c710 137 rst = 0;
eggsylah 0:b0151666c710 138 wait_ms(10);
eggsylah 0:b0151666c710 139 rst = 1;
eggsylah 0:b0151666c710 140 }
eggsylah 0:b0151666c710 141
eggsylah 0:b0151666c710 142 const uint8_t cmds[] = {
eggsylah 0:b0151666c710 143 SSD1306_DISPLAYOFF,
eggsylah 0:b0151666c710 144 SSD1306_SETDISPLAYCLOCKDIV,
eggsylah 0:b0151666c710 145 0x80, // the suggested ratio 0x80
eggsylah 0:b0151666c710 146 SSD1306_SETMULTIPLEX,
eggsylah 0:b0151666c710 147 SSD1306_LCDHEIGHT - 1,
eggsylah 0:b0151666c710 148 SSD1306_SETDISPLAYOFFSET,
eggsylah 0:b0151666c710 149 0x0, // no offset
eggsylah 0:b0151666c710 150 SSD1306_SETSTARTLINE | 0x0, // line #0
eggsylah 0:b0151666c710 151 SSD1306_CHARGEPUMP,
eggsylah 0:b0151666c710 152 0x14,
eggsylah 0:b0151666c710 153 SSD1306_MEMORYMODE,
eggsylah 0:b0151666c710 154 0x00, // 0x0 act like ks0108
eggsylah 0:b0151666c710 155 SSD1306_SEGREMAP | 0x1,
eggsylah 0:b0151666c710 156 SSD1306_COMSCANDEC,
eggsylah 0:b0151666c710 157 SSD1306_SETCOMPINS,
eggsylah 0:b0151666c710 158 0x12,
eggsylah 0:b0151666c710 159 SSD1306_SETCONTRAST,
eggsylah 0:b0151666c710 160 0xCF,
eggsylah 0:b0151666c710 161 SSD1306_SETPRECHARGE,
eggsylah 0:b0151666c710 162 0xF1,
eggsylah 0:b0151666c710 163 SSD1306_SETVCOMDETECT,
eggsylah 0:b0151666c710 164 0x40,
eggsylah 0:b0151666c710 165 SSD1306_DISPLAYALLON_RESUME,
eggsylah 0:b0151666c710 166 SSD1306_NORMALDISPLAY,
eggsylah 0:b0151666c710 167 SSD1306_DEACTIVATE_SCROLL,
eggsylah 0:b0151666c710 168 SSD1306_DISPLAYON //--turn on oled panel
eggsylah 0:b0151666c710 169 };
eggsylah 0:b0151666c710 170
eggsylah 0:b0151666c710 171 sendCommands(cmds, NUM_ELEMENTS(cmds));
eggsylah 0:b0151666c710 172
eggsylah 0:b0151666c710 173 }
eggsylah 0:b0151666c710 174
eggsylah 0:b0151666c710 175
eggsylah 0:b0151666c710 176 void SSD1306::display(void) {
eggsylah 0:b0151666c710 177 const uint8_t cmds[] = {
eggsylah 0:b0151666c710 178 SSD1306_COLUMNADDR,
eggsylah 0:b0151666c710 179 0, // Column start address (0 = reset)
eggsylah 0:b0151666c710 180 SSD1306_LCDWIDTH - 1, // Column end address (127 = reset)
eggsylah 0:b0151666c710 181 SSD1306_PAGEADDR,
eggsylah 0:b0151666c710 182 0, // Page start address (0 = reset)
eggsylah 0:b0151666c710 183 7 // Page end address
eggsylah 0:b0151666c710 184 };
eggsylah 0:b0151666c710 185
eggsylah 0:b0151666c710 186 sendCommands(cmds, NUM_ELEMENTS(cmds));
eggsylah 0:b0151666c710 187 //now send the screen image
eggsylah 0:b0151666c710 188 sendData(buffer, NUM_ELEMENTS(buffer));
eggsylah 0:b0151666c710 189 }
eggsylah 0:b0151666c710 190
eggsylah 0:b0151666c710 191 void SSD1306::invertDisplay(uint8_t i) {
eggsylah 0:b0151666c710 192 const uint8_t normalCmd[] = { SSD1306_NORMALDISPLAY };
eggsylah 0:b0151666c710 193 const uint8_t invertCmd[] = { SSD1306_INVERTDISPLAY };
eggsylah 0:b0151666c710 194 sendCommands( i ? invertCmd : normalCmd, 1);
eggsylah 0:b0151666c710 195 }
eggsylah 0:b0151666c710 196
eggsylah 0:b0151666c710 197
eggsylah 0:b0151666c710 198 void SSD1306::_scroll(uint8_t mode, uint8_t start, uint8_t stop) {
eggsylah 0:b0151666c710 199 uint8_t cmds[] = { mode, 0, start, 0, stop, 0, 0xFF, SSD1306_ACTIVATE_SCROLL };
eggsylah 0:b0151666c710 200 sendCommands(cmds, NUM_ELEMENTS(cmds));
eggsylah 0:b0151666c710 201 }
eggsylah 0:b0151666c710 202 // startscrollright
eggsylah 0:b0151666c710 203 // Activate a right handed scroll for rows start through stop
eggsylah 0:b0151666c710 204 // Hint, the display is 16 rows tall. To scroll the whole display, run:
eggsylah 0:b0151666c710 205 // display.scrollright(0x00, 0x0F)
eggsylah 0:b0151666c710 206 void SSD1306::startscrollright(uint8_t start, uint8_t stop) {
eggsylah 0:b0151666c710 207 _scroll(SSD1306_RIGHT_HORIZONTAL_SCROLL, start, stop);
eggsylah 0:b0151666c710 208 }
eggsylah 0:b0151666c710 209
eggsylah 0:b0151666c710 210 // startscrollleft
eggsylah 0:b0151666c710 211 // Activate a right handed scroll for rows start through stop
eggsylah 0:b0151666c710 212 // Hint, the display is 16 rows tall. To scroll the whole display, run:
eggsylah 0:b0151666c710 213 // display.scrollright(0x00, 0x0F)
eggsylah 0:b0151666c710 214 void SSD1306::startscrollleft(uint8_t start, uint8_t stop) {
eggsylah 0:b0151666c710 215 _scroll(SSD1306_LEFT_HORIZONTAL_SCROLL, start, stop);
eggsylah 0:b0151666c710 216 }
eggsylah 0:b0151666c710 217
eggsylah 0:b0151666c710 218 // startscrolldiagright
eggsylah 0:b0151666c710 219 // Activate a diagonal scroll for rows start through stop
eggsylah 0:b0151666c710 220 // Hint, the display is 16 rows tall. To scroll the whole display, run:
eggsylah 0:b0151666c710 221 // display.scrollright(0x00, 0x0F)
eggsylah 0:b0151666c710 222 void SSD1306::startscrolldiagright(uint8_t start, uint8_t stop) {
eggsylah 0:b0151666c710 223 uint8_t cmds[] = {
eggsylah 0:b0151666c710 224 SSD1306_SET_VERTICAL_SCROLL_AREA,
eggsylah 0:b0151666c710 225 0X00,
eggsylah 0:b0151666c710 226 SSD1306_LCDHEIGHT,
eggsylah 0:b0151666c710 227 SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL,
eggsylah 0:b0151666c710 228 0X00,
eggsylah 0:b0151666c710 229 start,
eggsylah 0:b0151666c710 230 0X00,
eggsylah 0:b0151666c710 231 stop,
eggsylah 0:b0151666c710 232 0X01,
eggsylah 0:b0151666c710 233 SSD1306_ACTIVATE_SCROLL
eggsylah 0:b0151666c710 234 };
eggsylah 0:b0151666c710 235
eggsylah 0:b0151666c710 236 sendCommands(cmds, NUM_ELEMENTS(cmds));
eggsylah 0:b0151666c710 237 }
eggsylah 0:b0151666c710 238
eggsylah 0:b0151666c710 239 // startscrolldiagleft
eggsylah 0:b0151666c710 240 // Activate a diagonal scroll for rows start through stop
eggsylah 0:b0151666c710 241 // Hint, the display is 16 rows tall. To scroll the whole display, run:
eggsylah 0:b0151666c710 242 // display.scrollright(0x00, 0x0F)
eggsylah 0:b0151666c710 243 void SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop) {
eggsylah 0:b0151666c710 244 uint8_t cmds[] = {
eggsylah 0:b0151666c710 245 SSD1306_SET_VERTICAL_SCROLL_AREA,
eggsylah 0:b0151666c710 246 0X00,
eggsylah 0:b0151666c710 247 SSD1306_LCDHEIGHT,
eggsylah 0:b0151666c710 248 SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL,
eggsylah 0:b0151666c710 249 0X00,
eggsylah 0:b0151666c710 250 start,
eggsylah 0:b0151666c710 251 0X00,
eggsylah 0:b0151666c710 252 stop,
eggsylah 0:b0151666c710 253 0X01,
eggsylah 0:b0151666c710 254 SSD1306_ACTIVATE_SCROLL
eggsylah 0:b0151666c710 255 };
eggsylah 0:b0151666c710 256
eggsylah 0:b0151666c710 257 sendCommands(cmds, NUM_ELEMENTS(cmds));
eggsylah 0:b0151666c710 258 }
eggsylah 0:b0151666c710 259
eggsylah 0:b0151666c710 260
eggsylah 0:b0151666c710 261 void SSD1306::stopscroll(void) {
eggsylah 0:b0151666c710 262 const uint8_t cmds[] = { SSD1306_DEACTIVATE_SCROLL };
eggsylah 0:b0151666c710 263 sendCommands(cmds, NUM_ELEMENTS(cmds));
eggsylah 0:b0151666c710 264 }
eggsylah 0:b0151666c710 265
eggsylah 0:b0151666c710 266 // Dim the display
eggsylah 0:b0151666c710 267 // dim = true: display is dimmed
eggsylah 0:b0151666c710 268 // dim = false: display is normal
eggsylah 0:b0151666c710 269 void SSD1306::dim(bool dim) {
eggsylah 0:b0151666c710 270 // the range of contrast to too small to be really useful
eggsylah 0:b0151666c710 271 // it is useful to dim the display
eggsylah 0:b0151666c710 272 uint8_t cmds[] = {SSD1306_SETCONTRAST, dim ? 0 : 0xCF};
eggsylah 0:b0151666c710 273 sendCommands(cmds, NUM_ELEMENTS(cmds));
eggsylah 0:b0151666c710 274 }
eggsylah 0:b0151666c710 275
eggsylah 0:b0151666c710 276 // clear everything
eggsylah 0:b0151666c710 277 void SSD1306::clearDisplay(void) {
eggsylah 0:b0151666c710 278 memset(buffer, 0, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8));
eggsylah 0:b0151666c710 279 }
eggsylah 0:b0151666c710 280
eggsylah 0:b0151666c710 281 #if 1
eggsylah 0:b0151666c710 282 void SSD1306::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
eggsylah 0:b0151666c710 283 bool bSwap = false;
eggsylah 0:b0151666c710 284 switch (rotation) {
eggsylah 0:b0151666c710 285 case 0:
eggsylah 0:b0151666c710 286 // 0 degree rotation, do nothing
eggsylah 0:b0151666c710 287 break;
eggsylah 0:b0151666c710 288 case 1:
eggsylah 0:b0151666c710 289 // 90 degree rotation, swap x & y for rotation, then invert x
eggsylah 0:b0151666c710 290 bSwap = true;
eggsylah 0:b0151666c710 291 ssd1306_swap(x, y);
eggsylah 0:b0151666c710 292 x = WIDTH - x - 1;
eggsylah 0:b0151666c710 293 break;
eggsylah 0:b0151666c710 294 case 2:
eggsylah 0:b0151666c710 295 // 180 degree rotation, invert x and y - then shift y around for height.
eggsylah 0:b0151666c710 296 x = WIDTH - x - 1;
eggsylah 0:b0151666c710 297 y = HEIGHT - y - 1;
eggsylah 0:b0151666c710 298 x -= (w - 1);
eggsylah 0:b0151666c710 299 break;
eggsylah 0:b0151666c710 300 case 3:
eggsylah 0:b0151666c710 301 // 270 degree rotation, swap x & y for rotation, then invert y and adjust y for w (not to become h)
eggsylah 0:b0151666c710 302 bSwap = true;
eggsylah 0:b0151666c710 303 ssd1306_swap(x, y);
eggsylah 0:b0151666c710 304 y = HEIGHT - y - 1;
eggsylah 0:b0151666c710 305 y -= (w - 1);
eggsylah 0:b0151666c710 306 break;
eggsylah 0:b0151666c710 307 }
eggsylah 0:b0151666c710 308
eggsylah 0:b0151666c710 309 if (bSwap) {
eggsylah 0:b0151666c710 310 drawFastVLineInternal(x, y, w, color);
eggsylah 0:b0151666c710 311 } else {
eggsylah 0:b0151666c710 312 drawFastHLineInternal(x, y, w, color);
eggsylah 0:b0151666c710 313 }
eggsylah 0:b0151666c710 314 }
eggsylah 0:b0151666c710 315 #endif
eggsylah 0:b0151666c710 316
eggsylah 0:b0151666c710 317
eggsylah 0:b0151666c710 318 void SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w,
eggsylah 0:b0151666c710 319 uint16_t color) {
eggsylah 0:b0151666c710 320 // Do bounds/limit checks
eggsylah 0:b0151666c710 321 if (y < 0 || y >= HEIGHT) {
eggsylah 0:b0151666c710 322 return;
eggsylah 0:b0151666c710 323 }
eggsylah 0:b0151666c710 324
eggsylah 0:b0151666c710 325 // make sure we don't try to draw below 0
eggsylah 0:b0151666c710 326 if (x < 0) {
eggsylah 0:b0151666c710 327 w += x;
eggsylah 0:b0151666c710 328 x = 0;
eggsylah 0:b0151666c710 329 }
eggsylah 0:b0151666c710 330
eggsylah 0:b0151666c710 331 // make sure we don't go off the edge of the display
eggsylah 0:b0151666c710 332 if ((x + w) > WIDTH) {
eggsylah 0:b0151666c710 333 w = (WIDTH - x);
eggsylah 0:b0151666c710 334 }
eggsylah 0:b0151666c710 335
eggsylah 0:b0151666c710 336 // if our width is now negative, punt
eggsylah 0:b0151666c710 337 if (w <= 0) {
eggsylah 0:b0151666c710 338 return;
eggsylah 0:b0151666c710 339 }
eggsylah 0:b0151666c710 340
eggsylah 0:b0151666c710 341 // set up the pointer for movement through the buffer
eggsylah 0:b0151666c710 342 register uint8_t *pBuf = buffer;
eggsylah 0:b0151666c710 343 // adjust the buffer pointer for the current row
eggsylah 0:b0151666c710 344 pBuf += ((y / 8) * SSD1306_LCDWIDTH);
eggsylah 0:b0151666c710 345 // and offset x columns in
eggsylah 0:b0151666c710 346 pBuf += x;
eggsylah 0:b0151666c710 347
eggsylah 0:b0151666c710 348 register uint8_t mask = 1 << (y & 7);
eggsylah 0:b0151666c710 349
eggsylah 0:b0151666c710 350 switch (color) {
eggsylah 0:b0151666c710 351 case WHITE:
eggsylah 0:b0151666c710 352 while (w--)
eggsylah 0:b0151666c710 353 *pBuf++ |= mask;
eggsylah 0:b0151666c710 354 break;
eggsylah 0:b0151666c710 355 case BLACK:
eggsylah 0:b0151666c710 356 mask = ~mask;
eggsylah 0:b0151666c710 357 while (w--)
eggsylah 0:b0151666c710 358 *pBuf++ &= mask;
eggsylah 0:b0151666c710 359 break;
eggsylah 0:b0151666c710 360 case INVERSE:
eggsylah 0:b0151666c710 361 while (w--)
eggsylah 0:b0151666c710 362 *pBuf++ ^= mask;
eggsylah 0:b0151666c710 363 break;
eggsylah 0:b0151666c710 364 }
eggsylah 0:b0151666c710 365 }
eggsylah 0:b0151666c710 366
eggsylah 0:b0151666c710 367 void SSD1306::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
eggsylah 0:b0151666c710 368 bool bSwap = false;
eggsylah 0:b0151666c710 369 switch (rotation) {
eggsylah 0:b0151666c710 370 case 0:
eggsylah 0:b0151666c710 371 break;
eggsylah 0:b0151666c710 372 case 1:
eggsylah 0:b0151666c710 373 // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w)
eggsylah 0:b0151666c710 374 bSwap = true;
eggsylah 0:b0151666c710 375 ssd1306_swap(x, y)
eggsylah 0:b0151666c710 376 x = WIDTH - x - 1;
eggsylah 0:b0151666c710 377 x -= (h - 1);
eggsylah 0:b0151666c710 378 break;
eggsylah 0:b0151666c710 379 case 2:
eggsylah 0:b0151666c710 380 // 180 degree rotation, invert x and y - then shift y around for height.
eggsylah 0:b0151666c710 381 x = WIDTH - x - 1;
eggsylah 0:b0151666c710 382 y = HEIGHT - y - 1;
eggsylah 0:b0151666c710 383 y -= (h - 1);
eggsylah 0:b0151666c710 384 break;
eggsylah 0:b0151666c710 385 case 3:
eggsylah 0:b0151666c710 386 // 270 degree rotation, swap x & y for rotation, then invert y
eggsylah 0:b0151666c710 387 bSwap = true;
eggsylah 0:b0151666c710 388 ssd1306_swap(x, y)
eggsylah 0:b0151666c710 389 y = HEIGHT - y - 1;
eggsylah 0:b0151666c710 390 break;
eggsylah 0:b0151666c710 391 }
eggsylah 0:b0151666c710 392
eggsylah 0:b0151666c710 393 if (bSwap) {
eggsylah 0:b0151666c710 394 drawFastHLineInternal(x, y, h, color);
eggsylah 0:b0151666c710 395 } else {
eggsylah 0:b0151666c710 396 drawFastVLineInternal(x, y, h, color);
eggsylah 0:b0151666c710 397 }
eggsylah 0:b0151666c710 398 }
eggsylah 0:b0151666c710 399
eggsylah 0:b0151666c710 400 void SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) {
eggsylah 0:b0151666c710 401
eggsylah 0:b0151666c710 402 // do nothing if we're off the left or right side of the screen
eggsylah 0:b0151666c710 403 if (x < 0 || x >= WIDTH) {
eggsylah 0:b0151666c710 404 return;
eggsylah 0:b0151666c710 405 }
eggsylah 0:b0151666c710 406
eggsylah 0:b0151666c710 407 // make sure we don't try to draw below 0
eggsylah 0:b0151666c710 408 if (__y < 0) {
eggsylah 0:b0151666c710 409 // __y is negative, this will subtract enough from __h to account for __y being 0
eggsylah 0:b0151666c710 410 __h += __y;
eggsylah 0:b0151666c710 411 __y = 0;
eggsylah 0:b0151666c710 412
eggsylah 0:b0151666c710 413 }
eggsylah 0:b0151666c710 414
eggsylah 0:b0151666c710 415 // make sure we don't go past the height of the display
eggsylah 0:b0151666c710 416 if ((__y + __h) > HEIGHT) {
eggsylah 0:b0151666c710 417 __h = (HEIGHT - __y);
eggsylah 0:b0151666c710 418 }
eggsylah 0:b0151666c710 419
eggsylah 0:b0151666c710 420 // if our height is now negative, punt
eggsylah 0:b0151666c710 421 if (__h <= 0) {
eggsylah 0:b0151666c710 422 return;
eggsylah 0:b0151666c710 423 }
eggsylah 0:b0151666c710 424
eggsylah 0:b0151666c710 425 // this display doesn't need ints for coordinates, use local byte registers for faster juggling
eggsylah 0:b0151666c710 426 register uint8_t y = __y;
eggsylah 0:b0151666c710 427 register uint8_t h = __h;
eggsylah 0:b0151666c710 428
eggsylah 0:b0151666c710 429 // set up the pointer for fast movement through the buffer
eggsylah 0:b0151666c710 430 register uint8_t *pBuf = buffer;
eggsylah 0:b0151666c710 431 // adjust the buffer pointer for the current row
eggsylah 0:b0151666c710 432 pBuf += ((y / 8) * SSD1306_LCDWIDTH);
eggsylah 0:b0151666c710 433 // and offset x columns in
eggsylah 0:b0151666c710 434 pBuf += x;
eggsylah 0:b0151666c710 435
eggsylah 0:b0151666c710 436 // do the first partial byte, if necessary - this requires some masking
eggsylah 0:b0151666c710 437 register uint8_t mod = (y & 7);
eggsylah 0:b0151666c710 438 if (mod) {
eggsylah 0:b0151666c710 439 // mask off the high n bits we want to set
eggsylah 0:b0151666c710 440 mod = 8 - mod;
eggsylah 0:b0151666c710 441
eggsylah 0:b0151666c710 442 // note - lookup table results in a nearly 10% performance improvement in fill* functions
eggsylah 0:b0151666c710 443 // register uint8_t mask = ~(0xFF >> (mod));
eggsylah 0:b0151666c710 444 static uint8_t premask[8] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC,
eggsylah 0:b0151666c710 445 0xFE };
eggsylah 0:b0151666c710 446 register uint8_t mask = premask[mod];
eggsylah 0:b0151666c710 447
eggsylah 0:b0151666c710 448 // adjust the mask if we're not going to reach the end of this byte
eggsylah 0:b0151666c710 449 if (h < mod) {
eggsylah 0:b0151666c710 450 mask &= (0XFF >> (mod - h));
eggsylah 0:b0151666c710 451 }
eggsylah 0:b0151666c710 452
eggsylah 0:b0151666c710 453 switch (color) {
eggsylah 0:b0151666c710 454 case WHITE:
eggsylah 0:b0151666c710 455 *pBuf |= mask;
eggsylah 0:b0151666c710 456 break;
eggsylah 0:b0151666c710 457 case BLACK:
eggsylah 0:b0151666c710 458 *pBuf &= ~mask;
eggsylah 0:b0151666c710 459 break;
eggsylah 0:b0151666c710 460 case INVERSE:
eggsylah 0:b0151666c710 461 *pBuf ^= mask;
eggsylah 0:b0151666c710 462 break;
eggsylah 0:b0151666c710 463 }
eggsylah 0:b0151666c710 464
eggsylah 0:b0151666c710 465 // fast exit if we're done here!
eggsylah 0:b0151666c710 466 if (h < mod) {
eggsylah 0:b0151666c710 467 return;
eggsylah 0:b0151666c710 468 }
eggsylah 0:b0151666c710 469
eggsylah 0:b0151666c710 470 h -= mod;
eggsylah 0:b0151666c710 471
eggsylah 0:b0151666c710 472 pBuf += SSD1306_LCDWIDTH;
eggsylah 0:b0151666c710 473 }
eggsylah 0:b0151666c710 474
eggsylah 0:b0151666c710 475 // write solid bytes while we can - effectively doing 8 rows at a time
eggsylah 0:b0151666c710 476 if (h >= 8) {
eggsylah 0:b0151666c710 477 if (color == INVERSE) { // separate copy of the code so we don't impact performance of the black/white write version with an extra comparison per loop
eggsylah 0:b0151666c710 478 do {
eggsylah 0:b0151666c710 479 *pBuf = ~(*pBuf);
eggsylah 0:b0151666c710 480
eggsylah 0:b0151666c710 481 // adjust the buffer forward 8 rows worth of data
eggsylah 0:b0151666c710 482 pBuf += SSD1306_LCDWIDTH;
eggsylah 0:b0151666c710 483
eggsylah 0:b0151666c710 484 // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
eggsylah 0:b0151666c710 485 h -= 8;
eggsylah 0:b0151666c710 486 } while (h >= 8);
eggsylah 0:b0151666c710 487 } else {
eggsylah 0:b0151666c710 488 // store a local value to work with
eggsylah 0:b0151666c710 489 register uint8_t val = (color == WHITE) ? 255 : 0;
eggsylah 0:b0151666c710 490
eggsylah 0:b0151666c710 491 do {
eggsylah 0:b0151666c710 492 // write our value in
eggsylah 0:b0151666c710 493 *pBuf = val;
eggsylah 0:b0151666c710 494
eggsylah 0:b0151666c710 495 // adjust the buffer forward 8 rows worth of data
eggsylah 0:b0151666c710 496 pBuf += SSD1306_LCDWIDTH;
eggsylah 0:b0151666c710 497
eggsylah 0:b0151666c710 498 // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
eggsylah 0:b0151666c710 499 h -= 8;
eggsylah 0:b0151666c710 500 } while (h >= 8);
eggsylah 0:b0151666c710 501 }
eggsylah 0:b0151666c710 502 }
eggsylah 0:b0151666c710 503
eggsylah 0:b0151666c710 504 // now do the final partial byte, if necessary
eggsylah 0:b0151666c710 505 if (h) {
eggsylah 0:b0151666c710 506 mod = h & 7;
eggsylah 0:b0151666c710 507 // this time we want to mask the low bits of the byte, vs the high bits we did above
eggsylah 0:b0151666c710 508 // register uint8_t mask = (1 << mod) - 1;
eggsylah 0:b0151666c710 509 // note - lookup table results in a nearly 10% performance improvement in fill* functions
eggsylah 0:b0151666c710 510 static uint8_t postmask[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F,
eggsylah 0:b0151666c710 511 0x7F };
eggsylah 0:b0151666c710 512 register uint8_t mask = postmask[mod];
eggsylah 0:b0151666c710 513 switch (color) {
eggsylah 0:b0151666c710 514 case WHITE:
eggsylah 0:b0151666c710 515 *pBuf |= mask;
eggsylah 0:b0151666c710 516 break;
eggsylah 0:b0151666c710 517 case BLACK:
eggsylah 0:b0151666c710 518 *pBuf &= ~mask;
eggsylah 0:b0151666c710 519 break;
eggsylah 0:b0151666c710 520 case INVERSE:
eggsylah 0:b0151666c710 521 *pBuf ^= mask;
eggsylah 0:b0151666c710 522 break;
eggsylah 0:b0151666c710 523 }
eggsylah 0:b0151666c710 524 }
eggsylah 0:b0151666c710 525 }