From 3159005aa367c41ece46f271e26325f0cbb0902d Mon Sep 17 00:00:00 2001 From: Marc Graham Date: Thu, 27 Aug 2015 17:28:15 -0700 Subject: [PATCH] ssd1306: initial implementation Signed-off-by: Marc Graham Signed-off-by: Mihai Tudor Panu --- docs/images/ssd1306.jpeg | Bin 0 -> 73623 bytes examples/c++/CMakeLists.txt | 2 + examples/c++/ssd1306-oled.cxx | 149 +++++++++++++ examples/javascript/oled_ssd1306.js | 151 +++++++++++++ src/lcd/CMakeLists.txt | 4 +- src/lcd/javaupm_i2clcd.i | 2 + src/lcd/jsupm_i2clcd.i | 5 + src/lcd/pyupm_i2clcd.i | 5 + src/lcd/ssd1306.cxx | 320 ++++++++++++++++++++++++++++ src/lcd/ssd1306.h | 230 ++++++++++++++++++++ 10 files changed, 866 insertions(+), 2 deletions(-) create mode 100644 docs/images/ssd1306.jpeg create mode 100644 examples/c++/ssd1306-oled.cxx create mode 100644 examples/javascript/oled_ssd1306.js mode change 100644 => 100755 src/lcd/CMakeLists.txt mode change 100644 => 100755 src/lcd/jsupm_i2clcd.i mode change 100644 => 100755 src/lcd/pyupm_i2clcd.i create mode 100644 src/lcd/ssd1306.cxx create mode 100644 src/lcd/ssd1306.h diff --git a/docs/images/ssd1306.jpeg b/docs/images/ssd1306.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e24fda4d517e601becce0044d3630fb824d1a0d7 GIT binary patch literal 73623 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

H@cQ6~tI_7E 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 literal 0 HcmV?d00001 diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index 672be7d2..6c6ecd83 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -19,6 +19,7 @@ add_executable (nrf24l01-receiver-example nrf24l01-receiver.cxx) add_executable (nrf24l01-broadcast-example nrf24l01-broadcast.cxx) add_executable (es08a-example es08a.cxx) add_executable (hcsr04-example hcsr04.cxx) +add_executable (ssd1306-oled-example ssd1306-oled.cxx) add_executable (ssd1308-oled-example ssd1308-oled.cxx) add_executable (ssd1327-oled-example ssd1327-oled.cxx) add_executable (max44000-example max44000.cxx) @@ -270,6 +271,7 @@ target_link_libraries (nrf24l01-receiver-example nrf24l01 ${CMAKE_THREAD_LIBS_IN target_link_libraries (nrf24l01-broadcast-example nrf24l01 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (es08a-example servo ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (hcsr04-example hcsr04 ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (ssd1306-oled-example i2clcd ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (ssd1308-oled-example i2clcd ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (ssd1327-oled-example i2clcd ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (max44000-example max44000 ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/c++/ssd1306-oled.cxx b/examples/c++/ssd1306-oled.cxx new file mode 100644 index 00000000..07421e31 --- /dev/null +++ b/examples/c++/ssd1306-oled.cxx @@ -0,0 +1,149 @@ +/* + * Author Marc Graham + * Copyright (c) 2015 Intel Corporation. + * + * Adapted from ssd1308 library. + * Author: Yevgeniy Kiveish + * Copyright (c) 2014 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 "ssd1306.h" + +#define DEVICE_ADDRESS 0x3C +#define BUS_NUMBER 0x6 + +static uint8_t intel_logo[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 192, 192, 192, 224, + 224, 224, 224, 240, 240, 248, 248, 120, 120, 120, 120, 60, 60, 60, 60, 60, + 62, 30, 30, 30, 30, 30, 30, 30, 31, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 31, 31, 31, 31, 31, + 30, 62, 62, 62, 62, 126, 126, 124, 124, 252, 252, 248, 248, 240, 240, 240, + 224, 224, 224, 192, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, + 128, 0, 56, 56, 28, 30, 14, 15, 15, 7, 7, 7, 7, 3, 3, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 192, 193, 195, 195, + 195, 7, 15, 15, 63, 127, 255, 255, 255, 254, 252, 252, 240, 192, 0, 0, 0, + 0, 0, 0, 0, 0, 128, 192, 192, 240, 248, 124, 124, 60, 0, 0, 0, 0, 159, 159, + 159, 159, 159, 159, 159, 159, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, + 0, 0, 0, 0, 254, 254, 254, 254, 254, 254, 254, 254, 128, 128, 128, 128, + 128, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 192, 192, 192, 192, 192, 192, 128, + 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 0, 0, 0, 3, 7, 3, 3, 3, 0, 0, 0, 0, 0, 1, 1, 255, 255, 255, 255, 255, + 255, 255, 0, 0, 224, 248, 252, 252, 255, 127, 15, 15, 3, 1, 0, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, + 255, 255, 255, 255, 255, 15, 15, 15, 15, 15, 15, 255, 255, 255, 255, 255, + 255, 255, 252, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 15, 15, + 15, 15, 15, 224, 224, 252, 254, 255, 255, 255, 255, 159, 159, 143, 143, + 135, 135, 143, 159, 255, 255, 255, 255, 255, 255, 252, 248, 0, 0, 0, 255, + 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, + 224, 248, 248, 255, 255, 255, 255, 255, 127, 15, 255, 255, 255, 255, 255, + 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, + 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, + 255, 255, 255, 255, 255, 192, 192, 192, 192, 192, 31, 31, 255, 255, 255, + 255, 255, 255, 231, 231, 199, 199, 199, 199, 199, 199, 199, 199, 231, 231, + 231, 231, 199, 135, 0, 0, 0, 63, 255, 255, 255, 255, 255, 255, 255, 0, 0, + 0, 0, 224, 240, 248, 248, 252, 254, 255, 255, 255, 127, 63, 63, 31, 15, 7, + 7, 1, 0, 0, 63, 63, 255, 255, 255, 255, 255, 240, 192, 192, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 3, 3, 7, 7, 7, 7, 7, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 3, 3, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 0, 0, 0, 1, 3, 3, 3, 7, 7, 7, 7, 15, 15, 15, 15, 7, 7, 7, + 7, 7, 3, 3, 3, 1, 0, 0, 0, 0, 1, 3, 3, 7, 135, 135, 135, 192, 192, 0, 0, 7, + 7, 3, 3, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 7, 15, 15, + 31, 127, 127, 127, 255, 255, 252, 252, 252, 248, 240, 240, 240, 224, 224, + 224, 192, 192, 192, 192, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 192, 192, 192, 192, 192, + 224, 224, 224, 224, 240, 240, 240, 240, 248, 248, 248, 248, 252, 252, 252, + 254, 254, 255, 255, 255, 255, 255, 255, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 3, 3, 3, 7, 7, 7, 15, 15, 31, 31, 31, 63, 63, 63, 63, 63, 127, 127, 127, + 127, 127, 255, 255, 255, 255, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 255, 255, 255, 255, 255, 255, 255, 127, 127, 127, 127, 127, 127, 127, 127, + 63, 63, 63, 63, 63, 31, 31, 31, 31, 31, 15, 15, 15, 15, 7, 7, 7, 7, 3, 3, + 3, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }; + +int +main(int argc, char **argv) +{ +//! [Interesting] + upm::SSD1306 *lcd = new upm::SSD1306(BUS_NUMBER, DEVICE_ADDRESS); + + lcd->clear(); + lcd->stopscroll(); + lcd->draw(intel_logo, 1024); + + sleep(3); + + lcd->clear(); + lcd->setCursor(2, 0); + lcd->write("Hello"); + lcd->setCursor(3,0); + lcd->write("World"); + + sleep(3); + + lcd->invert(true); + + sleep(3); + + lcd->dim(true); + + sleep(3); + + lcd->dim(false); + + sleep(3); + + lcd->invert(false); + lcd->startscrollright(0x00, 0x0F); + + sleep(5); + + lcd->stopscroll(); + lcd->startscrollleft(0x00, 0x0F); + + sleep(5); + + lcd->stopscroll(); + lcd->startscrolldiagleft(0x00,0x0F); + + sleep(5); + + lcd->stopscroll(); + lcd->startscrolldiagright(0x00,0x0F); + + sleep(5); + + lcd->stopscroll(); + + delete lcd; +//! [Interesting] + return 0; +} diff --git a/examples/javascript/oled_ssd1306.js b/examples/javascript/oled_ssd1306.js new file mode 100644 index 00000000..b3ceac7f --- /dev/null +++ b/examples/javascript/oled_ssd1306.js @@ -0,0 +1,151 @@ +/* + * Author: Marc Graham + * Copyright (c) 2015 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. + */ + + + +var intel_logo = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 192, 192, 192, 224, +224, 224, 224, 240, 240, 248, 248, 120, 120, 120, 120, 60, 60, 60, 60, 60, +62, 30, 30, 30, 30, 30, 30, 30, 31, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 31, 31, 31, 31, 31, +30, 62, 62, 62, 62, 126, 126, 124, 124, 252, 252, 248, 248, 240, 240, 240, +224, 224, 224, 192, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, +128, 0, 56, 56, 28, 30, 14, 15, 15, 7, 7, 7, 7, 3, 3, 1, 1, 1, 1, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 192, 193, 195, 195, +195, 7, 15, 15, 63, 127, 255, 255, 255, 254, 252, 252, 240, 192, 0, 0, 0, +0, 0, 0, 0, 0, 128, 192, 192, 240, 248, 124, 124, 60, 0, 0, 0, 0, 159, 159, +159, 159, 159, 159, 159, 159, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, +0, 0, 0, 0, 254, 254, 254, 254, 254, 254, 254, 254, 128, 128, 128, 128, +128, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 192, 192, 192, 192, 192, 192, 128, +128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, +0, 0, 0, 0, 3, 7, 3, 3, 3, 0, 0, 0, 0, 0, 1, 1, 255, 255, 255, 255, 255, +255, 255, 0, 0, 224, 248, 252, 252, 255, 127, 15, 15, 3, 1, 0, 0, 0, 0, 0, +0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, +255, 255, 255, 255, 255, 15, 15, 15, 15, 15, 15, 255, 255, 255, 255, 255, +255, 255, 252, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 15, 15, +15, 15, 15, 224, 224, 252, 254, 255, 255, 255, 255, 159, 159, 143, 143, +135, 135, 143, 159, 255, 255, 255, 255, 255, 255, 252, 248, 0, 0, 0, 255, +255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, +224, 248, 248, 255, 255, 255, 255, 255, 127, 15, 255, 255, 255, 255, 255, +255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, +255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, +0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, +255, 255, 255, 255, 255, 192, 192, 192, 192, 192, 31, 31, 255, 255, 255, +255, 255, 255, 231, 231, 199, 199, 199, 199, 199, 199, 199, 199, 231, 231, +231, 231, 199, 135, 0, 0, 0, 63, 255, 255, 255, 255, 255, 255, 255, 0, 0, +0, 0, 224, 240, 248, 248, 252, 254, 255, 255, 255, 127, 63, 63, 31, 15, 7, +7, 1, 0, 0, 63, 63, 255, 255, 255, 255, 255, 240, 192, 192, 128, 0, 0, 0, +0, 0, 0, 0, 0, 1, 3, 3, 7, 7, 7, 7, 7, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, +0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 3, 3, 7, 7, 7, +7, 7, 7, 7, 7, 7, 0, 0, 0, 1, 3, 3, 3, 7, 7, 7, 7, 15, 15, 15, 15, 7, 7, 7, +7, 7, 3, 3, 3, 1, 0, 0, 0, 0, 1, 3, 3, 7, 135, 135, 135, 192, 192, 0, 0, 7, +7, 3, 3, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 7, 15, 15, +31, 127, 127, 127, 255, 255, 252, 252, 252, 248, 240, 240, 240, 224, 224, +224, 192, 192, 192, 192, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 192, 192, 192, 192, 192, +224, 224, 224, 224, 240, 240, 240, 240, 248, 248, 248, 248, 252, 252, 252, +254, 254, 255, 255, 255, 255, 255, 255, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, +3, 3, 3, 7, 7, 7, 15, 15, 31, 31, 31, 63, 63, 63, 63, 63, 127, 127, 127, +127, 127, 255, 255, 255, 255, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +255, 255, 255, 255, 255, 255, 255, 127, 127, 127, 127, 127, 127, 127, 127, +63, 63, 63, 63, 63, 31, 31, 31, 31, 31, 15, 15, 15, 15, 7, 7, 7, 7, 3, 3, +3, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0]; + +function exit() +{ + lcd = null; + lcdObj.cleanUp(); + lcdObj = null; + process.exit(0); +} + +// Load i2clcd module +var lcdObj = require('jsupm_i2clcd'); +var lcd = new lcdObj.SSD1306(6, 0x3c); +var next = 0; + +lcd.clear(); +lcd.setCursor(2, 0); +lcd.write("Hello"); +lcd.setCursor(3, 0); +lcd.write("World!"); + +setInterval(function(){ + loop(); +}, +3000 ); + +function loop(){ + switch(next) + { + case 0: + lcd.invert(true) + break; + case 1: + lcd.dim(true); + break; + case 2: + lcd.invert(false); + break; + case 3: + lcd.startscrollright(0x00, 0x0F); + break; + case 4: + lcd.startscrollleft(0x00, 0x0F); + break; + case 5: + lcd.startscrolldiagleft(0x00, 0x0F) + break; + case 6: + lcd.startscrolldiagright(0x00, 0x0F) + break; + case 7: + var logo = new lcdObj.uint8Array(intel_logo.length); + for(var x = 0 ; x < intel_logo.length ; x++){ + logo.setitem(x, intel_logo[x]); + } + lcd.stopscroll(); + lcd.clear(); + lcd.draw(logo, 1024); + break; + case 8: + default: + lcd.stopscroll(); + lcd.clear(); + lcd.setCursor(2, 0); + lcd.write("All"); + lcd.setCursor(3, 0); + lcd.write("Done!"); + exit(); + } + next++; +} diff --git a/src/lcd/CMakeLists.txt b/src/lcd/CMakeLists.txt old mode 100644 new mode 100755 index e2ee87e0..c21ea8a9 --- a/src/lcd/CMakeLists.txt +++ b/src/lcd/CMakeLists.txt @@ -1,6 +1,6 @@ set (libname "i2clcd") set (classname "lcd") set (libdescription "upm lcd/oled displays") -set (module_src lcd.cxx lcm1602.cxx jhd1313m1.cxx ssd1308.cxx eboled.cxx ssd1327.cxx sainsmartks.cxx) -set (module_h lcd.h lcm1602.h jhd1313m1.h ssd1308.h eboled.h ssd1327.h ssd.h sainsmartks.h) +set (module_src lcd.cxx lcm1602.cxx jhd1313m1.cxx ssd1308.cxx eboled.cxx ssd1327.cxx sainsmartks.cxx ssd1306.cxx) +set (module_h lcd.h lcm1602.h jhd1313m1.h ssd1308.h eboled.h ssd1327.h ssd.h sainsmartks.h ssd1306.h) upm_module_init() diff --git a/src/lcd/javaupm_i2clcd.i b/src/lcd/javaupm_i2clcd.i index 9ff85405..2daa0c98 100644 --- a/src/lcd/javaupm_i2clcd.i +++ b/src/lcd/javaupm_i2clcd.i @@ -27,6 +27,7 @@ #include "ssd.h" #include "ssd1327.h" #include "ssd1308.h" + #include "ssd1306.h" #include "eboled.h" #include "lcm1602.h" #include "jhd1313m1.h" @@ -37,6 +38,7 @@ %include "ssd.h" %include "ssd1327.h" %include "ssd1308.h" +%include "ssd1306.h" %include "eboled.h" %include "lcm1602.h" %include "jhd1313m1.h" diff --git a/src/lcd/jsupm_i2clcd.i b/src/lcd/jsupm_i2clcd.i old mode 100644 new mode 100755 index 68cc4578..9b53d23b --- a/src/lcd/jsupm_i2clcd.i +++ b/src/lcd/jsupm_i2clcd.i @@ -43,3 +43,8 @@ %{ #include "sainsmartks.h" %} + +%include "ssd1306.h" +%{ + #include "ssd1306.h" +%} diff --git a/src/lcd/pyupm_i2clcd.i b/src/lcd/pyupm_i2clcd.i old mode 100644 new mode 100755 index 76ce65e1..1bcb1ab7 --- a/src/lcd/pyupm_i2clcd.i +++ b/src/lcd/pyupm_i2clcd.i @@ -46,3 +46,8 @@ %{ #include "sainsmartks.h" %} + +%include "ssd1306.h" +%{ + #include "ssd1306.h" +%} diff --git a/src/lcd/ssd1306.cxx b/src/lcd/ssd1306.cxx new file mode 100644 index 00000000..90d67d39 --- /dev/null +++ b/src/lcd/ssd1306.cxx @@ -0,0 +1,320 @@ +/* + * Author: Marc Graham + * Copyright (c) 2015 Intel Corporation + * + * Adapted from ssd1308 library. + * Author: Yevgeniy Kiveisha + * Copyright (c) 2014 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 "hd44780_bits.h" +#include "ssd1306.h" + +using namespace upm; + +SSD1306::SSD1306(int bus_in, int addr_in) : m_i2c_lcd_control(bus_in) +{ + int vccstate = SSD1306_SWITCHCAPVCC; + _vccstate = vccstate; + + int LCD_CMD = 0x00; + + m_lcd_control_address = addr_in; + m_name = "SSD1306"; + + mraa_result_t error = m_i2c_lcd_control.address(m_lcd_control_address); + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + + if (error != mraa_SUCCESS) { + fprintf(stderr, "Failed to initialize i2c bus\n"); + return; + } + + m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_OFF); // display off + usleep(4500); + //ADD 1306 stuff + // Init sequence for 128x64 OLED module // 0xAE + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 + m_i2c_lcd_control.writeReg(LCD_CMD, 0x80); // the suggested ratio 0x80 + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETMULTIPLEX); // 0xA8 + m_i2c_lcd_control.writeReg(LCD_CMD, 0x3F); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETDISPLAYOFFSET); // 0xD3 + m_i2c_lcd_control.writeReg(LCD_CMD, 0x0); // no offset + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETSTARTLINE | 0x0); // line #0 + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_CHARGEPUMP); // 0x8D + if (vccstate == SSD1306_EXTERNALVCC) { + m_i2c_lcd_control.writeReg(LCD_CMD, 0x10); + } else { + m_i2c_lcd_control.writeReg(LCD_CMD,0x14); + } + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_MEMORYMODE); // 0x20 + m_i2c_lcd_control.writeReg(LCD_CMD, 0x00); // 0x0 act like ks0108 + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SEGREMAP | 0x1); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_COMSCANDEC); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETCOMPINS); // 0xDA + m_i2c_lcd_control.writeReg(LCD_CMD, 0x12); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETCONTRAST); // 0x81 + if (vccstate == SSD1306_EXTERNALVCC) { + m_i2c_lcd_control.writeReg(LCD_CMD, 0x9F); + } else { + m_i2c_lcd_control.writeReg(LCD_CMD, 0xCF); + } + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETPRECHARGE); // 0xd9 + if (vccstate == SSD1306_EXTERNALVCC) { + m_i2c_lcd_control.writeReg(LCD_CMD, 0x22); + } else { + m_i2c_lcd_control.writeReg(LCD_CMD,0xF1); + } + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SETVCOMDETECT); // 0xDB + m_i2c_lcd_control.writeReg(LCD_CMD, 0x40); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_DISPLAYALLON_RESUME); // 0xA4 + m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_SET_NORMAL_1306); // 0xA6 + + //END 1306 Stuff + m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_ON); // display on + usleep(4500); + setNormalDisplay(); // set to normal display '1' is ON + + clear(); + setAddressingMode(PAGE); +} + +SSD1306::~SSD1306() +{ +} + +mraa_result_t +SSD1306::draw(uint8_t* data, int bytes) +{ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + mraa_result_t error = mraa_SUCCESS; + + setAddressingMode(HORIZONTAL); + for (int idx = 0; idx < bytes; idx++) { + m_i2c_lcd_control.writeReg(LCD_DATA, data[idx]); + } + + return error; +} + +/* + * ************** + * virtual area + * ************** + */ +mraa_result_t +SSD1306::write(std::string msg) +{ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + mraa_result_t error = mraa_SUCCESS; + + setAddressingMode(PAGE); + for (std::string::size_type i = 0; i < msg.size(); ++i) { + writeChar(msg[i]); + } + + return error; +} + +mraa_result_t +SSD1306::setCursor(int row, int column) +{ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + mraa_result_t error = mraa_SUCCESS; + + error = m_i2c_lcd_control.writeReg(LCD_CMD, BASE_PAGE_START_ADDR + row); // set page address + error = m_i2c_lcd_control.writeReg(LCD_CMD, + BASE_LOW_COLUMN_ADDR + (8 * column & 0x0F)); // set column + // lower address + error = m_i2c_lcd_control.writeReg(LCD_CMD, + BASE_HIGH_COLUMN_ADDR + + ((8 * column >> 4) & 0x0F)); // set column higher address + + return error; +} + +mraa_result_t +SSD1306::clear() +{ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + mraa_result_t error = mraa_SUCCESS; + uint8_t columnIdx, rowIdx; + + m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_OFF); // display off + for (rowIdx = 0; rowIdx < 8; rowIdx++) { + setCursor(rowIdx, 0); + + // clear all columns + for (columnIdx = 0; columnIdx < 16; columnIdx++) { + writeChar(' '); + } + } + m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_ON); // display on + home(); + + return error; +} + +mraa_result_t +SSD1306::home() +{ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + return setCursor(0, 0); +} + +/* + * ************** + * private area + * ************** + */ +mraa_result_t +SSD1306::writeChar(uint8_t value) +{ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + mraa_result_t rv; + if (value < 0x20 || value > 0x7F) { + value = 0x20; // space + } + + for (uint8_t idx = 0; idx < 8; idx++) { + rv = m_i2c_lcd_control.writeReg(LCD_DATA, BasicFont[value - 32][idx]); + } + + return rv; +} + +mraa_result_t +SSD1306::setNormalDisplay() +{ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + return m_i2c_lcd_control.writeReg(LCD_CMD, + DISPLAY_CMD_SET_NORMAL_1306); // set to normal display '1' is + // ON +} + +mraa_result_t +SSD1306::setAddressingMode(displayAddressingMode mode) +{ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + mraa_result_t rv; + rv =m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_MEM_ADDR_MODE); // set addressing mode + rv =m_i2c_lcd_control.writeReg(LCD_CMD, mode); // set page addressing mode + return rv; +} + + +mraa_result_t +SSD1306::invert(bool i) +{ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + mraa_result_t rv; + if(i){ + rv = m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_SET_INVERT_1306); + } else { + rv = m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_SET_NORMAL_1306); + } + return rv; +} + + +void SSD1306::startscrollright(uint8_t start, uint8_t stop){ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_RIGHT_HORIZONTAL_SCROLL); + m_i2c_lcd_control.writeReg(LCD_CMD,0X00); + m_i2c_lcd_control.writeReg(LCD_CMD,start); + m_i2c_lcd_control.writeReg(LCD_CMD,0X00); + m_i2c_lcd_control.writeReg(LCD_CMD,stop); + m_i2c_lcd_control.writeReg(LCD_CMD,0X00); + m_i2c_lcd_control.writeReg(LCD_CMD,0XFF); + m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_ACTIVATE_SCROLL); +} + + +void SSD1306::startscrollleft(uint8_t start, uint8_t stop){ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_LEFT_HORIZONTAL_SCROLL); + m_i2c_lcd_control.writeReg(LCD_CMD,0X00); + m_i2c_lcd_control.writeReg(LCD_CMD,start); + m_i2c_lcd_control.writeReg(LCD_CMD,0X00); + m_i2c_lcd_control.writeReg(LCD_CMD,stop); + m_i2c_lcd_control.writeReg(LCD_CMD,0X00); + m_i2c_lcd_control.writeReg(LCD_CMD,0XFF); + m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_ACTIVATE_SCROLL); +} + +void SSD1306::startscrolldiagright(uint8_t start, uint8_t stop){ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SET_VERTICAL_SCROLL_AREA); + m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_LCDHEIGHT); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL); + m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); + m_i2c_lcd_control.writeReg(LCD_CMD, start); + m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); + m_i2c_lcd_control.writeReg(LCD_CMD, stop); + m_i2c_lcd_control.writeReg(LCD_CMD, 0X01); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_ACTIVATE_SCROLL); +} + +void SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop){ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_SET_VERTICAL_SCROLL_AREA); + m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_LCDHEIGHT); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL); + m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); + m_i2c_lcd_control.writeReg(LCD_CMD, start); + m_i2c_lcd_control.writeReg(LCD_CMD, 0X00); + m_i2c_lcd_control.writeReg(LCD_CMD, stop); + m_i2c_lcd_control.writeReg(LCD_CMD, 0X01); + m_i2c_lcd_control.writeReg(LCD_CMD, SSD1306_ACTIVATE_SCROLL); +} + +void SSD1306::stopscroll(void){ + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_DEACTIVATE_SCROLL); +} + +// Dim the display +// dim = true: display is dimmed +// dim = false: display is normal +void SSD1306::dim(bool dim) { + m_i2c_lcd_control.frequency(MRAA_I2C_FAST); + uint8_t contrast; + + if (dim) { + contrast = 0; // Dimmed display + } else { + if (_vccstate == SSD1306_EXTERNALVCC) { + contrast = 0x9F; + } else { + contrast = 0xCF; + } + } + // the range of contrast to too small to be really useful + // it is useful to dim the display + m_i2c_lcd_control.writeReg(LCD_CMD,SSD1306_SETCONTRAST); + m_i2c_lcd_control.writeReg(LCD_CMD,contrast); +} diff --git a/src/lcd/ssd1306.h b/src/lcd/ssd1306.h new file mode 100644 index 00000000..429d4c82 --- /dev/null +++ b/src/lcd/ssd1306.h @@ -0,0 +1,230 @@ +/* + * Author: Marc Graham + * Copyright (c) 2015 Intel Corporation + * + * Adapted from ssd1308 library. + * Author: Yevgeniy Kiveisha + * Copyright (c) 2014 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 "lcd.h" +#include "ssd.h" + +namespace upm +{ +const uint8_t DISPLAY_CMD_SET_NORMAL_1306 = 0xA6; +const uint8_t SSD1306_SETCONTRAST = 0x81; +const uint8_t SSD1306_DISPLAYALLON_RESUME =0xA4; +const uint8_t SSD1306_DISPLAYALLON = 0xA5; +const uint8_t DISPLAY_CMD_SET_INVERT_1306 = 0xA7; + +const uint8_t SSD1306_SETDISPLAYOFFSET =0xD3; +const uint8_t SSD1306_SETCOMPINS = 0xDA; + +const uint8_t SSD1306_SETVCOMDETECT = 0xDB; + +const uint8_t SSD1306_SETDISPLAYCLOCKDIV = 0xD5; +const uint8_t SSD1306_SETPRECHARGE = 0xD9; + +const uint8_t SSD1306_SETMULTIPLEX = 0xA8; + +const uint8_t SSD1306_SETLOWCOLUM = 0x00; +const uint8_t SSD1306_SETHIGHCOLUMN = 0x10; + +const uint8_t SSD1306_SETSTARTLINE = 0x40; + +const uint8_t SSD1306_MEMORYMODE = 0x20; +const uint8_t SSD1306_COLUMNADDR = 0x21; +const uint8_t SSD1306_PAGEADDR = 0x22; + +const uint8_t SSD1306_COMSCANINC = 0xC0; +const uint8_t SSD1306_COMSCANDEC = 0xC8; + +const uint8_t SSD1306_SEGREMAP = 0xA0; + +const uint8_t SSD1306_CHARGEPUMP = 0x8D; + +const uint8_t SSD1306_EXTERNALVCC = 0x1; +const uint8_t SSD1306_SWITCHCAPVCC = 0x2; + +// Scrolling const uint8_t s +const uint8_t SSD1306_ACTIVATE_SCROLL = 0x2F; +const uint8_t SSD1306_DEACTIVATE_SCROLL = 0x2E; +const uint8_t SSD1306_SET_VERTICAL_SCROLL_AREA = 0xA3; +const uint8_t SSD1306_RIGHT_HORIZONTAL_SCROLL = 0x26; +const uint8_t SSD1306_LEFT_HORIZONTAL_SCROLL = 0x27; +const uint8_t SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29; +const uint8_t SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A; + +const uint8_t SSD1306_BLACK = 0; +const uint8_t SSD1306_WHITE = 1; +const uint8_t SSD1306_LCDWIDTH = 128; +const uint8_t SSD1306_LCDHEIGHT = 64; + +/** + * @library i2clcd + * @sensor ssd1306 + * @comname SSD1306 OLED Display + * @altname Adafruit SSD1306 OLED Display 0.96" + * @type display + * @man adafruit + * @web https://www.adafruit.com/datasheets/SSD1306.pdf + * @web http://www.farnell.com/datasheets/609753.pdf + * @con i2c + * + * @brief API for SSD1306 I2C-controlled OLED displays + * + * SSD1306 is a 128x64 dot-matrix OLED/PLED segment driver with a + * controller. This device is available from many suppliers for a + * very low cost. This implementation was tested using a generic + * SSD1306 device from eBay. + * + * @image html ssd1306.jpeg + * @snippet ssd1306-oled.cxx Interesting + */ +class SSD1306 : public LCD +{ + public: + /** + * SSD1306 constructor; calls libmraa initialisation functions + * + * @param bus I2C bus to use + * @param address Slave address the LCD is registered on + */ + SSD1306(int bus, int address = 0x3C); + /** + * SSD1306 destructor + */ + ~SSD1306(); + /** + * Draws an image; see examples/python/make_oled_pic.py for an + * explanation of how pixels are mapped to bytes + * + * @param data Buffer to read + * @param bytes Number of bytes to read from the pointer + * @return Result of the operation + */ + mraa_result_t draw(uint8_t* data, int bytes); + /** + * Writes a string to the LCD + * + * @param msg std::string to write to the display; note: only ASCII + * characters are supported + * @return Result of the operation + */ + mraa_result_t write(std::string msg); + /** + * Sets the cursor to specified coordinates + * + * @param row Row to set the cursor to + * @param column Column to set the cursor to + * @return Result of the operation + */ + mraa_result_t setCursor(int row, int column); + /** + * Clears the display of all characters + * + * @return Result of the operation + */ + mraa_result_t clear(); + /** + * Returns to the original coordinates (0,0) + * + * @return Result of the operation + */ + mraa_result_t home(); + /** + * Inverts the display + * + * @param i true to invert, false for normal display + * @return Result of the operation + */ + mraa_result_t invert(bool i); + /** + * Activate a scroll to the right for rows start through stop + * The display is 16 rows tall. To scroll the whole display, run: + * display.scrollright(0x00, 0x0F) + * + * @param start First row to scroll + * @param stop Last row to scroll + * @return void + */ + void startscrollright(uint8_t start, uint8_t stop); + /** + * Activate a scroll to the left for rows start through stop + * The display is 16 rows tall. To scroll the whole display, run: + * display.startscrollright(0x00, 0x0F) + * + * @param start First row to scroll + * @param stop Last row to scroll + * @return void + */ + void startscrollleft(uint8_t start, uint8_t stop); + /** + * Activate a scroll to the upper right for rows start through stop + * The display is 16 rows tall. To scroll the whole display, run: + * display.startscrollleft(0x00, 0x0F) + * + * @param start First row to scroll + * @param stop Last row to scroll + * @return void + */ + void startscrolldiagright(uint8_t start, uint8_t stop); + /** + * Activate a scroll to the upper left for rows start through stop + * The display is 16 rows tall. To scroll the whole display, run: + * display.startscrolldiaagright(0x00, 0x0F) + * + * @param start First row to scroll + * @param stop Last row to scroll + * @return void + */ + void startscrolldiagleft(uint8_t start, uint8_t stop); + /** + * Stops display scrolling. + * + * @return void + */ + void stopscroll(void); + /** + * Dims display + * + * @param dim True to dim display, false for max intensity + * @return Result of last operation + */ + void dim(bool dim); + + private: + mraa_result_t writeChar(uint8_t value); + mraa_result_t setNormalDisplay(); + mraa_result_t setAddressingMode(displayAddressingMode mode); + + int m_lcd_control_address; + mraa::I2c m_i2c_lcd_control; + + int _vccstate; +}; +}