Final

Dependencies:   IRremote HCSR04 TB6612FNG

Committer:
eunmango
Date:
Sun Jun 16 04:51:51 2019 +0000
Revision:
97:59d348745d96
s

Who changed what in which revision?

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