From 144937995c066e8f4aecbeff2f67bc231f08c578 Mon Sep 17 00:00:00 2001 From: Mihai Tudor Panu Date: Thu, 3 Mar 2016 17:22:12 -0800 Subject: [PATCH] ssd1351: Initial implementation Signed-off-by: Mihai Tudor Panu --- docs/images/ssd1351.jpg | Bin 0 -> 92216 bytes examples/c++/CMakeLists.txt | 17 +- examples/c++/ssd1351.cxx | 61 +++++ src/ssd1351/CMakeLists.txt | 5 + src/ssd1351/gfx.cxx | 218 ++++++++++++++++ src/ssd1351/gfx.h | 453 ++++++++++++++++++++++++++++++++++ src/ssd1351/javaupm_ssd1351.i | 28 +++ src/ssd1351/jsupm_ssd1351.i | 12 + src/ssd1351/pyupm_ssd1351.i | 17 ++ src/ssd1351/ssd1351.cxx | 225 +++++++++++++++++ src/ssd1351/ssd1351.h | 188 ++++++++++++++ 11 files changed, 1216 insertions(+), 8 deletions(-) create mode 100644 docs/images/ssd1351.jpg create mode 100644 examples/c++/ssd1351.cxx create mode 100644 src/ssd1351/CMakeLists.txt create mode 100644 src/ssd1351/gfx.cxx create mode 100644 src/ssd1351/gfx.h create mode 100644 src/ssd1351/javaupm_ssd1351.i create mode 100644 src/ssd1351/jsupm_ssd1351.i create mode 100644 src/ssd1351/pyupm_ssd1351.i create mode 100644 src/ssd1351/ssd1351.cxx create mode 100644 src/ssd1351/ssd1351.h diff --git a/docs/images/ssd1351.jpg b/docs/images/ssd1351.jpg new file mode 100644 index 0000000000000000000000000000000000000000..541d97d1f6593780e69470b8a3e1eb12c127f85f GIT binary patch literal 92216 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 literal 0 HcmV?d00001 diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index 7bfa702c..b2277035 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -10,7 +10,7 @@ macro(get_module_name example_name module_name) elseif ((${example_name} MATCHES "^mq" AND ${length} EQUAL 3) OR ${example_name} STREQUAL "tp401") set (${module_name} "gas") else() - set(${module_name} ${example_name}) + set(${module_name} ${example_name}) endif() endmacro() @@ -25,25 +25,25 @@ macro(add_custom_example example_bin example_src example_module_list) if (MODULE_LIST) list(FIND MODULE_LIST ${module} index) if (${index} EQUAL -1) - set(found_all_modules FALSE) + set(found_all_modules FALSE) endif() endif() endforeach() if (found_all_modules) add_executable (${example_bin} ${example_src}) - target_link_libraries (${example_bin} ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries (${example_bin} ${CMAKE_THREAD_LIBS_INIT}) foreach (module ${example_module_list}) set(module_dir "${PROJECT_SOURCE_DIR}/src/${module}") include_directories (${module_dir}) if (${module} STREQUAL "lcd") - set(module "i2clcd") + set(module "i2clcd") endif() - target_link_libraries (${example_bin} ${module}) + target_link_libraries (${example_bin} ${module}) endforeach() else() MESSAGE(INFO " Ignored ${example_bin}") set (example_bin "") - endif() + endif() endmacro() @@ -56,13 +56,13 @@ macro(add_example example_name) set(module_dir "${PROJECT_SOURCE_DIR}/src/${module_name}") if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${example_src}" AND EXISTS ${module_dir} - AND IS_DIRECTORY ${module_dir}) + AND IS_DIRECTORY ${module_dir}) add_custom_example(${example_bin} ${example_src} ${module_name}) if ((NOT ${example_bin} STREQUAL "") AND (${module_name} STREQUAL "grove")) set(grove_module_path "${PROJECT_SOURCE_DIR}/src/${example_name}") if (EXISTS ${grove_module_path}) include_directories(${grove_module_path}) - target_link_libraries (${example_bin} ${example_name}) + target_link_libraries (${example_bin} ${example_name}) endif() endif() else() @@ -239,6 +239,7 @@ add_example (hdxxvxta) add_example (rhusb) add_example (apds9930) add_example (kxcjk1013) +add_example (ssd1351) # These are special cases where you specify example binary, source file and module(s) include_directories (${PROJECT_SOURCE_DIR}/src) diff --git a/examples/c++/ssd1351.cxx b/examples/c++/ssd1351.cxx new file mode 100644 index 00000000..c0de509f --- /dev/null +++ b/examples/c++/ssd1351.cxx @@ -0,0 +1,61 @@ +#include "mraa.hpp" +#include +#include + +#include "ssd1351.h" + +#define BLACK 0x0000 +#define WHITE 0xFFFF +#define INTEL_BLUE 0x0BF8 + +int main(int argc, char **argv) +{ + // Define colors (16-bit RGB on 5/6/5 bits) + int colors[] = {0x0000, 0x000F, 0x03E0, 0x03EF, + 0x7800, 0x780F, 0x7BE0, 0xC618, + 0x7BEF, 0x001F, 0x07E0, 0x07FF, + 0xF800, 0xF81F, 0xFFE0, 0xFFFF}; +//! [Interesting] + // Initialize display with pins + // oc = 0, dc = 1, r = 2, si = 11, cl = 13 + upm::SSD1351* display = new upm::SSD1351(0, 1, 2); + + // Test lines pixel by pixel + for(int i = 0; i < SSD1351HEIGHT; i++) { + for(int j = 0; j < SSD1351WIDTH; j++) { + display->drawPixel(i, j, colors[i/8]); + } + } + display->refresh(); + sleep(5); + + // Test rectangles + for(int i = 0; i < SSD1351HEIGHT/32; i++) { + for (int j = 0; j < SSD1351WIDTH/32; j++) { + display->fillRect(i * 32, j * 32, 32, 32, colors[i * 4 + j]); + } + } + display->refresh(); + sleep(5); + + // Test circles + display->fillScreen(0x2104); + for(int i = 0; i < SSD1351HEIGHT/32; i++) { + for (int j = 0; j < SSD1351WIDTH/32; j++) { + display->drawCircle(i * 32 + 15, j * 32 + 15, 15, colors[i * 4 + j]); + } + } + display->refresh(); + sleep(5); + + // Test Text + display->fillScreen(INTEL_BLUE); + display->setTextColor(WHITE, INTEL_BLUE); + display->setTextSize(4); + display->setCursor(7, 30); + display->print("Intel"); + display->setCursor(5, 70); + display->print("IoTDK"); + display->refresh(); +//! [Interesting] +} diff --git a/src/ssd1351/CMakeLists.txt b/src/ssd1351/CMakeLists.txt new file mode 100644 index 00000000..ee75b73a --- /dev/null +++ b/src/ssd1351/CMakeLists.txt @@ -0,0 +1,5 @@ +set (libname "ssd1351") +set (libdescription "libupm SSD1351 SPI LCD") +set (module_src gfx.cxx ssd1351.cxx) +set (module_h gfx.h ssd1351.h) +upm_module_init() diff --git a/src/ssd1351/gfx.cxx b/src/ssd1351/gfx.cxx new file mode 100644 index 00000000..443932e0 --- /dev/null +++ b/src/ssd1351/gfx.cxx @@ -0,0 +1,218 @@ +/* + * Authors: Yevgeniy Kiveisha + * Mihai Tudor Panu + * + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "gfx.h" + +using namespace upm; + +GFX::GFX (int width, int height) : m_width(width), m_height(height), + m_textSize(1), m_textColor(0xFFFF), m_textBGColor(0x0000), + m_cursorX(0), m_cursorY(0), m_font(font) { +} + +GFX::~GFX () { +} + +void +GFX::fillScreen (uint16_t color) { + fillRect(0, 0, m_width, m_height, color); +} + +void +GFX::fillRect (int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { + for (int16_t i=x; i abs(x1 - x0); + + if (steep) { + swap(x0, y0); + swap(x1, y1); + } + + if (x0 > x1) { + swap(x0, x1); + swap(y0, y1); + } + + int16_t dx, dy; + dx = x1 - x0; + dy = abs (y1 - y0); + + int16_t err = dx / 2; + int16_t ystep; + + if (y0 < y1) { + ystep = 1; + } else { + ystep = -1; + } + + for (; x0 <= x1; x0++) { + if (steep) { + drawPixel(y0, x0, color); + } else { + drawPixel(x0, y0, color); + } + err -= dy; + if (err < 0) { + y0 += ystep; + err += dx; + } + } +} + +void +GFX::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) { + drawLine(x0, y0, x1, y1, color); + drawLine(x1, y1, x2, y2, color); + drawLine(x2, y2, x0, y0, color); +} + +void +GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) { + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + drawPixel(x0 , y0+r, color); + drawPixel(x0 , y0-r, color); + drawPixel(x0+r, y0 , color); + drawPixel(x0-r, y0 , color); + + while (x= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + + ddF_x += 2; + f += ddF_x; + + drawPixel(x0 + x, y0 + y, color); + drawPixel(x0 - x, y0 + y, color); + drawPixel(x0 + x, y0 - y, color); + drawPixel(x0 - x, y0 - y, color); + drawPixel(x0 + y, y0 + x, color); + drawPixel(x0 - y, y0 + x, color); + drawPixel(x0 + y, y0 - x, color); + drawPixel(x0 - y, y0 - x, color); + } +} + +void +GFX::setCursor (int16_t x, int16_t y) { + m_cursorX = x; + m_cursorY = y; +} + +void +GFX::setTextColor (uint16_t textColor, uint16_t textBGColor) { + m_textColor = textColor; + m_textBGColor = textBGColor; +} + +void +GFX::setTextSize (uint8_t size) { + m_textSize = (size > 0) ? size : 1; +} + +void +GFX::setTextWrap (uint8_t wrap) { + m_wrap = wrap; +} + +void +GFX::drawChar (int16_t x, int16_t y, uint8_t data, uint16_t color, uint16_t bg, uint8_t size) { + if( (x >= m_width) || // Clip right + (y >= m_height) || // Clip bottom + ((x + 6 * size - 1) < 0) || // Clip left + ((y + 8 * size - 1) < 0)) // Clip top + return; + + for (int8_t i=0; i<6; i++ ) { + uint8_t line; + if (i == 5) { + line = 0x0; + } else { + line = *(m_font+(data * 5)+i); + for (int8_t j = 0; j<8; j++) { + if (line & 0x1) { + if (size == 1) // default size + drawPixel (x+i, y+j, color); + else { // big size + fillRect (x+(i*size), y+(j*size), size, size, color); + } + } else if (bg != color) { + if (size == 1) // default size + drawPixel (x+i, y+j, bg); + else { // big size + fillRect (x+i*size, y+j*size, size, size, bg); + } + } + line >>= 1; + } + } + } +} + +void +GFX::print (std::string msg) { + int len = msg.length(); + + for (int idx = 0; idx < len; idx++) { + if (msg[idx] == '\n') { + m_cursorY += m_textSize * 8; + m_cursorX = 0; + } else if (msg[idx] == '\r') { + // skip em + } else { + drawChar(m_cursorX, m_cursorY, msg[idx], m_textColor, m_textBGColor, m_textSize); + m_cursorX += m_textSize * 6; + if (m_wrap && ((m_cursorX + m_textSize * 6) >= m_width)) { + m_cursorY += m_textSize * 8; + m_cursorX = 0; + } + } + } +} diff --git a/src/ssd1351/gfx.h b/src/ssd1351/gfx.h new file mode 100644 index 00000000..e199cd2f --- /dev/null +++ b/src/ssd1351/gfx.h @@ -0,0 +1,453 @@ +/* + * Authors: Yevgeniy Kiveisha + * Mihai Tudor Panu + * + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include +#include +#include +#include + +#define swap(a, b) { int16_t t = a; a = b; b = t; } + +namespace upm { + +const unsigned char font[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, + 0x00, 0x18, 0x3C, 0x18, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, + 0x00, 0x18, 0x24, 0x18, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, + 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, + 0x40, 0x7F, 0x05, 0x05, 0x07, + 0x40, 0x7F, 0x05, 0x25, 0x3F, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, + 0x14, 0x22, 0x7F, 0x22, 0x14, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, + 0x06, 0x09, 0x7F, 0x01, 0x7F, + 0x00, 0x66, 0x89, 0x95, 0x6A, + 0x60, 0x60, 0x60, 0x60, 0x60, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, + 0x10, 0x20, 0x7E, 0x20, 0x10, + 0x08, 0x08, 0x2A, 0x1C, 0x08, + 0x08, 0x1C, 0x2A, 0x08, 0x08, + 0x1E, 0x10, 0x10, 0x10, 0x10, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, + 0x30, 0x38, 0x3E, 0x38, 0x30, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + 0x23, 0x13, 0x08, 0x64, 0x62, + 0x36, 0x49, 0x56, 0x20, 0x50, + 0x00, 0x08, 0x07, 0x03, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + 0x08, 0x08, 0x3E, 0x08, 0x08, + 0x00, 0x80, 0x70, 0x30, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x60, 0x60, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, + 0x00, 0x42, 0x7F, 0x40, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, + 0x21, 0x41, 0x49, 0x4D, 0x33, + 0x18, 0x14, 0x12, 0x7F, 0x10, + 0x27, 0x45, 0x45, 0x45, 0x39, + 0x3C, 0x4A, 0x49, 0x49, 0x31, + 0x41, 0x21, 0x11, 0x09, 0x07, + 0x36, 0x49, 0x49, 0x49, 0x36, + 0x46, 0x49, 0x49, 0x29, 0x1E, + 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x41, 0x22, 0x14, 0x08, + 0x02, 0x01, 0x59, 0x09, 0x06, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + 0x7C, 0x12, 0x11, 0x12, 0x7C, + 0x7F, 0x49, 0x49, 0x49, 0x36, + 0x3E, 0x41, 0x41, 0x41, 0x22, + 0x7F, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x49, 0x49, 0x49, 0x41, + 0x7F, 0x09, 0x09, 0x09, 0x01, + 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, + 0x00, 0x41, 0x7F, 0x41, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, + 0x7F, 0x08, 0x14, 0x22, 0x41, + 0x7F, 0x40, 0x40, 0x40, 0x40, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, + 0x7F, 0x04, 0x08, 0x10, 0x7F, + 0x3E, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x09, 0x09, 0x09, 0x06, + 0x3E, 0x41, 0x51, 0x21, 0x5E, + 0x7F, 0x09, 0x19, 0x29, 0x46, + 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, + 0x3F, 0x40, 0x40, 0x40, 0x3F, + 0x1F, 0x20, 0x40, 0x20, 0x1F, + 0x3F, 0x40, 0x38, 0x40, 0x3F, + 0x63, 0x14, 0x08, 0x14, 0x63, + 0x03, 0x04, 0x78, 0x04, 0x03, + 0x61, 0x59, 0x49, 0x4D, 0x43, + 0x00, 0x7F, 0x41, 0x41, 0x41, + 0x02, 0x04, 0x08, 0x10, 0x20, + 0x00, 0x41, 0x41, 0x41, 0x7F, + 0x04, 0x02, 0x01, 0x02, 0x04, + 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, + 0x7F, 0x28, 0x44, 0x44, 0x38, + 0x38, 0x44, 0x44, 0x44, 0x28, + 0x38, 0x44, 0x44, 0x28, 0x7F, + 0x38, 0x54, 0x54, 0x54, 0x18, + 0x00, 0x08, 0x7E, 0x09, 0x02, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, + 0x7F, 0x08, 0x04, 0x04, 0x78, + 0x00, 0x44, 0x7D, 0x40, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, + 0x7C, 0x08, 0x04, 0x04, 0x78, + 0x38, 0x44, 0x44, 0x44, 0x38, + 0xFC, 0x18, 0x24, 0x24, 0x18, + 0x18, 0x24, 0x24, 0x18, 0xFC, + 0x7C, 0x08, 0x04, 0x04, 0x08, + 0x48, 0x54, 0x54, 0x54, 0x24, + 0x04, 0x04, 0x3F, 0x44, 0x24, + 0x3C, 0x40, 0x40, 0x20, 0x7C, + 0x1C, 0x20, 0x40, 0x20, 0x1C, + 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, + 0x4C, 0x90, 0x90, 0x90, 0x7C, + 0x44, 0x64, 0x54, 0x4C, 0x44, + 0x00, 0x08, 0x36, 0x41, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, + 0x3C, 0x26, 0x23, 0x26, 0x3C, + 0x1E, 0xA1, 0xA1, 0x61, 0x12, + 0x3A, 0x40, 0x40, 0x20, 0x7A, + 0x38, 0x54, 0x54, 0x55, 0x59, + 0x21, 0x55, 0x55, 0x79, 0x41, + 0x21, 0x54, 0x54, 0x78, 0x41, + 0x21, 0x55, 0x54, 0x78, 0x40, + 0x20, 0x54, 0x55, 0x79, 0x40, + 0x0C, 0x1E, 0x52, 0x72, 0x12, + 0x39, 0x55, 0x55, 0x55, 0x59, + 0x39, 0x54, 0x54, 0x54, 0x59, + 0x39, 0x55, 0x54, 0x54, 0x58, + 0x00, 0x00, 0x45, 0x7C, 0x41, + 0x00, 0x02, 0x45, 0x7D, 0x42, + 0x00, 0x01, 0x45, 0x7C, 0x40, + 0xF0, 0x29, 0x24, 0x29, 0xF0, + 0xF0, 0x28, 0x25, 0x28, 0xF0, + 0x7C, 0x54, 0x55, 0x45, 0x00, + 0x20, 0x54, 0x54, 0x7C, 0x54, + 0x7C, 0x0A, 0x09, 0x7F, 0x49, + 0x32, 0x49, 0x49, 0x49, 0x32, + 0x32, 0x48, 0x48, 0x48, 0x32, + 0x32, 0x4A, 0x48, 0x48, 0x30, + 0x3A, 0x41, 0x41, 0x21, 0x7A, + 0x3A, 0x42, 0x40, 0x20, 0x78, + 0x00, 0x9D, 0xA0, 0xA0, 0x7D, + 0x39, 0x44, 0x44, 0x44, 0x39, + 0x3D, 0x40, 0x40, 0x40, 0x3D, + 0x3C, 0x24, 0xFF, 0x24, 0x24, + 0x48, 0x7E, 0x49, 0x43, 0x66, + 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, + 0xFF, 0x09, 0x29, 0xF6, 0x20, + 0xC0, 0x88, 0x7E, 0x09, 0x03, + 0x20, 0x54, 0x54, 0x79, 0x41, + 0x00, 0x00, 0x44, 0x7D, 0x41, + 0x30, 0x48, 0x48, 0x4A, 0x32, + 0x38, 0x40, 0x40, 0x22, 0x7A, + 0x00, 0x7A, 0x0A, 0x0A, 0x72, + 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, + 0x26, 0x29, 0x29, 0x29, 0x26, + 0x30, 0x48, 0x4D, 0x40, 0x20, + 0x38, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x38, + 0x2F, 0x10, 0xC8, 0xAC, 0xBA, + 0x2F, 0x10, 0x28, 0x34, 0xFA, + 0x00, 0x00, 0x7B, 0x00, 0x00, + 0x08, 0x14, 0x2A, 0x14, 0x22, + 0x22, 0x14, 0x2A, 0x14, 0x08, + 0xAA, 0x00, 0x55, 0x00, 0xAA, + 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x00, + 0x14, 0x14, 0x14, 0xFF, 0x00, + 0x10, 0x10, 0xFF, 0x00, 0xFF, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x14, 0x14, 0x14, 0xFC, 0x00, + 0x14, 0x14, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x14, 0x14, 0xF4, 0x04, 0xFC, + 0x14, 0x14, 0x17, 0x10, 0x1F, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xFF, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x14, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0x10, 0x17, + 0x00, 0x00, 0xFC, 0x04, 0xF4, + 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, + 0x00, 0x00, 0xFF, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xF7, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x17, 0x14, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0xF4, 0x14, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x00, 0x00, 0x1F, 0x10, 0x1F, + 0x00, 0x00, 0x00, 0x1F, 0x14, + 0x00, 0x00, 0x00, 0xFC, 0x14, + 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, + 0x14, 0x14, 0x14, 0xFF, 0x14, + 0x10, 0x10, 0x10, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x38, 0x44, 0x44, 0x38, 0x44, + 0x7C, 0x2A, 0x2A, 0x3E, 0x14, + 0x7E, 0x02, 0x02, 0x06, 0x06, + 0x02, 0x7E, 0x02, 0x7E, 0x02, + 0x63, 0x55, 0x49, 0x41, 0x63, + 0x38, 0x44, 0x44, 0x3C, 0x04, + 0x40, 0x7E, 0x20, 0x1E, 0x20, + 0x06, 0x02, 0x7E, 0x02, 0x02, + 0x99, 0xA5, 0xE7, 0xA5, 0x99, + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, + 0x4C, 0x72, 0x01, 0x72, 0x4C, + 0x30, 0x4A, 0x4D, 0x4D, 0x30, + 0x30, 0x48, 0x78, 0x48, 0x30, + 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, + 0x7E, 0x01, 0x01, 0x01, 0x7E, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x44, 0x44, 0x5F, 0x44, 0x44, + 0x40, 0x51, 0x4A, 0x44, 0x40, + 0x40, 0x44, 0x4A, 0x51, 0x40, + 0x00, 0x00, 0xFF, 0x01, 0x03, + 0xE0, 0x80, 0xFF, 0x00, 0x00, + 0x08, 0x08, 0x6B, 0x6B, 0x08, + 0x36, 0x12, 0x36, 0x24, 0x36, + 0x06, 0x0F, 0x09, 0x0F, 0x06, + 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, + 0x30, 0x40, 0xFF, 0x01, 0x01, + 0x00, 0x1F, 0x01, 0x01, 0x1E, + 0x00, 0x19, 0x1D, 0x17, 0x12, + 0x00, 0x3C, 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/** + * @brief GFX helper class + * + * This file is used by the screen. + */ +class GFX { + public: + /** + * Instantiates a GFX object + * + * @param width Screen width + * @param height Screen height + */ + GFX (int width, int height); + + /** + * GFX object destructor + */ + ~GFX (); + + /** + * Sends a pixel color (RGB) to the chip. Must be implemented by the + * inherited class. + * + * @param x Axis on the horizontal scale + * @param y Axis on the vertical scale + * @param color RGB value + */ + virtual void drawPixel (int16_t x, int16_t y, uint16_t color) = 0; + + /** + * Copies the buffer to the chip via the SPI. + */ + virtual void refresh () = 0; + + /** + * + * + * @param x Axis on the horizontal scale + * @param y Axis on the vertical scale + * @param data Character to write + * @param color Character color + * @param bg Character background color + * @param size Size of the font + */ + void drawChar (int16_t x, int16_t y, uint8_t data, uint16_t color, uint16_t bg, uint8_t size); + + /** + * Prints a message on the screen + * + * @param msg Message to print + */ + void print (std::string msg); + + /** + * Fills the screen with a selected color + * + * @param color Selected color + */ + void fillScreen (uint16_t color); + + /** + * Fills a rectangle with a selected color + * + * @param x Axis on the horizontal scale (top-left corner) + * @param y Axis on the vertical scale (top-left corner) + * @param w Distanse from x + * @param h Distanse from y + * @param color Selected color + */ + void fillRect (int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + + /** + * Draws a line on the vertical scale + * + * @param x Axis on the horizontal scale + * @param y Axis on the vertical scale + * @param h Distanse from y + * @param color Selected color + */ + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + + /** + * Draws a line from coordinate C0 to coordinate C1 + * + * @param x0 First coordinate + * @param y0 First coordinate + * @param x1 Second coordinate + * @param y1 Second coordinate + * @param color selected color + */ + void drawLine (int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + + /** + * Draws a triangle + * + * @param x0 First coordinate + * @param y0 First coordinate + * @param x1 Second coordinate + * @param y1 Second coordinate + * @param x2 Third coordinate + * @param y2 Third coordinate + * @param color Selected color + */ + void drawTriangle (int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); + + /** + * Draws a circle + * + * @param x Center of the circle on the horizontal scale + * @param y Center of the circle on the vertical scale + * @param r Radius of the circle + * @param color Color of the circle + */ + void drawCircle (int16_t x, int16_t y, int16_t r, uint16_t color); + + /** + * Sets the cursor for a text message + * + * @param x Axis on the horizontal scale + * @param y Axis on the vertical scale + */ + void setCursor (int16_t x, int16_t y); + + /** + * Sets a text color for a message + * + * @param textColor Font color + * @param textBGColor Background color + */ + void setTextColor (uint16_t textColor, uint16_t textBGColor); + + /** + * Sets the size of the font + * + * @param size Font size + */ + void setTextSize (uint8_t size); + + /** + * Wraps a printed message + * + * @param wrap True (0x1) or false (0x0) + */ + void setTextWrap (uint8_t wrap); + + protected: + int m_width; /**< Screen width */ + int m_height; /**< Screen height */ + int m_textSize; /**< Printed text size */ + int m_textColor; /**< Printed text color */ + int m_textBGColor; /**< Printed text background color */ + int m_cursorX; /**< Cursor X coordinate */ + int m_cursorY; /**< Cursor Y coordinate */ + int m_wrap; /**< Wrapper flag (true or false) */ + + const unsigned char * m_font; + }; +} diff --git a/src/ssd1351/javaupm_ssd1351.i b/src/ssd1351/javaupm_ssd1351.i new file mode 100644 index 00000000..7adb59a7 --- /dev/null +++ b/src/ssd1351/javaupm_ssd1351.i @@ -0,0 +1,28 @@ +%module javaupm_ssd1351 +%include "../upm.i" +%include "typemaps.i" +%include "stdint.i" + +%ignore m_map; +%ignore font; + +%include "gfx.h" +%{ + #include "gfx.h" +%} + +%include "ssd1351.h" +%{ + #include "ssd1351.h" +%} + +%pragma(java) jniclasscode=%{ + static { + try { + System.loadLibrary("javaupm_ssd1351"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. \n" + e); + System.exit(1); + } + } +%} \ No newline at end of file diff --git a/src/ssd1351/jsupm_ssd1351.i b/src/ssd1351/jsupm_ssd1351.i new file mode 100644 index 00000000..b0961519 --- /dev/null +++ b/src/ssd1351/jsupm_ssd1351.i @@ -0,0 +1,12 @@ +%module jsupm_ssd1351 +%include "../upm.i" + +%include "gfx.h" +%{ + #include "gfx.h" +%} + +%include "ssd1351.h" +%{ + #include "ssd1351.h" +%} diff --git a/src/ssd1351/pyupm_ssd1351.i b/src/ssd1351/pyupm_ssd1351.i new file mode 100644 index 00000000..fee480d2 --- /dev/null +++ b/src/ssd1351/pyupm_ssd1351.i @@ -0,0 +1,17 @@ +// Include doxygen-generated documentation +%include "pyupm_doxy2swig.i" +%module pyupm_ssd1351 +%include "../upm.i" + +%feature("autodoc", "3"); +%rename("printString") print(std::string msg); + +%include "gfx.h" +%{ + #include "gfx.h" +%} + +%include "ssd1351.h" +%{ + #include "ssd1351.h" +%} diff --git a/src/ssd1351/ssd1351.cxx b/src/ssd1351/ssd1351.cxx new file mode 100644 index 00000000..2103603b --- /dev/null +++ b/src/ssd1351/ssd1351.cxx @@ -0,0 +1,225 @@ +/* + * Author: Mihai Tudor Panu + * Copyright (c) 2016 Intel Corporation. + * + * Based on Adafruit SSD1351 library. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "ssd1351.h" + +using namespace upm; +using namespace std; + +SSD1351::SSD1351 (uint8_t oc, uint8_t dc, uint8_t rst) : + GFX(SSD1351WIDTH, SSD1351HEIGHT), + m_spi(0), m_oc(oc), m_dc(dc), m_rst(rst) { + + m_name = "SSD1351"; + m_usemap = true; + + // Setup SPI bus + m_spi.frequency(8 * 1000000); + m_spi.mode(mraa::SPI_MODE3); + m_spi.writeByte(0x00); // Need to bring clk high before init + + // Init pins + if (m_oc.dir(mraa::DIR_OUT) != mraa::SUCCESS) { + throw std::runtime_error(string(__FUNCTION__) + + ": Could not initialize CS pin"); + return; + } + m_oc.useMmap(true); + if (m_dc.dir(mraa::DIR_OUT) != mraa::SUCCESS) { + throw std::runtime_error(string(__FUNCTION__) + + ": Could not initialize data/cmd pin"); + return; + } + m_dc.useMmap(true); + if (m_rst.dir(mraa::DIR_OUT) != mraa::SUCCESS) { + throw std::runtime_error(string(__FUNCTION__) + + ": Could not initialize reset pin"); + return; + } + + // Toggle reset pin + ocLow(); + m_rst.write(1); + usleep(500000); + m_rst.write(0); + usleep(500000); + m_rst.write(1); + usleep(500000); + + // Configure and init display + writeCommand(SSD1351_CMD_COMMANDLOCK); + writeData(0x12); + + writeCommand(SSD1351_CMD_COMMANDLOCK); + writeData(0xB1); + + writeCommand(SSD1351_CMD_DISPLAYOFF); + + writeCommand(SSD1351_CMD_CLOCKDIV); + writeCommand(0xF1); + + writeCommand(SSD1351_CMD_MUXRATIO); + writeData(127); + + writeCommand(SSD1351_CMD_SETREMAP); + writeData(0x74); + + writeCommand(SSD1351_CMD_SETCOLUMN); + writeData(0x00); + writeData(0x7F); + + writeCommand(SSD1351_CMD_SETROW); + writeData(0x00); + writeData(0x7F); + + writeCommand(SSD1351_CMD_STARTLINE); + if (SSD1351HEIGHT == 96) { + writeData(96); + } else { + writeData(0); + } + + writeCommand(SSD1351_CMD_DISPLAYOFFSET); + writeData(0x0); + + writeCommand(SSD1351_CMD_SETGPIO); + writeData(0x00); + + writeCommand(SSD1351_CMD_FUNCTIONSELECT); + writeData(0x01); + + writeCommand(SSD1351_CMD_PRECHARGE); + writeCommand(0x32); + + writeCommand(SSD1351_CMD_VCOMH); + writeCommand(0x05); + + writeCommand(SSD1351_CMD_NORMALDISPLAY); + + writeCommand(SSD1351_CMD_CONTRASTABC); + writeData(0xC8); + writeData(0x80); + writeData(0xC8); + + writeCommand(SSD1351_CMD_CONTRASTMASTER); + writeData(0x0F); + + writeCommand(SSD1351_CMD_SETVSL ); + writeData(0xA0); + writeData(0xB5); + writeData(0x55); + + writeCommand(SSD1351_CMD_PRECHARGE2); + writeData(0x01); + + writeCommand(SSD1351_CMD_DISPLAYON); +} + +SSD1351::~SSD1351() { +} + +void +SSD1351::writeCommand (uint8_t value) { + dcLow(); + m_spi.writeByte(value); +} + +void +SSD1351::writeData (uint8_t value) { + dcHigh (); + m_spi.writeByte(value); +} + +void +SSD1351::drawPixel(int16_t x, int16_t y, uint16_t color) { + if ((x < 0) || (y < 0) || (x >= SSD1351WIDTH) || (y >= SSD1351HEIGHT)) + return; + + if(m_usemap) { + int index = (y * SSD1351WIDTH + x) * 2; + m_map[index] = color >> 8; + m_map[index + 1] = color; + } else { + writeCommand(SSD1351_CMD_SETCOLUMN); + writeData(x); + writeData(SSD1351WIDTH-1); + + writeCommand(SSD1351_CMD_SETROW); + writeData(y); + writeData(SSD1351HEIGHT-1); + + writeCommand(SSD1351_CMD_WRITERAM); + writeData(color >> 8); + writeData(color); + } +} +void +SSD1351::refresh () { + writeCommand(SSD1351_CMD_WRITERAM); + int blockSize = SSD1351HEIGHT * SSD1351WIDTH * 2 / BLOCKS; + dcHigh(); + for (int block = 0; block < BLOCKS; block++) { + m_spi.write(&m_map[block * blockSize], blockSize); + } +} +void +SSD1351::ocLow() { + if (m_oc.write(LOW) != mraa::SUCCESS) { + throw std::runtime_error(string(__FUNCTION__) + + ": Failed to write CS pin"); + } +} +void +SSD1351::ocHigh() { + if (m_oc.write(HIGH) != mraa::SUCCESS) { + throw std::runtime_error(string(__FUNCTION__) + + ": Failed to write CS pin"); + } +} +void +SSD1351::dcLow() { + if (m_dc.write(LOW) != mraa::SUCCESS) { + throw std::runtime_error(string(__FUNCTION__) + + ": Failed to write data/cmd pin"); + } +} +void +SSD1351::dcHigh() { + if (m_dc.write(HIGH) != mraa::SUCCESS) { + throw std::runtime_error(string(__FUNCTION__) + + ": Failed to write data/cmd pin"); + } +} +void +upm::SSD1351::useMemoryMap(bool var) { + m_usemap = var; +} diff --git a/src/ssd1351/ssd1351.h b/src/ssd1351/ssd1351.h new file mode 100644 index 00000000..6f23c66e --- /dev/null +++ b/src/ssd1351/ssd1351.h @@ -0,0 +1,188 @@ +/* + * Author: Mihai Tudor Panu + * Copyright (c) 2016 Intel Corporation. + * + * Based on Adafruit SSD1351 library. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include + +#include +#include +#include +#include "gfx.h" + +// Display Size +#define SSD1351WIDTH 128 +#define SSD1351HEIGHT 128 // Set this to 96 for 1.27" + +// SSD1351 Commands +#define SSD1351_CMD_SETCOLUMN 0x15 +#define SSD1351_CMD_SETROW 0x75 +#define SSD1351_CMD_WRITERAM 0x5C +#define SSD1351_CMD_READRAM 0x5D +#define SSD1351_CMD_SETREMAP 0xA0 +#define SSD1351_CMD_STARTLINE 0xA1 +#define SSD1351_CMD_DISPLAYOFFSET 0xA2 +#define SSD1351_CMD_DISPLAYALLOFF 0xA4 +#define SSD1351_CMD_DISPLAYALLON 0xA5 +#define SSD1351_CMD_NORMALDISPLAY 0xA6 +#define SSD1351_CMD_INVERTDISPLAY 0xA7 +#define SSD1351_CMD_FUNCTIONSELECT 0xAB +#define SSD1351_CMD_DISPLAYOFF 0xAE +#define SSD1351_CMD_DISPLAYON 0xAF +#define SSD1351_CMD_PRECHARGE 0xB1 +#define SSD1351_CMD_DISPLAYENHANCE 0xB2 +#define SSD1351_CMD_CLOCKDIV 0xB3 +#define SSD1351_CMD_SETVSL 0xB4 +#define SSD1351_CMD_SETGPIO 0xB5 +#define SSD1351_CMD_PRECHARGE2 0xB6 +#define SSD1351_CMD_SETGRAY 0xB8 +#define SSD1351_CMD_USELUT 0xB9 +#define SSD1351_CMD_PRECHARGELEVEL 0xBB +#define SSD1351_CMD_VCOMH 0xBE +#define SSD1351_CMD_CONTRASTABC 0xC1 +#define SSD1351_CMD_CONTRASTMASTER 0xC7 +#define SSD1351_CMD_MUXRATIO 0xCA +#define SSD1351_CMD_COMMANDLOCK 0xFD +#define SSD1351_CMD_HORIZSCROLL 0x96 +#define SSD1351_CMD_STOPSCROLL 0x9E +#define SSD1351_CMD_STARTSCROLL 0x9F + +#define HIGH 1 +#define LOW 0 + +// Number of blocks for SPI transfer of buffer +#define BLOCKS 8 + +namespace upm { +/** + * @brief SSD1351 OLED library + * @defgroup ssd1351 libupm-ssd1351 + * @ingroup adafruit spi display + */ +/** + * @library ssd1351 + * @sensor ssd1351 + * @comname SSD1351 OLED + * @type display + * @man adafruit + * @web http://www.adafruit.com/products/1431 + * @con spi + * + * @brief API for SSD1351 OLED displays + * + * This module defines the interface for the SSD1351 display library + * + * @image html ssd1351.jpg + * @snippet ssd1351.cxx Interesting + */ +class SSD1351 : public GFX{ + public: + /** + * Instantiates an SSD1351 object + * + * @param oc LCD chip select pin + * @param dc Data/command pin + * @param rst Reset pin + */ + SSD1351 (uint8_t oc, uint8_t dc, uint8_t rst); + + /** + * SSD1351 object destructor + */ + ~SSD1351(); + + /** + * Returns the name of the component + */ + std::string name() + { + return m_name; + } + + /** + * Sends a command to an SPI bus + * + * @param value Command + */ + void writeCommand (uint8_t value); + + /** + * Sends data to an SPI bus + * + * @param value Data + */ + void writeData (uint8_t value); + /** + * Sends a pixel color (RGB) to the display buffer or chip + * + * @param x Axis on the horizontal scale + * @param y Axis on the vertical scale + * @param color RGB (16-bit) color (R[0-4], G[5-10], B[11-15]) + */ + void drawPixel (int16_t x, int16_t y, uint16_t color); + + /** + * Copies the buffer to the chip via the SPI bus + */ + void refresh (); + + /** + * Set OLED chip select LOW + */ + void ocLow (); + + /** + * Set OLED chip select HIGH + */ + void ocHigh (); + + /** + * Data select LOW + */ + void dcLow (); + + /** + * Data select HIGH + */ + void dcHigh (); + + /** + * Use memory mapped (buffered) writes to the display + * + * @param var true for yes (default), false for no + */ + void useMemoryMap (bool var); + private: + mraa::Spi m_spi; + uint8_t m_map[SSD1351HEIGHT * SSD1351WIDTH * 2]; /**< Screen buffer */ + bool m_usemap; + + mraa::Gpio m_oc; + mraa::Gpio m_dc; + mraa::Gpio m_rst; + + std::string m_name; +}; +}