Last active
August 10, 2017 23:30
-
-
Save ElectricImpSampleCode/94ec295cd1a71d9b8061add9565ce494 to your computer and use it in GitHub Desktop.
Squirrel Class to control Adafruit SSD1306-based 0.96in 128 x 32/64 OLED
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Constants for the OLED and the SSD1306 | |
const SSD1306_SETCONTRAST = "\x81"; | |
const SSD1306_DISPLAYALLON_RESUME = "\xA4"; | |
const SSD1306_DISPLAYALLON = "\xA5"; | |
const SSD1306_NORMALDISPLAY = "\xA6"; | |
const SSD1306_INVERTDISPLAY = "\xA7"; | |
const SSD1306_DISPLAYOFF = "\xAE"; | |
const SSD1306_DISPLAYON = "\xAF"; | |
const SSD1306_SETDISPLAYOFFSET = "\xD3"; | |
const SSD1306_SETCOMPINS = "\xDA"; | |
const SSD1306_SETVCOMDETECT = "\xDB"; | |
const SSD1306_SETDISPLAYCLOCKDIV = "\xD5"; | |
const SSD1306_SETPRECHARGE = "\xD9"; | |
const SSD1306_SETMULTIPLEX = "\xA8"; | |
const SSD1306_SETLOWCOLUMN = "\x00"; | |
const SSD1306_SETHIGHCOLUMN = "\x10"; | |
const SSD1306_SETSTARTLINE = "\x40"; | |
const SSD1306_ADDRESSMODE = "\x20"; | |
const SSD1306_COLUMNADDR = "\x21"; | |
const SSD1306_PAGEADDR = "\x22"; | |
const SSD1306_COMSCANINC = "\xC0"; | |
const SSD1306_COMSCANDEC = "\xC8"; | |
const SSD1306_SEGREMAP = "\xA1"; | |
const SSD1306_CHARGEPUMP = "\x8D"; | |
const SSD1306_EXTERNALVCC = "\x01"; | |
const SSD1306_SWITCHCAPVCC = "\x02"; | |
// Constants for scolling, as yet unimplemented | |
const SSD1306_ACTIVATE_SCROLL = 0x2F; | |
const SSD1306_DEACTIVATE_SCROLL = 0x2E; | |
const SSD1306_SET_VERTICAL_SCROLL_AREA = 0xA3; | |
const SSD1306_RIGHT_HORIZONTAL_SCROLL = 0x26; | |
const SSD1306_LEFT_HORIZONTAL_SCROLL = 0x27; | |
const SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29; | |
const SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A; | |
const HIGH = 1; | |
const LOW = 0; | |
class SSD1306OLED { | |
// Squirrel Class for Solomon SSD1306 OLED controller chip | |
// [http://www.adafruit.com/datasheets/SSD1306.pdf] | |
// As used on the Adafruit SSD1306 I2C breakout board | |
// [http://www.adafruit.com/products/931] | |
// Bus: I2C | |
// Code by Tony Smith (@smittytone) June 2014 | |
// Version 1.0.2 | |
// Constants for the alphanumeric character set | |
// Each character is an 8 x 8 bitmap rendered | |
// as eight 8-bit values | |
static charset = [ | |
[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], // Space - Ascii 32 | |
[0x00,0x10,0x10,0x10,0x10,0x00,0x10,0x00], // ! | |
[0x00,0x24,0x24,0x00,0x00,0x00,0x00,0x00], // ” | |
[0x00,0x24,0x7E,0x24,0x24,0x7E,0x24,0x00], // # | |
[0x00,0x08,0x3E,0x28,0x3E,0x0A,0x3E,0x08], // $ | |
[0x00,0x62,0x64,0x08,0x10,0x26,0x46,0x00], // % | |
[0x00,0x10,0x28,0x10,0x2A,0x44,0x3A,0x00], // & | |
[0x00,0x08,0x10,0x00,0x00,0x00,0x00,0x00], // ‘ | |
[0x00,0x04,0x08,0x08,0x08,0x08,0x04,0x00], // ( | |
[0x00,0x20,0x10,0x10,0x10,0x10,0x20,0x00], // ) | |
[0x00,0x00,0x14,0x08,0x3E,0x08,0x14,0x00], // * | |
[0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x00], // + | |
[0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10], // , | |
[0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00], // - | |
[0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00], // . | |
[0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x00], // / | |
[0x00,0x3C,0x46,0x4A,0x52,0x62,0x3C,0x00], // 0 - Ascii 48 | |
[0x00,0x30,0x50,0x10,0x10,0x10,0x7C,0x00], // 1 | |
[0x00,0x3C,0x42,0x02,0x3C,0x40,0x7E,0x00], // 2 | |
[0x00,0x3C,0x42,0x0C,0x02,0x42,0x3C,0x00], // 3 | |
[0x00,0x08,0x18,0x28,0x48,0x7E,0x08,0x00], // 4 | |
[0x00,0x7E,0x40,0x7C,0x02,0x42,0x3C,0x00], // 5 | |
[0x00,0x3C,0x40,0x7C,0x42,0x42,0x3C,0x00], // 6 | |
[0x00,0x7E,0x02,0x04,0x08,0x10,0x10,0x00], // 7 | |
[0x00,0x3C,0x42,0x3C,0x42,0x42,0x3C,0x00], // 8 | |
[0x00,0x3C,0x42,0x42,0x3E,0x02,0x3C,0x00], // 9 | |
[0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00], // : - Ascii 58 | |
[0x00,0x00,0x10,0x00,0x00,0x10,0x10,0x20], // ; | |
[0x00,0x00,0x04,0x08,0x10,0x08,0x04,0x00], // < | |
[0x00,0x00,0x00,0x3E,0x00,0x3E,0x00,0x00], // = | |
[0x00,0x00,0x10,0x08,0x04,0x08,0x10,0x00], // > | |
[0x00,0x3C,0x42,0x04,0x08,0x00,0x08,0x00], // ? | |
[0x00,0x3C,0x4A,0x56,0x5E,0x40,0x3C,0x00], // @ | |
[0x00,0x3C,0x42,0x42,0x7E,0x42,0x42,0x00], // A - Ascii 65 | |
[0x00,0x7C,0x42,0x7C,0x42,0x42,0x7C,0x00], // B | |
[0x00,0x3C,0x42,0x40,0x40,0x42,0x3C,0x00], // C | |
[0x00,0x78,0x44,0x42,0x42,0x44,0x78,0x00], // D | |
[0x00,0x7E,0x40,0x7C,0x40,0x40,0x7E,0x00], // E | |
[0x00,0x7E,0x40,0x7C,0x40,0x40,0x40,0x00], // F | |
[0x00,0x3C,0x42,0x40,0x4E,0x42,0x3C,0x00], // G | |
[0x00,0x42,0x42,0x7E,0x42,0x42,0x42,0x00], // H | |
[0x00,0x7C,0x10,0x10,0x10,0x10,0x7C,0x00], // I | |
[0x00,0x02,0x02,0x02,0x02,0x42,0x3C,0x00], // J | |
[0x00,0x44,0x48,0x70,0x48,0x44,0x42,0x00], // K | |
[0x00,0x40,0x40,0x40,0x40,0x40,0x7E,0x00], // L | |
[0x00,0x42,0x66,0x5A,0x42,0x42,0x42,0x00], // M | |
[0x00,0x42,0x62,0x52,0x4A,0x46,0x42,0x00], // N | |
[0x00,0x3C,0x42,0x42,0x42,0x42,0x3C,0x00], // O | |
[0x00,0x7C,0x42,0x42,0x7C,0x40,0x40,0x00], // P | |
[0x00,0x3C,0x42,0x42,0x52,0x4A,0x3C,0x00], // Q | |
[0x00,0x7C,0x42,0x42,0x7C,0x44,0x42,0x00], // R | |
[0x00,0x3C,0x40,0x3C,0x02,0x42,0x3C,0x00], // S | |
[0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x00], // T | |
[0x00,0x42,0x42,0x42,0x42,0x42,0x3C,0x00], // U | |
[0x00,0x42,0x42,0x42,0x42,0x24,0x18,0x00], // V | |
[0x00,0x42,0x42,0x42,0x42,0x5A,0x24,0x00], // W | |
[0x00,0x42,0x24,0x18,0x18,0x24,0x42,0x00], // X | |
[0x00,0x44,0x28,0x10,0x10,0x10,0x10,0x00], // Y | |
[0x00,0x7E,0x04,0x08,0x10,0x20,0x7E,0x00], // Z - Ascii 90 | |
[0x00,0x0E,0x08,0x08,0x08,0x08,0x0E,0x00], // [ | |
[0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x00], // \ | |
[0x00,0x70,0x10,0x10,0x10,0x10,0x70,0x00], // ] | |
[0x00,0x10,0x38,0x54,0x10,0x10,0x10,0x00], // ^ | |
[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF], // _ | |
[0x00,0x1C,0x22,0x78,0x20,0x20,0x7E,0x00], // £ | |
[0x00,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00], // a - Ascii 97 | |
[0x00,0x40,0x40,0x78,0x44,0x44,0x78,0x00], // b | |
[0x00,0x00,0x38,0x40,0x40,0x40,0x38,0x00], // c | |
[0x00,0x04,0x04,0x3C,0x44,0x44,0x3C,0x00], // d | |
[0x00,0x00,0x38,0x44,0x78,0x40,0x3C,0x00], // e | |
[0x00,0x30,0x40,0x60,0x40,0x40,0x40,0x00], // f | |
[0x00,0x3C,0x44,0x44,0x3C,0x04,0x38,0x00], // g | |
[0x00,0x40,0x40,0x40,0x78,0x44,0x44,0x00], // h | |
[0x00,0x20,0x00,0x60,0x20,0x20,0x70,0x00], // i | |
[0x00,0x08,0x00,0x08,0x08,0x48,0x30,0x00], // j | |
[0x00,0x40,0x50,0x60,0x60,0x50,0x48,0x00], // k | |
[0x00,0x40,0x40,0x40,0x40,0x40,0x30,0x00], // l | |
[0x00,0x00,0x68,0x54,0x54,0x54,0x54,0x00], // m | |
[0x00,0x00,0x78,0x44,0x44,0x44,0x44,0x00], // n | |
[0x00,0x00,0x38,0x44,0x44,0x44,0x38,0x00], // o | |
[0x00,0x78,0x44,0x44,0x78,0x40,0x40,0x00], // p | |
[0x00,0x3C,0x44,0x44,0x3C,0x04,0x06,0x00], // q | |
[0x00,0x00,0x1C,0x20,0x20,0x20,0x20,0x00], // r | |
[0x00,0x00,0x38,0x40,0x38,0x04,0x78,0x00], // s | |
[0x00,0x20,0x70,0x20,0x20,0x20,0x18,0x00], // t | |
[0x00,0x00,0x44,0x44,0x44,0x44,0x38,0x00], // u | |
[0x00,0x00,0x44,0x44,0x28,0x28,0x10,0x00], // v | |
[0x00,0x00,0x44,0x54,0x54,0x54,0x28,0x00], // w | |
[0x00,0x00,0x44,0x28,0x10,0x28,0x44,0x00], // x | |
[0x00,0x00,0x44,0x44,0x3C,0x04,0x38,0x00], // y | |
[0x00,0x00,0x7C,0x08,0x10,0x20,0x7C,0x00], // z - Ascii 122 | |
[0x00,0x0E,0x08,0x30,0x08,0x08,0x0E,0x00], // { | |
[0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00], // | | |
[0x00,0x70,0x10,0x0C,0x10,0x10,0x70,0x00], // } | |
[0x00,0x14,0x28,0x00,0x00,0x00,0x00,0x00], // ~ | |
[0x3C,0x42,0x99,0xA1,0xA1,0x99,0x42,0x3C], // © - Ascii 127 | |
[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF], // Block Graphic 1 | |
[0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF], | |
[0xF0,0xF0,0xF0,0xF0,0xFF,0xFF,0xFF,0xFF], | |
[0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF], | |
[0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F], | |
[0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F], | |
[0xF0,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F], | |
[0x00,0x00,0x00,0x00,0x0F,0x0F,0x0F,0x0F], | |
[0xFF,0xFF,0xFF,0xFF,0x55,0xAA,0x55,0xAA], | |
[0xAA,0x55,0xAA,0x55,0xFF,0xFF,0xFF,0xFF], | |
[0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55] // Block Graphic 11 | |
]; | |
// Zero instance variables ahead of constructor function | |
_i2cAddress = 0; | |
_i2c = null; | |
_rst = null; | |
_buffer = null; | |
_alphaCount = 107; | |
_pixelCursor_x = 0; | |
_pixelCursor_y = 0; | |
_textCursor_x = 0; | |
_textCursor_y = 0; | |
_oledWidth = 0; | |
_oledHeight = 0; | |
constructor(bus, address, resetPin, pixelWidth = 128, pixelHeight = 32) { | |
// Parameters: | |
// 1. The chosen imp I2C bus object | |
// 2. The OLED's 7-bit I2C address as an integer | |
// 3. The chosen imp pin object to control the Reset line | |
// 4. OLED pixel width | |
// 5. OLED pixel height | |
_i2c = bus; | |
_i2cAddress = address; | |
_i2c.configure(CLOCK_SPEED_400_KHZ); | |
_rst = resetPin; | |
_rst.configure(DIGITAL_OUT); | |
_oledWidth = pixelWidth; | |
_oledHeight = pixelHeight; | |
_buffer = array((_oledWidth * _oledHeight / 8) , 0); | |
} | |
function init() { | |
// Toggle the RST pin over 1ms + 10ms | |
_rst.write(HIGH); | |
imp.sleep(0.001); | |
_rst.write(LOW); | |
imp.sleep(0.01); | |
_rst.write(HIGH); | |
// Write the display settings | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_DISPLAYOFF); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_SETDISPLAYCLOCKDIV + "\x80"); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_SETMULTIPLEX + "\x1F"); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_SETDISPLAYOFFSET + "\x00"); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_SETSTARTLINE); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_CHARGEPUMP + "\x14"); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_ADDRESSMODE + "\x00"); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_SEGREMAP); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_COMSCANDEC); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_SETCOMPINS + "\x02"); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_SETCONTRAST + "\x8F"); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_SETPRECHARGE + "\xF1"); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_SETVCOMDETECT + "\x40"); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_DISPLAYALLON_RESUME); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_NORMALDISPLAY); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_DISPLAYON); | |
// Clear the screen | |
clearDisplay(); | |
} | |
function setGraphicsCursor(x = 0, y = 0) { | |
if (x < 0 || x > 127 || y < 0 || y > 31) return; | |
_pixelCursor_x = x; | |
_pixelCursor_y = y; | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_COLUMNADDR); | |
_i2c.write(_i2cAddress, "\x00" + _pixelCursor_x.tochar()); | |
_i2c.write(_i2cAddress, "\x00" + (_oledWidth - 1).tochar()); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_PAGEADDR); | |
_i2c.write(_i2cAddress, "\x00" + _pixelCursor_y.tochar()); | |
_i2c.write(_i2cAddress, "\x00" + (_oledHeight - 1).tochar()); | |
} | |
function setTextCursor(row = 0, col = 0) { | |
if (row < 0 || row > 3 || col < 0 || col > 15) return; | |
_textCursor_x = col; | |
_textCursor_y = row; | |
local a = _textCursor_x * 8; | |
local b = _textCursor_y; | |
local c = "\x03"; | |
if (_oledHeight == 64) c = "\x07"; | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_COLUMNADDR + a.tochar() + (_oledWidth - 1).tochar()); | |
_i2c.write(_i2cAddress, "\x00" + SSD1306_PAGEADDR + b.tochar() + c); | |
} | |
function display() { | |
// Writes the display buffer to screen as a single I2C string | |
local dataString = ""; | |
for (local i = 0; i < (_oledWidth * _oledHeight / 8) ; i++) { | |
dataString = dataString + _buffer[i].tochar(); | |
} | |
_i2c.write(_i2cAddress, "\x40" + dataString); | |
} | |
function clearBuffer() { | |
// Wipes the display buffer by writing 0x00 to all array elements | |
for (local i = 0 ; i < 512 ; i++) { | |
_buffer[i] = 0x00; | |
} | |
} | |
function clearDisplay() { | |
// Clear the display: zero the buffer then write it to the screen | |
setGraphicsCursor(0, 0); | |
clearBuffer(); | |
display(); | |
} | |
function inverse(setting = false) { | |
// Set the display to black-on-white or white-on-black | |
// Parameter: | |
// 1. Boolean value determining inverse state of display | |
// 'true' to inverse dislay, 'false' to put it back | |
_i2c.write(_i2cAddress, "\x00" + (setting ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY)); | |
} | |
function printText(stringToPrint) { | |
// Display the input string on the display | |
// Parameter: | |
// 1. String to print | |
if (stringToPrint == "" || stringToPrint == null) return; | |
local dataString = ""; | |
foreach (index, character in stringToPrint) { | |
// Read in each character in the source string, determine its | |
// Ascii value and use this to find the character's bitmap array | |
// in the charset. This array is rotated to match the byte | |
// structure of the OLED's on-board buffer, then its byte values | |
// are added to an I2C data string and transmitted to OLED RAM | |
local ascii = stringToPrint[index] - 32; | |
local glyph = rotateMatrix(charset[ascii]); | |
for (local j = 0 ; j < 8 ; j++) { | |
dataString = dataString + glyph[j].tochar(); | |
} | |
} | |
_i2c.write(_i2cAddress, "\x40" + dataString); | |
} | |
function printIcon(iconArray) { | |
// Display a custom 8 x 8 character icon on the display | |
// Parameter: | |
// 1. Array of eight 8-bit values forming the icon bitmap | |
local data_string = ""; | |
local icon = rotateMatrix(iconArray); | |
for (local i = 0 ; i < 8 ; i++) { | |
dataString = dataString + icon[i].tochar(); | |
} | |
_i2c.write(_i2cAddress, "\x40" + dataString); | |
} | |
function printChar(asciiVal = 32, row = 0, col = 0) { | |
// Display a specific character at a set position | |
// Parameters: | |
// 1. Integer Ascii code of the character to print | |
// 2. Integer row value (0-3) | |
// 3. Integer column value (0-15) | |
asciiVal = asciVal - 32; | |
if (asciiVal < 0 || asciiVal > _alphaCount) return; | |
local dataString = ""; | |
local glyph = rotateMatrix(charset[asciiVal]); | |
setTextCursor(row, col); | |
for (local j = 0 ; j < 8 ; j++) { | |
dataString = dataString + glyph[j].tochar(); | |
} | |
_i2c.write(_i2cAddress, "\x40" + dataString); | |
} | |
function printBitmap(pixelArray) { | |
// Displays a preformatted 128 x 32 or 128 x 64 bitmap image stored in a byte array | |
// Note each byte consists of a row-high set of *vertical* pixels | |
// Parameter: | |
// 1. Array of 512 or 1024 8-bit values | |
if (pixelArray == null || pixelArray.len() <= 0) return; | |
local dataString = ""; | |
setGraphicsCursor(0, 0); | |
foreach (byte in pixelArray) { | |
dataString = dataString + byte.tochar(); | |
} | |
_i2c.write(_i2cAddress, "\x40" + dataString); | |
} | |
function rotateMatrix(inputMatrix) { | |
// Rotate the character matrix through 90 degrees anti-clockwise | |
// Used if the OLED matrix pins are connected directly to a breadboard | |
// Returns a new array | |
local i = 0; | |
local j = 0; | |
local bit = 0; | |
local lineVal = 0; | |
local outputMatrix = [0,0,0,0,0,0,0,0]; | |
for (i = 0 ; i < 8 ; i++) { | |
lineVal = inputMatrix[i]; | |
for (j = 7 ; j > -1 ; j--) { | |
bit = (lineVal & math.pow(2, j).tointeger()); | |
if (bit > 0) outputMatrix[7-j] = outputMatrix[7-j] + math.pow(2, i).tointeger(); | |
} | |
} | |
return outputMatrix; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment