dd

Dependencies:   Final HCSR04 TB6612FNG

Committer:
eunmango
Date:
Sun Jun 16 04:44:35 2019 +0000
Revision:
97:b483e656bd14
t

Who changed what in which revision?

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