This library provides an OLED (SSD1332, 96x64xRGB) interface that best utilizes SSD1332's graphic accelerator (especially for drawing lines and rectangles). Though it still has some limitations --- it does not support 'clipping', odd numbers for circle/ellipse diameter, and so on, it runs quite fast. Enjoy the speed.
Fork of OLEDaccel by
Revision 0:76a5ae915f62, committed 2012-08-17
- Comitter:
- xkozima
- Date:
- Fri Aug 17 15:30:29 2012 +0000
- Commit message:
- This library provides an OLED (SSD1332, 96x64xRGB) interface that best utilizes SSD1332's graphic accelerator (especially for drawing lines and rectangles). Though it still has some limitations --- it does not support 'clipping', odd numbers for circle...
Changed in this revision
diff -r 000000000000 -r 76a5ae915f62 OLEDaccel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OLEDaccel.cpp Fri Aug 17 15:30:29 2012 +0000 @@ -0,0 +1,400 @@ +// +// OLEDaccel: 96x64 OLED driver +// (version 0.2, August 17, 2012) +// xkozima@myu.ac.jp + +#include "OLEDaccel.h" +#include "font6x8.h" + +OLED::OLED (PinName rstPin, PinName csPin, PinName dcPin, PinName mosiPin, PinName sckPin) : + rst(rstPin), cs(csPin), dc(dcPin), spi(mosiPin, NC, sckPin) +{ + // setup spi (8bit master @48MHz) + spi.format(8,3); + spi.frequency(48000000); + wait_ms(20); + + // reset OLED + rst = 0; + wait_ms(20); + rst = 1; + wait_ms(20); + + // init command + unsigned char cmd1[] = {0xa0, 0x70}; + cmdOut(cmd1, 2); + unsigned char cmd2[] = {0xaf}; + cmdOut(cmd2, 1); + unsigned char cmd3[] = {0x26, 0x01}; + cmdOut(cmd3, 2); + + // clear flags + reversal = false; + filling = true; + + // clear and display on + rect(0, 0, 96, 64, 0, 1); + wait(0.1); + cmdOutOne(0xaf); // display on +} + +void OLED::cmdOutOne(unsigned char cmdOne) +{ + dc = 0; + cs = 0; + spi.write(cmdOne); + cs = 1; +} + +void OLED::cmdOut(unsigned char *cmd, int length) +{ + dc = 0; + cs = 0; + for (int i = 0; i < length; i++) { + spi.write(*cmd++); + } + cs = 1; +} + +void OLED::dataOut(unsigned short *data, int length) +{ + dc = 1; + cs = 0; + for (int i = 0; i < length; i++) { + unsigned short d16 = *data++; + spi.write((unsigned char) ((d16 & 0xff00) >> 8)); + spi.write((unsigned char) (d16 & 0x00ff)); + } + cs = 1; +} + +unsigned short OLED::color (int r, int g, int b) +{ + return ((b & 0xf8) << 8) | ((g & 0xfc) << 3) | ((r & 0xf8) >> 3); +} + +void OLED::clear (unsigned short color) +{ + rect(0, 0, 96, 64, color, 1); +} + +void OLED::point(int x, int y, unsigned short color) +{ + // draw a point (a small rectangle/filled) + unsigned char c1 = (color & 0xf800) >> 10, + c2 = (color & 0x07e0) >> 5, + c3 = (color & 0x001f) << 1; + unsigned char cmd[] = {0x22, x, y, x, y, + c1, c2, c3, c1, c2, c3 }; + cmdOut(cmd, 11); +} + +void OLED::rect (int x, int y, int w, int h, + unsigned short color, int fill ) +{ + unsigned char c1 = (color & 0xf800) >> 10, + c2 = (color & 0x07e0) >> 5, + c3 = (color & 0x001f) << 1; + // + // fill or no fill + if (fill) { + if (! filling) { + unsigned char cmdF[] = {0x26, 1}; + cmdOut(cmdF, 2); + filling = true; + } + } + else { + if (filling) { + unsigned char cmdN[] = {0x26, 0}; + cmdOut(cmdN, 2); + filling = false; + } + } + // un-reverse + if (reversal) { + unsigned char cmdN[] = {0xa0, 0x70}; + cmdOut(cmdN, 2); + reversal = false; + } + // draw/fill the rectangle + unsigned char cmd[] = {0x22, x, y, x + w - 1, y + h - 1, + c1, c2, c3, c1, c2, c3 }; + cmdOut(cmd, 11); + // wait + wait_us(w * h / 10); +} + +void OLED::line(int x1, int y1, int x2, int y2, unsigned short color) +{ + unsigned char c1 = (color & 0xf800) >> 10, + c2 = (color & 0x07e0) >> 5, + c3 = (color & 0x001f) << 1; + if (x1 < x2) { + if (y1 < y2) { + // normal + unsigned char cmd[] = {0x21, x1, y1, x2, y2, c1, c2, c3}; + if (reversal) { + unsigned char cmdN[] = {0xa0, 0x70}; + cmdOut(cmdN, 2); + reversal = false; + } + cmdOut(cmd, 8); + } + else if (y1 > y2) { + // reversal + if (! reversal) { + unsigned char cmdR[] = {0xa0, 0x72}; + cmdOut(cmdR, 2); + reversal = true; + } + unsigned char cmd[] = {0x21, 95 - x2, y2, 95 - x1, y1, c1, c2, c3}; + cmdOut(cmd, 8); + } + else { // y1 == y2 + // normal + unsigned char cmd[] = {0x21, x1, y1, x2, y2, c1, c2, c3}; + if (reversal) { + unsigned char cmdN[] = {0xa0, 0x70}; + cmdOut(cmdN, 2); + reversal = false; + } + cmdOut(cmd, 8); + } + } + else if (x1 > x2) { + if (y1 < y2) { + // reversal + if (! reversal) { + unsigned char cmdR[] = {0xa0, 0x72}; + cmdOut(cmdR, 2); + reversal = true; + } + unsigned char cmd[] = {0x21, 95 - x2, y2, 95 - x1, y1, c1, c2, c3}; + cmdOut(cmd, 8); + } + else if (y1 > y2) { + // normal + unsigned char cmd[] = {0x21, x1, y1, x2, y2, c1, c2, c3}; + if (reversal) { + unsigned char cmdN[] = {0xa0, 0x70}; + cmdOut(cmdN, 2); + reversal = false; + } + cmdOut(cmd, 8); + } + else { // y1 == y2 + // reversal + unsigned char cmd[] = {0xa0, 0x72, + 0x21, 95 - x2, y2, 95 - x1, y1, c1, c2, c3, + 0xa0, 0x70 }; + cmdOut(cmd, 12); + } + } + else { // x1 == x2 + if (y1 < y2) { + // normal + unsigned char cmd[] = {0x21, x1, y1, x2, y2, c1, c2, c3}; + if (reversal) { + unsigned char cmdN[] = {0xa0, 0x70}; + cmdOut(cmdN, 2); + reversal = false; + } + cmdOut(cmd, 8); + } + else if (y1 > y2) { + // normal (force downward) + unsigned char cmd[] = {0x21, x2, y2, x1, y1, c1, c2, c3}; + cmdOut(cmd, 8); + } + else { // y1 == y2 + // normal (point) + unsigned char cmd[] = {0x21, x1, y1, x2, y2, c1, c2, c3}; + if (reversal) { + unsigned char cmdN[] = {0xa0, 0x70}; + cmdOut(cmdN, 2); + reversal = false; + } + cmdOut(cmd, 8); + } + } + // wait + wait_us(1); +} + +void OLED::circle(int x, int y, int r, unsigned short color, int fill) +{ + // exception + if (r < 1) { + line(x, y, x, y, color); + return; + } else if (r == 1) { + rect(x - 1, y - 1, 3, 3, color, fill); + return; + } + // ok, go + int xx = 0, + yy = r, + err = 2 - 2 * r; + // iteration + do { + // draw it! + if (fill) { + line(x + xx, y + yy, x + xx, y, color); + line(x - xx, y + yy, x, y + yy, color); + line(x - xx, y - yy, x - xx, y, color); + line(x + xx, y - yy, x, y - yy, color); + } + else { + point(x + xx, y + yy, color); + point(x - xx, y + yy, color); + point(x - xx, y - yy, color); + point(x + xx, y - yy, color); + } + // walk + if (err > -yy) { + yy--; + err += 1 - 2 * yy; + } + if (err <= xx) { + xx++; + err += 1 + 2 * xx; + } + } while (yy >= 0); +} + +void OLED::ellipse(int x, int y, int rx, int ry, unsigned short color, int fill) +{ + // exception + if (rx < 1) { + line(x, y - ry, x, y + ry, color); + return; + } + else if (ry < 1) { + line(x - rx, y, x + rx, y, color); + return; + } + // ok, go + int xx = -rx, yy = 0; + int e2 = ry, + dx = (2 * xx + 1) * e2 * e2, + dy = xx * xx, + err = dx + dy; + do { + if (fill) { + line(x + xx, y + yy, x + xx, y, color); + line(x - xx, y + yy, x, y + yy, color); + line(x - xx, y - yy, x - xx, y, color); + line(x + xx, y - yy, x, y - yy, color); + } + else { + point(x + xx, y + yy, color); + point(x - xx, y + yy, color); + point(x - xx, y - yy, color); + point(x + xx, y - yy, color); + } + e2 = 2 * err; + if (e2 >= dx) { + xx++; + dx += 2 * ry * ry; + err += dx; + } + if (e2 <= dy) { + yy++; + dy += 2 * rx * rx; + err += dy; + } + } while (xx <= 0); + if (fill) { + while (yy++ < ry) { + line(x, y + yy, x, y, color); + line(x, y - yy, x, y, color); + } + } + else { + while (yy++ < ry) { + point(x, y + yy, color); + point(x, y - yy, color); + } + } +} + +void OLED::image(int x, int y, int w, int h, unsigned short *image16) +{ + // un-reverse + if (reversal) { + unsigned char cmdN[] = {0xa0, 0x70}; + cmdOut(cmdN, 2); + reversal = false; + } + // setup the region to fill + unsigned char cmd[]={0x15, x, x+w-1, 0x75, y, y+h-1}; + cmdOut(cmd, 6); + // fill up the region with the image data + dataOut(image16, w * h); + // wait + wait_us(100); +} + +void OLED::image(int x, int y, int w, int h, const unsigned short *image16) +{ + image(x, y, w, h, (unsigned short *) image16); +} + +void OLED::image(int x, int y, int w, int h, unsigned char *image8x3) +{ + // un-reverse + if (reversal) { + unsigned char cmdN[] = {0xa0, 0x70}; + cmdOut(cmdN, 2); + reversal = false; + } + // setup the region to fill + unsigned char cmd[]={0x15, x, x+w-1, 0x75, y, y+h-1}; + cmdOut(cmd, 6); + // fill up the region with the image data + int size = w * h; + for (int k = 0; k < size; k++) { + unsigned char r, g, b; + b = *image8x3++; + g = *image8x3++; + r = *image8x3++; + unsigned short data16 = color(r, g, b); + dataOut(&data16, 1); + } + // wait + wait_us(100); +} + +void OLED::image(int x, int y, int w, int h, const unsigned char *image8x3) +{ + image(x, y, w, h, (unsigned char *) image8x3); +} + +void OLED::text(int x, int y, char *string, unsigned short color) +{ + int len = strlen(string); + for (int i = 0; i < len; i++) { + int xx = x + i * 6; + unsigned char code = string[i]; + if (code < 0x20 || code >= 0x80) continue; + unsigned char *font = font6x8 + ((code - 0x20) * 6); + for (int fx = 0; fx < 6; fx++) { + if (xx + fx > 95) break; + unsigned char line = *(font + fx); + for (int fy = 0, bit = 0x01; fy < 8; fy++, bit <<= 1) { + if (line & bit) point(xx + fx, y + fy, color); + } + } + } +} + +void OLED::text(int x, int y, char *string, unsigned short colorF, unsigned short colorB) +{ + // clear the background + int w = strlen(string) * 6; + if (x + w > 95) w = 95 - x; + rect(x, y, w, 8, colorB, 1); + // overwrite the text + text(x, y, string, colorF); +} \ No newline at end of file
diff -r 000000000000 -r 76a5ae915f62 OLEDaccel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OLEDaccel.h Fri Aug 17 15:30:29 2012 +0000 @@ -0,0 +1,33 @@ +// +// OLEDaccel: 96x64 OLED driver +// (version 0.2, August 15, 2012) +// xkozima@myu.ac.jp + +#pragma once +#include "mbed.h" + +class OLED { +public: + OLED(PinName rstPin, PinName csPin, PinName dcPin, PinName mosiPin, PinName sckPin); + void clear(unsigned short color); + void point(int x, int y, unsigned short color); + void line(int x1, int y1, int x2, int y2, unsigned short color); + void rect(int x, int y, int w, int h, unsigned short color, int fill); + void circle(int x, int y, int r, unsigned short color, int fill); + void ellipse(int x, int y, int rx, int ry, unsigned short color, int fill); + void image(int x, int y, int w, int h, unsigned short *image16); + void image(int x, int y, int w, int h, const unsigned short *image16); + void image(int x, int y, int w, int h, unsigned char *image8x3); + void image(int x, int y, int w, int h, const unsigned char *image8x3); + void text(int x, int y, char *string, unsigned short color); + void text(int x, int y, char *string, unsigned short colorF, unsigned short colorB); + unsigned short color(int r, int g, int b); +private: + void cmdOutOne(unsigned char cmdOne); + void cmdOut(unsigned char *cmd, int length); + void dataOut(unsigned short *data, int length); + DigitalOut rst, cs, dc; + SPI spi; + bool reversal; + bool filling; +}; \ No newline at end of file
diff -r 000000000000 -r 76a5ae915f62 font6x8.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/font6x8.h Fri Aug 17 15:30:29 2012 +0000 @@ -0,0 +1,194 @@ +unsigned char font6x8[] = { + // 0x20 (SPC) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // 0x21 (!) + 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, + // 0x22 (") + 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, + // 0x23 (#) + 0x14, 0x7f, 0x14, 0x7f, 0x14, 0x00, + // 0x24 ($) + 0x24, 0x2a, 0x7f, 0x2a, 0x12, 0x00, + // 0x25 (%) + 0x46, 0x26, 0x18, 0x64, 0x62, 0x00, + // 0x26 (&) + 0x30, 0x4b, 0x4d, 0x33, 0x48, 0x00, + // 0x27 (') + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + // 0x28 (() + 0x00, 0x1c, 0x22, 0x41, 0x00, 0x00, + // 0x29 ()) + 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, + // 0x2a (*) + 0x2a, 0x1c, 0x7f, 0x1c, 0x2a, 0x00, + // 0x2b (+) + 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, + // 0x2c (,) + 0x00, 0x00, 0x40, 0x20, 0x00, 0x00, + // 0x2d (-) + 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, + // 0x2e (.) + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + // 0x2f (/) + 0x40, 0x30, 0x08, 0x06, 0x01, 0x00, + // 0x30 (0) + 0x3e, 0x61, 0x5d, 0x43, 0x3e, 0x00, + // 0x31 (1) + 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, + // 0x32 (2) + 0x62, 0x51, 0x51, 0x49, 0x46, 0x00, + // 0x33 (3) + 0x22, 0x41, 0x49, 0x49, 0x36, 0x00, + // 0x34 (4) + 0x30, 0x2e, 0x21, 0x7f, 0x20, 0x00, + // 0x35 (5) + 0x4f, 0x49, 0x49, 0x49, 0x31, 0x00, + // 0x36 (6) + 0x3e, 0x49, 0x49, 0x49, 0x32, 0x00, + // 0x37 (7) + 0x01, 0x61, 0x19, 0x05, 0x03, 0x00, + // 0x38 (8) + 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, + // 0x39 (9) + 0x26, 0x49, 0x49, 0x49, 0x3e, 0x00, + // 0x3a (:) + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + // 0x3b (;) + 0x00, 0x00, 0x40, 0x24, 0x00, 0x00, + // 0x3c (<) + 0x00, 0x08, 0x14, 0x22, 0x00, 0x00, + // 0x3d (=) + 0x00, 0x14, 0x14, 0x14, 0x14, 0x00, + // 0x3e (>) + 0x00, 0x22, 0x14, 0x08, 0x00, 0x00, + // 0x3f (?) + 0x06, 0x01, 0x59, 0x09, 0x06, 0x00, + // 0x40 (@) + 0x3e, 0x41, 0x5d, 0x55, 0x5e, 0x00, + // 0x41 (A) + 0x7e, 0x11, 0x11, 0x11, 0x7e, 0x00, + // 0x42 (B) + 0x7f, 0x49, 0x49, 0x49, 0x36, 0x00, + // 0x43 (C) + 0x3e, 0x41, 0x41, 0x41, 0x22, 0x00, + // 0x44 (D) + 0x7f, 0x41, 0x41, 0x22, 0x1c, 0x00, + // 0x45 (E) + 0x7f, 0x49, 0x49, 0x49, 0x41, 0x00, + // 0x46 (F) + 0x7f, 0x09, 0x09, 0x09, 0x01, 0x00, + // 0x47 (G) + 0x3e, 0x41, 0x51, 0x51, 0x72, 0x00, + // 0x48 (H) + 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x00, + // 0x49 (I) + 0x00, 0x41, 0x7f, 0x41, 0x00, 0x00, + // 0x4a (J) + 0x30, 0x40, 0x41, 0x41, 0x3f, 0x00, + // 0x4b (K) + 0x7f, 0x08, 0x14, 0x22, 0x41, 0x00, + // 0x4c (L) + 0x7f, 0x40, 0x40, 0x40, 0x40, 0x00, + // 0x4d (M) + 0x7f, 0x06, 0x18, 0x06, 0x7f, 0x00, + // 0x4e (N) + 0x7f, 0x02, 0x1c, 0x20, 0x7f, 0x00, + // 0x4f (O) + 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x00, + // 0x50 (P) + 0x7f, 0x09, 0x09, 0x09, 0x06, 0x00, + // 0x51 (Q) + 0x3e, 0x41, 0x51, 0x61, 0x7e, 0x00, + // 0x52 (R) + 0x7f, 0x09, 0x09, 0x19, 0x66, 0x00, + // 0x53 (S) + 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, + // 0x54 (T) + 0x01, 0x01, 0x7f, 0x01, 0x01, 0x00, + // 0x55 (U) + 0x3f, 0x40, 0x40, 0x40, 0x3f, 0x00, + // 0x56 (V) + 0x07, 0x18, 0x60, 0x18, 0x07, 0x00, + // 0x57 (W) + 0x7f, 0x30, 0x0c, 0x30, 0x7f, 0x00, + // 0x58 (X) + 0x41, 0x36, 0x08, 0x36, 0x41, 0x00, + // 0x59 (Y) + 0x03, 0x0c, 0x70, 0x0c, 0x03, 0x00, + // 0x5a (Z) + 0x61, 0x51, 0x49, 0x45, 0x43, 0x00, + // 0x5b ([) + 0x00, 0x00, 0x7f, 0x41, 0x00, 0x00, + // 0x5c (\) + 0x01, 0x06, 0x08, 0x30, 0x40, 0x00, + // 0x5d (]) + 0x00, 0x00, 0x41, 0x7f, 0x00, 0x00, + // 0x5e (^) + 0x00, 0x02, 0x01, 0x02, 0x00, 0x00, + // 0x5f (_) + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + // 0x60 (`) + 0x00, 0x01, 0x02, 0x04, 0x00, 0x00, + // 0x61 (a) + 0x24, 0x54, 0x54, 0x54, 0x38, 0x40, + // 0x62 (b) + 0x7f, 0x44, 0x44, 0x44, 0x38, 0x00, + // 0x63 (c) + 0x38, 0x44, 0x44, 0x44, 0x44, 0x00, + // 0x64 (d) + 0x38, 0x44, 0x44, 0x44, 0x7f, 0x00, + // 0x65 (e) + 0x38, 0x54, 0x54, 0x54, 0x5c, 0x00, + // 0x66 (f) + 0x00, 0x08, 0x7f, 0x09, 0x00, 0x00, + // 0x67 (g) + 0x58, 0x54, 0x54, 0x54, 0x3c, 0x00, + // 0x68 (h) + 0x7f, 0x04, 0x04, 0x04, 0x78, 0x00, + // 0x69 (i) + 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, + // 0x6a (j) + 0x20, 0x40, 0x40, 0x40, 0x3a, 0x00, + // 0x6b (k) + 0x7f, 0x10, 0x10, 0x28, 0x48, 0x00, + // 0x6c (l) + 0x00, 0x00, 0x41, 0x7f, 0x40, 0x00, + // 0x6d (m) + 0x7c, 0x04, 0x78, 0x04, 0x78, 0x00, + // 0x6e (n) + 0x7c, 0x04, 0x04, 0x04, 0x78, 0x00, + // 0x6f (o) + 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, + // 0x70 (p) + 0x7c, 0x24, 0x24, 0x24, 0x18, 0x00, + // 0x71 (q) + 0x18, 0x24, 0x24, 0x24, 0x7c, 0x00, + // 0x72 (r) + 0x7c, 0x08, 0x04, 0x04, 0x04, 0x00, + // 0x73 (s) + 0x58, 0x54, 0x54, 0x54, 0x34, 0x00, + // 0x74 (t) + 0x00, 0x04, 0x7e, 0x44, 0x00, 0x00, + // 0x75 (u) + 0x3c, 0x40, 0x40, 0x40, 0x7c, 0x00, + // 0x76 (v) + 0x0c, 0x30, 0x40, 0x30, 0x0c, 0x00, + // 0x77 (w) + 0x7c, 0x20, 0x18, 0x20, 0x7c, 0x00, + // 0x78 (x) + 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, + // 0x79 (y) + 0x44, 0x28, 0x10, 0x08, 0x04, 0x00, + // 0x7a (z) + 0x44, 0x64, 0x54, 0x4c, 0x44, 0x00, + // 0x7b ({) + 0x00, 0x08, 0x3e, 0x41, 0x00, 0x00, + // 0x7c (|) + 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, + // 0x7d (}) + 0x00, 0x00, 0x41, 0x3e, 0x08, 0x00, + // 0x7e (~) + 0x02, 0x01, 0x02, 0x01, 0x01, 0x00, + // 0x7f (DEL) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +};