OLED display demonstration. 16-pin multi-mode 0.96in module (SPI, I2C, DIO parallel) configured in 4-wire SPI. STM32L152RE Nucleo platform.

Dependencies:   SSD1306 mbed

Files at this revision

API Documentation at this revision

Comitter:
charlesfhda
Date:
Thu Jun 26 22:43:10 2014 +0000
Commit message:
Moved program files to new account.

Changed in this revision

SSD1306.lib Show annotated file Show diff for this revision Revisions of this file
SSD1306/bold_font.h Show annotated file Show diff for this revision Revisions of this file
SSD1306/ssd1306.cpp Show annotated file Show diff for this revision Revisions of this file
SSD1306/ssd1306.h Show annotated file Show diff for this revision Revisions of this file
SSD1306/standard_font.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SSD1306.lib	Thu Jun 26 22:43:10 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/masato/code/SSD1306/#ec5add86f335
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SSD1306/bold_font.h	Thu Jun 26 22:43:10 2014 +0000
@@ -0,0 +1,109 @@
+/** Thick 8x8 font, good for headings etc. */
+static unsigned char bold_font[] = {
+
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x20] ' '
+    0x0,  0x0,  0x0,  0xDF,  0xDF,  0x0,  0x0,  0x0,    // [0x21] '!'
+    0x0,  0x3,  0x7,  0x0,  0x3,  0x7,  0x0,  0x0,    // [0x22] '"'
+    0x0,  0x14,  0x3E,  0x14,  0x3E,  0x14,  0x0,  0x0,    // [0x23] '#'
+    0x0,  0x24,  0x2A,  0x7F,  0x2A,  0x12,  0x0,  0x0,    // [0x24] '$'
+    0x43,  0x23,  0x10,  0x8,  0x4,  0x62,  0x61,  0x0,    // [0x25] '%'
+    0x38,  0x7C,  0x44,  0x7F,  0x3F,  0x4,  0x4,  0x0,    // [0x26] '&'
+    0x0,  0x0,  0x0,  0x7,  0x7,  0x0,  0x0,  0x0,    // [0x27] '''
+    0x0,  0x0,  0x7E,  0xFF,  0x81,  0x0,  0x0,  0x0,    // [0x28] '('
+    0x0,  0x0,  0x81,  0xFF,  0x7E,  0x0,  0x0,  0x0,    // [0x29] ')'
+    0x8,  0x2A,  0x1C,  0x7F,  0x1C,  0x2A,  0x8,  0x0,    // [0x2A] '*'
+    0x0,  0x8,  0x8,  0x3E,  0x3E,  0x8,  0x8,  0x0,    // [0x2B] '+'
+    0x0,  0x0,  0x80,  0xE0,  0x60,  0x0,  0x0,  0x0,    // [0x2C] ','
+    0x0,  0x8,  0x8,  0x8,  0x8,  0x8,  0x8,  0x0,    // [0x2D] '-'
+    0x0,  0x0,  0x0,  0xC0,  0xC0,  0x0,  0x0,  0x0,    // [0x2E] '.'
+    0x0,  0xC0,  0xF0,  0x3C,  0xF,  0x3,  0x0,  0x0,    // [0x2F] '/'
+    0x3E,  0x7F,  0x51,  0x49,  0x45,  0x7F,  0x3E,  0x0,    // [0x30] '0'
+    0x0,  0x40,  0x42,  0x7F,  0x7F,  0x40,  0x40,  0x0,    // [0x31] '1'
+    0x72,  0x7B,  0x49,  0x49,  0x49,  0x4F,  0x46,  0x0,    // [0x32] '2'
+    0x22,  0x63,  0x41,  0x49,  0x49,  0x7F,  0x36,  0x0,    // [0x33] '3'
+    0x7,  0xF,  0x8,  0x8,  0x8,  0x7E,  0x7E,  0x0,    // [0x34] '4'
+    0x27,  0x6F,  0x49,  0x49,  0x49,  0x79,  0x31,  0x0,    // [0x35] '5'
+    0x3E,  0x7F,  0x49,  0x49,  0x49,  0x79,  0x30,  0x0,    // [0x36] '6'
+    0x1,  0x1,  0x1,  0x1,  0x1,  0x7F,  0x7E,  0x0,    // [0x37] '7'
+    0x36,  0x7F,  0x49,  0x49,  0x49,  0x7F,  0x36,  0x0,    // [0x38] '8'
+    0x6,  0xF,  0x9,  0x9,  0x9,  0x7F,  0x7F,  0x0,    // [0x39] '9'
+    0x0,  0x0,  0x0,  0x63,  0x63,  0x0,  0x0,  0x0,    // [0x3A] ':'
+    0x0,  0x0,  0x80,  0xE3,  0x63,  0x0,  0x0,  0x0,    // [0x3B] ';'
+    0x0,  0x8,  0x1C,  0x36,  0x63,  0x41,  0x0,  0x0,    // [0x3C] '<'
+    0x0,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x0,    // [0x3D] '='
+    0x0,  0x41,  0x63,  0x36,  0x1C,  0x8,  0x0,  0x0,    // [0x3E] '>'
+    0x2,  0x3,  0xD1,  0xD9,  0x9,  0xF,  0x6,  0x0,    // [0x3F] '?'
+    0x3E,  0x7F,  0x41,  0x5D,  0x55,  0x5F,  0xE,  0x0,    // [0x40] '@'
+    0x7E,  0x7F,  0x9,  0x9,  0x9,  0x7F,  0x7E,  0x0,    // [0x41] 'A'
+    0x7F,  0x7F,  0x49,  0x49,  0x49,  0x7F,  0x36,  0x0,    // [0x42] 'B'
+    0x3E,  0x7F,  0x41,  0x41,  0x41,  0x63,  0x22,  0x0,    // [0x43] 'C'
+    0x7F,  0x7F,  0x41,  0x41,  0x63,  0x3E,  0x1C,  0x0,    // [0x44] 'D'
+    0x7F,  0x7F,  0x49,  0x49,  0x49,  0x41,  0x41,  0x0,    // [0x45] 'E'
+    0x7F,  0x7F,  0x9,  0x9,  0x9,  0x1,  0x1,  0x0,    // [0x46] 'F'
+    0x3E,  0x7F,  0x41,  0x49,  0x49,  0x7B,  0x7A,  0x0,    // [0x47] 'G'
+    0x7F,  0x7F,  0x8,  0x8,  0x8,  0x7F,  0x7F,  0x0,    // [0x48] 'H'
+    0x0,  0x41,  0x41,  0x7F,  0x7F,  0x41,  0x41,  0x0,    // [0x49] 'I'
+    0x20,  0x61,  0x41,  0x7F,  0x3F,  0x1,  0x1,  0x0,    // [0x4A] 'J'
+    0x7F,  0x7F,  0x8,  0x1C,  0x36,  0x63,  0x41,  0x0,    // [0x4B] 'K'
+    0x7F,  0x7F,  0x40,  0x40,  0x40,  0x40,  0x40,  0x0,    // [0x4C] 'L'
+    0x7F,  0x7F,  0x6,  0xC,  0x6,  0x7F,  0x7F,  0x0,    // [0x4D] 'M'
+    0x7F,  0x7F,  0x6,  0xC,  0x18,  0x7F,  0x7F,  0x0,    // [0x4E] 'N'
+    0x3E,  0x7F,  0x41,  0x41,  0x41,  0x7F,  0x3E,  0x0,    // [0x4F] 'O'
+    0x7F,  0x7F,  0x9,  0x9,  0x9,  0xF,  0x6,  0x0,    // [0x50] 'P'
+    0x3E,  0x7F,  0x41,  0x61,  0xC1,  0xFF,  0xBE,  0x0,    // [0x51] 'Q'
+    0x7F,  0x7F,  0x9,  0x9,  0x9,  0x7F,  0x76,  0x0,    // [0x52] 'R'
+    0x26,  0x6F,  0x49,  0x49,  0x49,  0x7B,  0x32,  0x0,    // [0x53] 'S'
+    0x0,  0x1,  0x1,  0x7F,  0x7F,  0x1,  0x1,  0x0,    // [0x54] 'T'
+    0x3F,  0x7F,  0x40,  0x40,  0x40,  0x7F,  0x7F,  0x0,    // [0x55] 'U'
+    0x0,  0x7,  0x1F,  0x78,  0x78,  0x1F,  0x7,  0x0,    // [0x56] 'V'
+    0x7F,  0x7F,  0x30,  0x18,  0x30,  0x7F,  0x7F,  0x0,    // [0x57] 'W'
+    0x63,  0x77,  0x1C,  0x8,  0x1C,  0x77,  0x63,  0x0,    // [0x58] 'X'
+    0x27,  0x6F,  0x48,  0x48,  0x48,  0x7F,  0x3F,  0x0,    // [0x59] 'Y'
+    0x61,  0x71,  0x59,  0x4D,  0x47,  0x43,  0x41,  0x0,    // [0x5A] 'Z'
+    0x0,  0x0,  0xFF,  0xFF,  0x81,  0x81,  0x0,  0x0,    // [0x5B] '['
+    0x0,  0x3,  0xF,  0x3C,  0xF0,  0xC0,  0x0,  0x0,    // [0x5C] '\\'
+    0x0,  0x0,  0x81,  0x81,  0xFF,  0xFF,  0x0,  0x0,    // [0x5D] ']'
+    0x4,  0x6,  0x3,  0x1,  0x3,  0x6,  0x4,  0x0,    // [0x5E] '^'
+    0x80,  0x80,  0x80,  0x80,  0x80,  0x80,  0x80,  0x0,    // [0x5F] '_'
+    0x3,  0x7,  0x4,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x60] '`'
+    0x38,  0x7C,  0x44,  0x44,  0x24,  0x7C,  0x78,  0x0,    // [0x61] 'a'
+    0x7F,  0x7F,  0x24,  0x44,  0x44,  0x7C,  0x38,  0x0,    // [0x62] 'b'
+    0x38,  0x7C,  0x44,  0x44,  0x44,  0x44,  0x44,  0x0,    // [0x63] 'c'
+    0x38,  0x7C,  0x44,  0x44,  0x24,  0x7F,  0x7F,  0x0,    // [0x64] 'd'
+    0x38,  0x7C,  0x54,  0x54,  0x54,  0x5C,  0x8,  0x0,    // [0x65] 'e'
+    0x0,  0x4,  0x7E,  0x7F,  0x5,  0x1,  0x0,  0x0,    // [0x66] 'f'
+    0x18,  0xBC,  0xA4,  0xA4,  0x94,  0xFC,  0x78,  0x0,    // [0x67] 'g'
+    0x7F,  0x7F,  0x8,  0x4,  0x4,  0x7C,  0x78,  0x0,    // [0x68] 'h'
+    0x0,  0x0,  0x0,  0x7D,  0x7D,  0x0,  0x0,  0x0,    // [0x69] 'i'
+    0x0,  0x40,  0x40,  0x40,  0x7D,  0x3D,  0x0,  0x0,    // [0x6A] 'j'
+    0x7F,  0x7F,  0x8,  0x8,  0x1C,  0x76,  0x62,  0x0,    // [0x6B] 'k'
+    0x0,  0x0,  0x0,  0x7F,  0x7F,  0x0,  0x0,  0x0,    // [0x6C] 'l'
+    0x78,  0x7C,  0x18,  0x30,  0x18,  0x7C,  0x78,  0x0,    // [0x6D] 'm'
+    0x7C,  0x7C,  0x8,  0x4,  0x4,  0x7C,  0x78,  0x0,    // [0x6E] 'n'
+    0x38,  0x7C,  0x44,  0x44,  0x44,  0x7C,  0x38,  0x0,    // [0x6F] 'o'
+    0xFC,  0xFC,  0x28,  0x24,  0x24,  0x3C,  0x18,  0x0,    // [0x70] 'p'
+    0x1C,  0x1E,  0x22,  0x22,  0x12,  0xFE,  0xFE,  0x0,    // [0x71] 'q'
+    0x7C,  0x7C,  0x8,  0x4,  0x4,  0xC,  0x8,  0x0,    // [0x72] 'r'
+    0x48,  0x5C,  0x54,  0x54,  0x54,  0x74,  0x20,  0x0,    // [0x73] 's'
+    0x3F,  0x7F,  0x44,  0x44,  0x44,  0x60,  0x20,  0x0,    // [0x74] 't'
+    0x3C,  0x7C,  0x40,  0x40,  0x20,  0x7C,  0x7C,  0x0,    // [0x75] 'u'
+    0x0,  0xC,  0x3C,  0x70,  0x70,  0x3C,  0xC,  0x0,    // [0x76] 'v'
+    0x3C,  0x7C,  0x30,  0x18,  0x30,  0x7C,  0x3C,  0x0,    // [0x77] 'w'
+    0x44,  0x6C,  0x38,  0x10,  0x38,  0x6C,  0x44,  0x0,    // [0x78] 'x'
+    0xC,  0x5C,  0x50,  0x50,  0x50,  0x7C,  0x3C,  0x0,    // [0x79] 'y'
+    0x44,  0x64,  0x74,  0x54,  0x5C,  0x4C,  0x44,  0x0,    // [0x7A] 'z'
+    0x0,  0x8,  0x3E,  0x77,  0x41,  0x0,  0x0,  0x0,    // [0x7B] '{'
+    0x0,  0x0,  0x0,  0xFF,  0xFF,  0x0,  0x0,  0x0,    // [0x7C] '|'
+    0x0,  0x41,  0x77,  0x3E,  0x8,  0x0,  0x0,  0x0,    // [0x7D] '}'
+    0x2,  0x3,  0x1,  0x3,  0x2,  0x3,  0x1,  0x0,    // [0x7E] '~'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x7F] ''
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x80] '€'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x81] ''
+    0x0,  0x0,  0x80,  0xE0,  0x60,  0x0,  0x0,  0x0,    // [0x82] '‚'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x83] 'ƒ'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x84] '„'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x85] '…'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x86] '†'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x87] '‡'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x88] 'ˆ'
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SSD1306/ssd1306.cpp	Thu Jun 26 22:43:10 2014 +0000
@@ -0,0 +1,423 @@
+
+#include "mbed.h"
+#include "ssd1306.h"
+
+#include <stdarg.h>
+
+#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
+
+SSD1306::SSD1306(PinName cs, PinName rs, PinName dc, PinName clk, PinName data)
+    : _spi(data, NC, clk), 
+      _cs(cs), 
+      _reset(rs), 
+      _dc(dc),
+      _cursor_x(0),
+      _cursor_y(0)
+{
+}
+
+void SSD1306::off()
+{
+    _send_command(0xAE);
+}
+
+void SSD1306::on()
+{
+    _send_command(0xAF);
+}
+
+void SSD1306::sleep()
+{
+    _send_command(0xAE);
+}
+
+void SSD1306::wake()
+{
+    _send_command(0xAF);
+}
+
+void SSD1306::set_inverse(unsigned char value)
+{
+    _send_command(value ? 0xA7 : 0xA6);
+}
+
+void SSD1306::set_display_offset(unsigned char value)
+{
+    _send_command(0xD3);
+    _send_command(value & 0x3F); 
+}
+
+void SSD1306::set_contrast(unsigned char value) 
+{
+    _send_command(0x81);
+    _send_command(value);
+}
+
+void SSD1306::set_display_start_line(unsigned char value)
+{
+    _send_command(0x40 | value);
+}
+
+void SSD1306::set_segment_remap(unsigned char value)
+{
+    _send_command(value ? 0xA1 : 0xA0);
+}
+
+void SSD1306::set_multiplex_ratio(unsigned char value)
+{
+    _send_command(0xA8);
+    _send_command(value & 0x3F);
+}
+
+void SSD1306::set_com_output_scan_direction(unsigned char value)
+{
+    _send_command(value ? 0xC8 : 0xC0);
+}
+
+void SSD1306::set_com_pins_hardware_configuration(unsigned char sequential, unsigned char lr_remap)
+{
+    _send_command(0xDA);
+    _send_command(0x02 | ((sequential & 1) << 4) | ((lr_remap & 1) << 5));
+}
+
+void SSD1306::start_horizontal_scroll(unsigned char direction, unsigned char start, unsigned char end, unsigned char interval) 
+{
+    _send_command(direction ? 0x27 : 0x26);
+    _send_command(0x00);
+    _send_command(start & 0x07);
+    switch (interval) {
+        case   2: _send_command(0x07); break; // 111b
+        case   3: _send_command(0x04); break; // 100b
+        case   4: _send_command(0x05); break; // 101b
+        case   5: _send_command(0x00); break; // 000b
+        case  25: _send_command(0x06); break; // 110b
+        case  64: _send_command(0x01); break; // 001b
+        case 128: _send_command(0x02); break; // 010b
+        case 256: _send_command(0x03); break; // 011b
+        default:
+            // default to 2 frame interval
+            _send_command(0x07); break;
+    }
+    _send_command(end & 0x07);
+    _send_command(0x00);
+    _send_command(0xFF);
+    
+    // activate scroll
+    _send_command(0x2F);
+}
+
+void SSD1306::start_vertical_and_horizontal_scroll(unsigned char direction, unsigned char start, unsigned char end, unsigned char interval, unsigned char vertical_offset)
+{
+    _send_command(direction ? 0x2A : 0x29);
+    _send_command(0x00);
+    _send_command(start & 0x07);
+    switch (interval) {
+        case   2: _send_command(0x07); break; // 111b
+        case   3: _send_command(0x04); break; // 100b
+        case   4: _send_command(0x05); break; // 101b
+        case   5: _send_command(0x00); break; // 000b
+        case  25: _send_command(0x06); break; // 110b
+        case  64: _send_command(0x01); break; // 001b
+        case 128: _send_command(0x02); break; // 010b
+        case 256: _send_command(0x03); break; // 011b
+        default:
+            // default to 2 frame interval
+            _send_command(0x07); break;
+    }
+    _send_command(end & 0x07);
+    _send_command(vertical_offset);    
+    
+    // activate scroll
+    _send_command(0x2F);
+}
+
+void SSD1306::stop_scroll()
+{
+    // all scroll configurations are removed from the display when executing this command.
+    _send_command(0x2E);
+}
+
+void SSD1306::pam_set_start_address(unsigned char address)
+{
+    // "Set Lower Column Start Address for Page Addressing Mode"
+    _send_command(address & 0x0F);
+    
+    // "Set Higher Column Start Address for Page Addressing Mode"
+    _send_command((address << 4) & 0x0F);
+}
+
+void SSD1306::set_memory_addressing_mode(unsigned char mode)
+{
+    _send_command(0x20);
+    _send_command(mode & 0x3);
+}
+
+void SSD1306::hv_set_column_address(unsigned char start, unsigned char end)
+{
+    _send_command(0x21);
+    _send_command(start & 0x7F);
+    _send_command(end & 0x7F);
+}
+
+void SSD1306::hv_set_page_address(unsigned char start, unsigned char end)
+{
+    _send_command(0x22);
+    _send_command(start & 0x07);
+    _send_command(end & 0x07);
+}
+
+void SSD1306::pam_set_page_start(unsigned char address)
+{
+    _send_command(0xB0 | (address & 0x07));
+}
+
+void SSD1306::set_display_clock_ratio_and_frequency(unsigned char ratio, unsigned char frequency)
+{
+    _send_command(0xD5);
+    _send_command((ratio & 0x0F) | ((frequency & 0x0F) << 4));
+}
+
+void SSD1306::set_precharge_period(unsigned char phase1, unsigned char phase2)
+{
+    _send_command(0xD9);
+    _send_command((phase1 & 0x0F) | ((phase2 & 0x0F ) << 4));
+}
+
+void SSD1306::set_vcomh_deselect_level(unsigned char level)
+{
+    _send_command(0xDB);
+    _send_command((level & 0x03) << 4);
+}
+
+void SSD1306::nop()
+{
+    _send_command(0xE3);
+}
+
+void SSD1306::set_charge_pump_enable(unsigned char enable)
+{
+    _send_command(0x8D);
+    _send_command(enable ? 0x14 : 0x10);
+}
+
+void SSD1306::initialise()
+{
+    // Init
+    _reset = 1;
+    wait(0.01);
+    _reset = 0;
+    wait(0.10);
+    _reset = 1;
+    
+    off();
+
+    set_display_clock_ratio_and_frequency(0, 8);
+    set_multiplex_ratio(0x3F); // 1/64 duty
+    set_precharge_period(0xF, 0x01);
+    set_display_offset(0);    
+    set_display_start_line(0);  
+    set_charge_pump_enable(1);    
+    set_memory_addressing_mode(0); // horizontal addressing mode; across then down
+    set_segment_remap(1);
+    set_com_output_scan_direction(1);
+    set_com_pins_hardware_configuration(1, 0);
+    set_contrast(0xFF);
+    set_vcomh_deselect_level(1);
+    
+    wake();
+    set_inverse(0);
+    
+    hv_set_column_address(0, 127);
+    hv_set_page_address(0, 7);
+    
+    pam_set_start_address(0);
+    pam_set_page_start(0);
+    
+    // set_precharge_period(2, 2);
+}
+
+void SSD1306::update()
+{
+    hv_set_column_address(0, 127);
+    hv_set_page_address(0, 7);
+    
+    for (int i = 0; i < 1024; i++)
+        _send_data(_screen[i]);
+}
+
+void SSD1306::drawBitmap(int x, int y,
+                  const unsigned char *bitmap, int w, int h, int color) {
+  int16_t i, j, byteWidth = (w + 7) / 8;
+
+  for(j=0; j<h; j++) {
+    for(i=0; i<w; i++ ) {
+      if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
+        color? set_pixel(x+i, y+j): clear_pixel(x+i, y+j);
+      }
+    }
+  }
+}
+
+void SSD1306::set_pixel(int x, int y)
+{
+    if (x >= SSD1306_LCDWIDTH || y >= SSD1306_LCDHEIGHT) return;
+    
+    _screen[x + (y / 8) * 128] |= 1 << (y % 8);
+}
+
+void SSD1306::clear_pixel(int x, int y)
+{
+    if (x >= SSD1306_LCDWIDTH || y >= SSD1306_LCDHEIGHT) return;
+    
+    _screen[x + (y / 8) * 128] &= ~(1 << (y % 8));
+}
+
+void SSD1306::line(int x0, int y0, int x1, int y1) {
+  int steep = abs(y1 - y0) > abs(x1 - x0);
+  int t;
+  
+  if (steep) {
+    t = x0; x0 = y0; y0 = t;
+    t = x1; x1 = y1; y1 = t;
+  }
+
+  if (x0 > x1) {
+    t = x0; x0 = x1; x1 = t;
+    t = y0; y0 = y1; y1 = t;
+  }
+
+  int dx, dy;
+  
+  dx = x1 - x0;
+  dy = abs(y1 - y0);
+
+  int err = dx / 2;
+  int ystep;
+
+  if (y0 < y1) {
+    ystep = 1;
+  } else {
+    ystep = -1;}
+
+  for (; x0<x1; x0++) {
+    if (steep) {
+      set_pixel(y0, x0);
+    } else {
+      set_pixel(x0, y0);
+    }
+    err -= dy;
+    if (err < 0) {
+      y0 += ystep;
+      err += dx;
+    }
+  }
+}
+
+void SSD1306::set_font(unsigned char *font, unsigned int width)
+{
+    _console_font_data = font;
+    _console_font_width = width;
+}
+
+void SSD1306::set_double_height_text(unsigned int double_height)
+{
+    _double_height_text = double_height;
+}
+
+void SSD1306::putc(unsigned char c)
+{
+    while (_cursor_x >= (128 / _console_font_width))
+    {
+        _cursor_x -= (128 / _console_font_width);
+        _cursor_y++;            
+    }
+
+    while (_cursor_y > 7)
+    {
+        scroll_up();            
+    }
+
+    switch (c)
+    {
+    case '\n':
+        _cursor_y++;
+        break;
+        
+    case '\r':
+        _cursor_x = 0;
+        break;
+        
+    case '\t':
+        _cursor_x = (_cursor_x + 4) % 4;
+        break;
+        
+    default:
+        for (int b = 0; b < _console_font_width; b++)
+        {
+            _screen[_cursor_x * _console_font_width + _cursor_y * 128 + b] = _console_font_data[(c - FONT_START) * _console_font_width + b];
+        }
+        
+        _cursor_x++;
+    }            
+}
+
+void SSD1306::scroll_up()
+{
+    for (int y = 1; y <= 7; y++)
+    {
+        for (int x = 0; x < 128; x++)
+        {
+            _screen[x + 128 * (y - 1)] = _screen[x + 128 * y];
+        }
+    }
+    
+    for (int x = 0; x < 128; x++)
+    {
+        _screen[x + 128 * 7] = 0;
+    }    
+
+    _cursor_y--;
+}
+
+void SSD1306::printf(const char *format, ...)
+{
+    static char buffer[128];
+    
+    va_list args;
+    va_start(args, format);
+    vsprintf(buffer, format, args);
+    va_end(args);
+    
+    char *c = (char *)&buffer;
+    while (*c != 0)
+    {
+        putc(*c++);
+    }
+}
+
+void SSD1306::clear()
+{
+    for (int i = 0; i < 1024; i++)
+        _screen[i] = 0;
+        
+    _cursor_x = 0;
+    _cursor_y = 0;
+}
+
+void SSD1306::_send_command(unsigned char code)
+{
+    _cs = 1;
+    _dc = 0;
+    _cs = 0;
+    _spi.write(code);
+    _cs = 1;
+}
+
+void SSD1306::_send_data(unsigned char value)
+{
+    _cs = 1;
+    _dc = 1;
+    _cs = 0;
+    _spi.write(value);
+    _cs = 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SSD1306/ssd1306.h	Thu Jun 26 22:43:10 2014 +0000
@@ -0,0 +1,237 @@
+#ifndef __SSD1306_H__
+#define __SSD1306_H__
+
+#define FONT_START          ' '  /* First character value in the font table */
+
+/** SSD1306 Controller Driver
+  *
+  * This class provides a buffered display for the SSD1306 OLED controller.
+  * 
+  * TODO: 
+  *   - At the moment, the driver assumes a 128x64 pixel display.
+  *   - Only fonts of 8 pixel height are supported (different widths can be used).
+  *   - Pretty much no drawing functions are provided as yet.
+  *   - Possible "auto-update", automatically calling update() after a printf etc.
+  *
+  * Information taken from the datasheet at:
+  *   http://www.adafruit.com/datasheets/SSD1306.pdf
+  *
+  */
+class SSD1306
+{
+public:
+    /** Construct a new SSD1306 object.
+     *  @param cs The connected C/S pin.
+     *  @param rs The connected RS pin.
+     *  @param dc The connected DC pin.
+     *  @param clk The connected CLK pin.
+     *  @param data The connected Data pin.
+     */
+    SSD1306(PinName cs, PinName rs, PinName dc, PinName clk, PinName data);
+
+    // ----- HARDWARE CONTROL -----
+
+    /** Initialise the display with defaults.*/
+    void initialise();
+    
+    /** Force a refresh of the display.  Copies the buffer to the controller. */
+    void update();
+
+    /** Turn the whole display off.  This will reset all configuration settings on the controller to their defaults. */
+    void off();
+    
+    /** Turn the whole display on.  Used during initialisation. */
+    void on();
+
+    /** Sends the display to sleep, but leaves RAM intact. */
+    void sleep();
+
+    /** Wakes up this display following a sleep() call.
+     *  @see sleep()
+     */
+    void wake();
+
+    /** Set the display contrast.
+     *  @param value The contrast, from 1 to 256.
+     */
+    void set_contrast(unsigned char value); // 1-256
+    
+    /** Set the display to normal or inverse.
+     *  @param value 0 for normal mode, or 1 for inverse mode.
+     */
+    void set_inverse(unsigned char value); // 0 or 1
+    
+    /** Set the display start line.  This is the line at which the display will start rendering.
+     *  @param value A value from 0 to 63 denoting the line to start at.
+     */
+    void set_display_start_line(unsigned char value); // 0-63
+    
+    /** Set the segment remap state.  This allows the module to be addressed as if flipped horizontally.
+      * NOTE: Changing this setting has no effect on data already in the module's GDDRAM.
+      * @param value 0 = column address 0 = segment 0 (the default), 1 = column address 127 = segment 0 (flipped).
+      */
+    void set_segment_remap(unsigned char value); // 0 or 1
+    
+    /** Set the vertical shift by COM.
+      * @param value The number of rows to shift, from 0 - 63.
+      */
+    void set_display_offset(unsigned char value); // 0-63
+    
+    /** Set the multiplex ratio.
+     *  @param value MUX will be set to (value+1). Valid values range from 15 to 63 - MUX 16 to 64.
+     */
+    void set_multiplex_ratio(unsigned char value); // 15-63 (value+1 mux)
+    
+    /** Set COM output scan direction.  If the display is active, this will immediately vertically
+      * flip the display.
+      * @param value 0 = Scan from COM0 (default), 1 = reversed (scan from COM[N-1]).
+      */
+    void set_com_output_scan_direction(unsigned char value); // 0 or 1
+    
+    /** Set COM pins hardware configuration.
+      * @param sequential 0 = Sequental COM pin configuration, 1 = Alternative COM pin configuration (default).
+      * @param lr_remap 0 = Disable COM left/right remap (default), 1 = enable COM left/right remap.
+      */
+    void set_com_pins_hardware_configuration(unsigned char sequential, unsigned char lr_remap); // 0 or 1 for both parametrs
+
+    /** Set up and start a continuous horizontal scroll.
+      * Once you have set up the scrolling, you can deactivate it with stop_scroll().
+      * @param direction 0 for right, 1 for left.
+      * @param start Start page address, 0 - 5.
+      * @param end End page address, 0 - 5.
+      * @param interval Interval in frame frequency.  Valid values are: 2, 3, 4, 5, 25, 64, 128, 256.
+      * @see stop_scrol
+      */
+    void start_horizontal_scroll(unsigned char direction, unsigned char start, unsigned char end, unsigned char interval);
+
+    /** Set up and start a continuous horizontal and vertical scroll.
+      * NOTE: No continuous vertical scroll is available.
+      * Once you have set up the scrolling, you can deactivate it with stop_scroll().
+      * @param direction 0 for vertical and right horizontal scroll, 1 for vertical and left horizontal scroll.
+      * @param start Start page address, 0 - 5.
+      * @param end End page address, 0 - 5.
+      * @param interval Interval in frame frequency.  Valid values are: 2, 3, 4, 5, 25, 64, 128, 256.
+      * @param vertical_offset Offset of vertical scroll, 1 - 63.
+      * @see stop_scroll
+      */
+    void start_vertical_and_horizontal_scroll(unsigned char direction, unsigned char start, unsigned char end, unsigned char interval, unsigned char vertical_offset);
+    
+    /** Deactivate the continuous scroll set up with start_horizontal_scroll() or 
+      * start_vertical_and_horizontal_scroll().
+      * @see set_horizontal_scroll, set_vertical_and_horizontal_scroll
+      */
+    void stop_scroll();
+    
+    // ----- ADDRESSING -----
+    
+    /** Set memory addressing mode to the given value.
+      * @param mode 0 for Horizontal addressing mode, 1 for Vertical addressing mode, or 2 for Page addressing mode (PAM).  2 is the default.
+      */
+    void set_memory_addressing_mode(unsigned char mode);
+    
+    /** Page Addressing Mode: Set the column start address register for
+      * page addressing mode.
+      * @param address The address (full byte).
+      */
+    void pam_set_start_address(unsigned char address);       
+    
+    /** Set the GDDRAM page start address for page addressing mode.
+      * @param address The start page, 0 - 7.
+      */
+    void pam_set_page_start(unsigned char address);
+    
+    /** Set page start and end address for horizontal/vertical addressing mode.
+      * @param start The start page, 0 - 7.
+      * @param end The end page, 0 - 7.
+      */
+    void hv_set_page_address(unsigned char start, unsigned char end);
+    
+    /** Set column address range for horizontal/vertical addressing mode.
+      * @param start Column start address, 0 - 127.
+      * @param end Column end address, 0 - 127.
+      */
+    void hv_set_column_address(unsigned char start, unsigned char end);
+    
+    // ----- TIMING & DRIVING -----
+    /** Set the display clock divide ratio and the oscillator frequency.
+      * @param ratio The divide ratio, default is 0.
+      * @param frequency The oscillator frequency, 0 - 127. Default is 8.  
+      */
+    void set_display_clock_ratio_and_frequency(unsigned char ratio, unsigned char frequency);
+    
+    /** Set the precharge period.
+      * @param phase1 Phase 1 period in DCLK clocks.  1 - 15, default is 2.
+      * @param phase2 Phase 2 period in DCLK clocks.  1 - 15, default is 2.
+      */
+    void set_precharge_period(unsigned char phase1, unsigned char phase2);
+    
+    /** Set the Vcomh deselect level.
+      * @param level 0 = 0.65 x Vcc, 1 = 0.77 x Vcc (default), 2 = 0.83 x Vcc.
+      */
+    void set_vcomh_deselect_level(unsigned char level);
+    
+    /** Perform a "no operation".
+      */
+    void nop();
+    
+    /** Enable/disable charge pump.
+      @param enable 0 to disable, 1 to enable the internal charge pump.
+      */
+    void set_charge_pump_enable(unsigned char enable);
+    
+    // ----- BUFFER EDITING -----
+
+    void clear();  
+    void drawBitmap(int x, int y, const unsigned char *bitmap, int w, int h, int color = 1);
+    void set_pixel(int x, int y);
+    void clear_pixel(int x, int y);
+    void line(int x0, int y0, int x1, int y1);
+
+    /** Set the current console font.
+      * @param font Font data, layed out vertically!
+      * @param width Width of the font characters in pixels.
+      * Fonts are always (at present) 8 pixels in height.
+      */
+    void set_font(unsigned char *font, unsigned int width);
+    
+    /** Set double height text output.
+      * @param double_height If 1, calls to putc(), printf() etc will
+      * result in text taking up 2 lines instead of 1.
+      */
+    void set_double_height_text(unsigned int double_height);
+    
+    /** Put a single character to the screen buffer.
+      * Repeated calls to putc() will cause the cursor to move across and
+      * then down as needed, with scrolling.
+      * @param c The character to write.
+      */
+    void putc(unsigned char c);
+    
+    /** Print to the screen buffer.
+      * printf() will wrap and scroll the screen as needed to display the text given.
+      * @param format Format specifier, same as printf() in normal C.
+      */
+    void printf(const char *format, ...);
+
+    /** Scroll the screen buffer up by one line. */
+    void scroll_up();
+
+private:
+    SPI _spi;
+    DigitalOut _cs, _reset, _dc;
+    unsigned char _screen[1024];
+    
+    int _cursor_x, _cursor_y;
+
+    void _send_command(unsigned char code);
+    void _send_data(unsigned char value);
+    
+    unsigned char *_console_font_data;  
+    unsigned int _console_font_width;
+    unsigned int _double_height_text;
+};
+
+#define SSD1306_LCDWIDTH 128
+#define SSD1306_LCDHEIGHT 64
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SSD1306/standard_font.h	Thu Jun 26 22:43:10 2014 +0000
@@ -0,0 +1,112 @@
+/** Thin 5x8 font. */
+static unsigned char standard_font[] = {
+
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x20] ' '
+    0x0,  0x0,  0x2F,  0x0,  0x0,  0x0,    // [0x21] '!'
+    0x0,  0x3,  0x0,  0x3,  0x0,  0x0,    // [0x22] '"'
+    0x14,  0x3E,  0x14,  0x3E,  0x14,  0x0,    // [0x23] '#'
+    0x24,  0x2A,  0x7F,  0x2A,  0x12,  0x0,    // [0x24] '$'
+    0x22,  0x10,  0x8,  0x4,  0x22,  0x0,    // [0x25] '%'
+    0x18,  0x24,  0x24,  0x1E,  0x4,  0x0,    // [0x26] '&'
+    0x0,  0x0,  0x3,  0x0,  0x0,  0x0,    // [0x27] '''
+    0x0,  0x1C,  0x22,  0x41,  0x0,  0x0,    // [0x28] '('
+    0x0,  0x41,  0x22,  0x1C,  0x0,  0x0,    // [0x29] ')'
+    0x2A,  0x1C,  0x3E,  0x1C,  0x2A,  0x0,    // [0x2A] '*'
+    0x8,  0x8,  0x3E,  0x8,  0x8,  0x0,    // [0x2B] '+'
+    0x0,  0x40,  0x20,  0x0,  0x0,  0x0,    // [0x2C] ','
+    0x8,  0x8,  0x8,  0x8,  0x8,  0x0,    // [0x2D] '-'
+    0x0,  0x0,  0x20,  0x0,  0x0,  0x0,    // [0x2E] '.'
+    0x0,  0xC0,  0x30,  0xC,  0x3,  0x0,    // [0x2F] '/'
+    0x1E,  0x29,  0x2D,  0x25,  0x1E,  0x0,    // [0x30] '0'
+    0x0,  0x22,  0x3F,  0x20,  0x0,  0x0,    // [0x31] '1'
+    0x32,  0x29,  0x29,  0x29,  0x26,  0x0,    // [0x32] '2'
+    0x12,  0x21,  0x29,  0x29,  0x16,  0x0,    // [0x33] '3'
+    0x7,  0x8,  0x8,  0x8,  0x3E,  0x0,    // [0x34] '4'
+    0x17,  0x25,  0x25,  0x25,  0x18,  0x0,    // [0x35] '5'
+    0x1E,  0x25,  0x25,  0x25,  0x18,  0x0,    // [0x36] '6'
+    0x1,  0x1,  0x9,  0x9,  0x3E,  0x0,    // [0x37] '7'
+    0x1A,  0x25,  0x25,  0x25,  0x1A,  0x0,    // [0x38] '8'
+    0x6,  0x9,  0x9,  0x9,  0x3E,  0x0,    // [0x39] '9'
+    0x0,  0x0,  0x22,  0x0,  0x0,  0x0,    // [0x3A] ':'
+    0x0,  0x40,  0x22,  0x0,  0x0,  0x0,    // [0x3B] ';'
+    0x0,  0x8,  0x14,  0x22,  0x41,  0x0,    // [0x3C] '<'
+    0x14,  0x14,  0x14,  0x14,  0x14,  0x0,    // [0x3D] '='
+    0x0,  0x41,  0x22,  0x14,  0x8,  0x0,    // [0x3E] '>'
+    0x2,  0x1,  0x29,  0x9,  0x6,  0x0,    // [0x3F] '?'
+    0x1E,  0x21,  0x2D,  0x2D,  0x6,  0x0,    // [0x40] '@'
+    0x3E,  0x11,  0x11,  0x11,  0x3E,  0x0,    // [0x41] 'A'
+    0x3E,  0x25,  0x25,  0x25,  0x1A,  0x0,    // [0x42] 'B'
+    0x1E,  0x21,  0x21,  0x21,  0x12,  0x0,    // [0x43] 'C'
+    0x3E,  0x21,  0x21,  0x22,  0x1C,  0x0,    // [0x44] 'D'
+    0x3F,  0x29,  0x29,  0x21,  0x21,  0x0,    // [0x45] 'E'
+    0x3F,  0x9,  0x9,  0x1,  0x1,  0x0,    // [0x46] 'F'
+    0x1E,  0x21,  0x29,  0x29,  0x1A,  0x0,    // [0x47] 'G'
+    0x3F,  0x8,  0x8,  0x8,  0x3F,  0x0,    // [0x48] 'H'
+    0x0,  0x21,  0x3F,  0x21,  0x0,  0x0,    // [0x49] 'I'
+    0x10,  0x20,  0x21,  0x21,  0x1F,  0x0,    // [0x4A] 'J'
+    0x3F,  0x8,  0xC,  0x12,  0x21,  0x0,    // [0x4B] 'K'
+    0x1F,  0x20,  0x20,  0x20,  0x20,  0x0,    // [0x4C] 'L'
+    0x3E,  0x1,  0x6,  0x1,  0x3E,  0x0,    // [0x4D] 'M'
+    0x3E,  0x1,  0x1,  0x2,  0x3C,  0x0,    // [0x4E] 'N'
+    0x1E,  0x21,  0x21,  0x21,  0x1E,  0x0,    // [0x4F] 'O'
+    0x3E,  0x11,  0x11,  0x11,  0xE,  0x0,    // [0x50] 'P'
+    0x1E,  0x21,  0x29,  0x71,  0x5E,  0x0,    // [0x51] 'Q'
+    0x3E,  0x9,  0x9,  0x9,  0x36,  0x0,    // [0x52] 'R'
+    0x12,  0x25,  0x25,  0x25,  0x18,  0x0,    // [0x53] 'S'
+    0x1,  0x1,  0x3F,  0x1,  0x1,  0x0,    // [0x54] 'T'
+    0x1F,  0x20,  0x20,  0x20,  0x1F,  0x0,    // [0x55] 'U'
+    0xF,  0x10,  0x20,  0x10,  0xF,  0x0,    // [0x56] 'V'
+    0x1F,  0x20,  0x18,  0x20,  0x1F,  0x0,    // [0x57] 'W'
+    0x31,  0xA,  0x4,  0xA,  0x31,  0x0,    // [0x58] 'X'
+    0x7,  0x28,  0x28,  0x28,  0x1F,  0x0,    // [0x59] 'Y'
+    0x31,  0x29,  0x25,  0x23,  0x21,  0x0,    // [0x5A] 'Z'
+    0x0,  0x7F,  0x41,  0x41,  0x0,  0x0,    // [0x5B] '['
+    0x0,  0x3,  0xC,  0x30,  0xC0,  0x0,    // [0x5C] '\\'
+    0x0,  0x41,  0x41,  0x7F,  0x0,  0x0,    // [0x5D] ']'
+    0x0,  0x2,  0x1,  0x2,  0x0,  0x0,    // [0x5E] '^'
+    0x40,  0x40,  0x40,  0x40,  0x40,  0x0,    // [0x5F] '_'
+    0x1,  0x2,  0x0,  0x0,  0x0,  0x0,    // [0x60] '`'
+    0x1C,  0x22,  0x22,  0x22,  0x3C,  0x0,    // [0x61] 'a'
+    0x1F,  0x22,  0x22,  0x22,  0x1C,  0x0,    // [0x62] 'b'
+    0x1C,  0x22,  0x22,  0x22,  0x20,  0x0,    // [0x63] 'c'
+    0x1C,  0x22,  0x22,  0x22,  0x1F,  0x0,    // [0x64] 'd'
+    0x1C,  0x2A,  0x2A,  0x2A,  0x4,  0x0,    // [0x65] 'e'
+    0x8,  0x7E,  0x9,  0x1,  0x1,  0x0,    // [0x66] 'f'
+    0xC,  0x52,  0x52,  0x52,  0x3C,  0x0,    // [0x67] 'g'
+    0x3F,  0x2,  0x2,  0x2,  0x3C,  0x0,    // [0x68] 'h'
+    0x0,  0x0,  0x3D,  0x0,  0x0,  0x0,    // [0x69] 'i'
+    0x20,  0x40,  0x40,  0x40,  0x3D,  0x0,    // [0x6A] 'j'
+    0x3F,  0x8,  0x8,  0x14,  0x22,  0x0,    // [0x6B] 'k'
+    0x0,  0x1F,  0x20,  0x20,  0x0,  0x0,    // [0x6C] 'l'
+    0x3C,  0x2,  0x4,  0x2,  0x3C,  0x0,    // [0x6D] 'm'
+    0x3C,  0x2,  0x2,  0x2,  0x3C,  0x0,    // [0x6E] 'n'
+    0x1C,  0x22,  0x22,  0x22,  0x1C,  0x0,    // [0x6F] 'o'
+    0x7C,  0x12,  0x12,  0x12,  0xC,  0x0,    // [0x70] 'p'
+    0xC,  0x12,  0x12,  0x12,  0x7E,  0x0,    // [0x71] 'q'
+    0x3C,  0x2,  0x2,  0x2,  0x4,  0x0,    // [0x72] 'r'
+    0x24,  0x2A,  0x2A,  0x2A,  0x10,  0x0,    // [0x73] 's'
+    0x1F,  0x22,  0x22,  0x20,  0x10,  0x0,    // [0x74] 't'
+    0x1E,  0x20,  0x20,  0x20,  0x1E,  0x0,    // [0x75] 'u'
+    0xE,  0x10,  0x20,  0x10,  0xE,  0x0,    // [0x76] 'v'
+    0x1E,  0x20,  0x10,  0x20,  0x1E,  0x0,    // [0x77] 'w'
+    0x22,  0x14,  0x8,  0x14,  0x22,  0x0,    // [0x78] 'x'
+    0xE,  0x50,  0x50,  0x50,  0x3E,  0x0,    // [0x79] 'y'
+    0x22,  0x32,  0x2A,  0x26,  0x22,  0x0,    // [0x7A] 'z'
+    0x0,  0x8,  0x36,  0x41,  0x0,  0x0,    // [0x7B] '{'
+    0x0,  0x0,  0x7F,  0x0,  0x0,  0x0,    // [0x7C] '|'
+    0x0,  0x41,  0x36,  0x8,  0x0,  0x0,    // [0x7D] '}'
+    0x0,  0x2,  0x1,  0x2,  0x1,  0x0,    // [0x7E] '~'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x7F] ''
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x80] '€'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x81] ''
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x82] '‚'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x83] 'ƒ'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x84] '„'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x85] '…'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x86] '†'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x87] '‡'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x88] 'ˆ'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x89] '‰'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x8A] 'Š'
+    0x0,  0x0,  0x0,  0x0,  0x0,  0x0,    // [0x8B] '‹'
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Jun 26 22:43:10 2014 +0000
@@ -0,0 +1,188 @@
+/*
+ Demonstrate 0.96 in. OLED module (128x64/SPI). Revised for use with ST Nucleo L152RE
+ 
+ Note:  On 16 pin OLED module from Taobao, MOSI connects to module D1
+        and CLK (also called SCK) connects to module D0. Module RW and RD lines
+        are connected to GND.
+*/
+
+#include "mbed.h"
+
+#include "ssd1306.h"
+#include "standard_font.h"
+#include "bold_font.h"
+
+/* definitions for ST Nucleo L152RE  */
+#define CSEL  PB_6  // CS  D10
+#define RST   PC_7  //     D9
+#define DCMD  PA_9  // DC  D8
+#define CLK   PA_5  // CLK D13
+#define DATA  PA_7  // MOSI D11
+
+// SSD1306 oled(p8 /* cs */, p9 /* reset */, p14 /* dc */, p13 /* clock */, p11 /* data */); // LPC1768
+// SSD1306 oled(PTA13 /* cs */, PTD5 /* reset */, PTD0 /* dc */, PTD1 /* clock */, PTD2 /* data */); // KL25Z
+// SSD1306 oled(D10 /* cs */, D9 /* reset */, D8 /* dc */, D13 /* clock */, D11 /* data */); // KL05Z or Arduino styles
+SSD1306 oled(CSEL, RST, DCMD, CLK, DATA);   // STM32 Nucleo
+
+#define NUMFLAKES 10
+#define XPOS 0
+#define YPOS 1
+#define DELTAY 2
+
+#define LOGO16_GLCD_HEIGHT 16 
+#define LOGO16_GLCD_WIDTH  16 
+
+static const unsigned char  logo16_glcd_bmp[] =
+{ 0x00, 0xc0, // B00000000, B11000000,
+  0x01, 0xc0, // B00000001, B11000000,
+  0x01, 0xc0, // B00000001, B11000000,
+  0x03, 0xe0, // B00000011, B11100000,
+  0xf3, 0xe0, // B11110011, B11100000,
+  0xfe, 0xf8, // B11111110, B11111000,
+  0x7e, 0xff, // B01111110, B11111111,
+  0x33, 0x9f, // B00110011, B10011111,
+  0x1f, 0xfc, // B00011111, B11111100,
+  0x0d, 0x70, // B00001101, B01110000,
+  0x1b, 0xa0, // B00011011, B10100000,
+  0x3f, 0xe0, // B00111111, B11100000,
+  0x3f, 0xf0, // B00111111, B11110000,
+  0x7c, 0xf0, // B01111100, B11110000,
+  0x70, 0x70, // B01110000, B01110000,
+  0x00, 0x30 }; // B00000000, B00110000 };
+
+void testdrawbitmap(const unsigned char *bitmap, int w, int h) {
+  uint8_t icons[NUMFLAKES][3];
+  srand((unsigned int)time(NULL)); // srandom(123);     // whatever seed
+  int i;
+ 
+  // initialize
+  for (uint8_t f=0; f< NUMFLAKES; f++) {
+    icons[f][XPOS] = rand() % SSD1306_LCDWIDTH; // display.width();
+    icons[f][YPOS] = 0;
+    icons[f][DELTAY] = rand() % 5 + 1;
+#if 0
+    Serial.print("x: ");
+    Serial.print(icons[f][XPOS], DEC);
+    Serial.print(" y: ");
+    Serial.print(icons[f][YPOS], DEC);
+    Serial.print(" dy: ");
+    Serial.println(icons[f][DELTAY], DEC);
+#endif
+  }
+
+  i = 0;
+  while (1) {
+    // draw each icon
+    for (uint8_t f=0; f< NUMFLAKES; f++) {
+      oled.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, 1); // WHITE);
+    }
+    oled.update();
+    wait(0.2); // delay(200);
+    
+    // then erase it + move it
+    for (uint8_t f=0; f< NUMFLAKES; f++) {
+      oled.drawBitmap(icons[f][XPOS], icons[f][YPOS],  logo16_glcd_bmp, w, h, 0); // BLACK);
+      // move it
+      icons[f][YPOS] += icons[f][DELTAY];
+      // if its gone, reinit
+      if (icons[f][YPOS] > SSD1306_LCDHEIGHT) { // display.height()) {
+        icons[f][XPOS] = rand() % SSD1306_LCDWIDTH; // display.width();
+        icons[f][YPOS] = 0;
+        icons[f][DELTAY] = rand() % 5 + 1;
+      }
+    }
+    if (i++ > 100) break;
+   }
+
+}
+
+void testdrawline() {  
+  for (int16_t i=0; i<SSD1306_LCDWIDTH; i+=4) {
+    oled.line(0, 0, i, SSD1306_LCDHEIGHT-1);
+    oled.update();
+  }
+  for (int16_t i=0; i<SSD1306_LCDHEIGHT; i+=4) {
+    oled.line(0, 0, SSD1306_LCDWIDTH-1, i);
+    oled.update();
+  }
+  wait(0.25); // delay(250);
+  
+  oled.clear();
+  for (int16_t i=0; i<SSD1306_LCDWIDTH; i+=4) {
+    oled.line(0, SSD1306_LCDHEIGHT-1, i, 0);
+    oled.update();
+  }
+  for (int16_t i=SSD1306_LCDHEIGHT-1; i>=0; i-=4) {
+    oled.line(0, SSD1306_LCDHEIGHT-1, SSD1306_LCDWIDTH-1, i);
+    oled.update();
+  }
+  wait(0.25); // delay(250);
+  
+  oled.clear();
+  for (int16_t i=SSD1306_LCDWIDTH-1; i>=0; i-=4) {
+    oled.line(SSD1306_LCDWIDTH-1, SSD1306_LCDHEIGHT-1, i, 0);
+    oled.update();
+  }
+  for (int16_t i=SSD1306_LCDHEIGHT-1; i>=0; i-=4) {
+    oled.line(SSD1306_LCDWIDTH-1, SSD1306_LCDHEIGHT-1, 0, i);
+    oled.update();
+  }
+  wait(0.25); // delay(250);
+
+  oled.clear();
+  for (int16_t i=0; i<SSD1306_LCDHEIGHT; i+=4) {
+    oled.line(SSD1306_LCDWIDTH-1, 0, 0, i);
+    oled.update();
+  }
+  for (int16_t i=0; i<SSD1306_LCDWIDTH; i+=4) {
+    oled.line(SSD1306_LCDWIDTH-1, 0, i, SSD1306_LCDHEIGHT-1); 
+    oled.update();
+  }
+  wait(0.25);
+}
+
+int main()
+{
+    oled.initialise();
+    oled.clear();
+    oled.set_contrast(255); // max contrast
+    
+    while(1)
+    {
+        
+    oled.drawBitmap(30, 16,  logo16_glcd_bmp, 16, 16);
+    oled.update();
+    wait(3);
+    
+    testdrawline();
+    
+    oled.clear();
+    testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH);
+
+    oled.set_font(bold_font, 8);
+    oled.printf("Heading\r\n");
+
+    oled.set_font(standard_font, 6);
+    oled.printf("Hello World!\r\n");
+    oled.printf("Some more text here...\r\n\r\n\r\n\r\n");
+    // oled.set_font(bold_font, 8);
+    oled.line(127, 0, 0, 63);
+
+    oled.update();
+    wait(1);
+
+    int i = 10;
+    while (i > 0)
+    {
+        wait(1);
+        oled.printf("%d\r\n", i--);
+        oled.update();
+        oled.scroll_up();
+    }
+    
+    oled.clear();
+    
+    } // end outside loop for OLED demo
+}
+
+// EOF
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Jun 26 22:43:10 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/024bf7f99721
\ No newline at end of file