Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for ST7567 LCD I2C display driver #310

Draft
wants to merge 61 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
d349d91
Fix problem of transitions getting faster with each call of setTargetFPS
geeksville Feb 21, 2020
9fdc276
Allow this library to work on other Arduinos (NRF52) besides ESPs
geeksville Apr 15, 2020
6ac546f
Merge remote-tracking branch 'root/master'
geeksville Apr 15, 2020
6a56151
Let users specify -1 for scl/sda to mean 'use current value'
geeksville Apr 23, 2020
0c83c42
fix missing dependency, std::max is defined in algorithm
geeksville Apr 27, 2020
dc278d1
Treat SH1106 controller the same as SSD1306
mrvdb Jun 14, 2020
72cc15c
Merge pull request #1 from mrvdb/ssh1106-support
geeksville Jun 16, 2020
a2f3e97
make sh1106 displays work on NRF52
geeksville Jul 10, 2020
3e5ae1f
Super ugly early version of a ST7567 LCD driver
geeksville Oct 23, 2020
b49120f
add basic contrast support for the LCD
geeksville Oct 24, 2020
26cffc6
fix what appears to be a bug in the configurable distance between UI …
crossan007 Feb 23, 2021
0c2ce75
add more information to the OLEDDisplayUiState about the transition
crossan007 Feb 23, 2021
35d7962
Merge pull request #2 from crossan007/master
geeksville Feb 23, 2021
8452c5a
add frame notification bounceyness
crossan007 Feb 26, 2021
0d82862
tweaks for debugging?
crossan007 Feb 26, 2021
20f3912
use std::vector instead of junky arrays
crossan007 Feb 27, 2021
29a9070
mostly working panel notifications
crossan007 Feb 27, 2021
4e724c4
fix header
crossan007 Feb 27, 2021
641e533
Cleanup the frame notification API so we're not passing ugly pointers
crossan007 Mar 2, 2021
d7f2174
prevent adding a notification to the currently active frame
crossan007 Mar 2, 2021
183c857
Nicely working callback to inform of currently active screen
crossan007 Mar 2, 2021
22c7eef
return -1 in getFirstNotifyingFrame if there are no notifications
crossan007 Mar 2, 2021
a589780
Merge pull request #3 from crossan007/adjust_frame_notifications
geeksville Mar 3, 2021
a17c51a
Merge branch 'master' of https://github.com/ThingPulse/esp8266-oled-s…
mc-hamster Dec 26, 2021
6545196
Merge branch 'ThingPulse-master' into update-from-head
mc-hamster Dec 26, 2021
881f880
Fix typo /Drawen/Drawn/
mc-hamster Dec 26, 2021
e5a09a2
update /Drawn/Drawen/
mc-hamster Dec 26, 2021
0bfaf5c
update Drawen to Drawn
mc-hamster Dec 26, 2021
bc1c277
More drawen to drawn
mc-hamster Dec 26, 2021
03c0015
Merge pull request #5 from meshtastic/update-from-head
mc-hamster Dec 26, 2021
ec1dbfb
Factor actual fontdata out to a cpp file so the font won't get embedd…
caveman99 Jan 21, 2022
c408e77
Merge pull request #6 from caveman99/master
mkinney Jan 24, 2022
b2f1e30
adding library for caveman99
mkinney Jan 24, 2022
da0f7fa
Merge pull request #7 from mkinney/add_lib_for_caveman
mkinney Jan 24, 2022
ad02dfd
Another Tryfix for Github CI
caveman99 Jan 24, 2022
2d32bf3
Update OLEDDisplayUi.h
caveman99 Jan 24, 2022
d90231d
Merge pull request #8 from caveman99/master
mkinney Jan 24, 2022
2d6bd3e
Helper for Autodetect Code
caveman99 Mar 24, 2022
9f92094
Merge branch 'ThingPulse:master' into master
caveman99 Mar 24, 2022
5358064
Merge branch 'ThingPulse:master' into master
mc-hamster Apr 11, 2022
6dccbab
Merge branch 'ThingPulse:master' into master
caveman99 Jan 18, 2023
bedfa09
add support for SH1107 variant on 128x128
caveman99 Jan 18, 2023
da1ede4
shift for auto detect too
caveman99 Jan 18, 2023
b38094e
Test: SH1107 Fix
caveman99 Mar 8, 2023
4cc4caa
fixed name collision for keyword NONE
dizcza Oct 8, 2023
37637e6
Enable selection of I2C wire interface on Pico RP2040 platform.
Mictronics Jan 18, 2024
a4031c8
Typo fixed.
Mictronics Jan 18, 2024
ee628ee
Merge pull request #10 from Mictronics/master
thebentern Jan 18, 2024
1143247
Merge pull request #11 from ThingPulse/master
caveman99 Mar 18, 2024
7304da2
Move SetGeometry to public space
caveman99 Mar 18, 2024
2d30270
Merge pull request #12 from meshtastic/caveman99-smallscreen
caveman99 Mar 18, 2024
1800ad5
Merge branch 'ThingPulse:master' into master
caveman99 Apr 15, 2024
b6ca371
Always break on newline character
thebentern Jun 13, 2024
69ba98f
Merge pull request #13 from meshtastic/newline
thebentern Jun 13, 2024
54b872e
Restore log buffer: revert upstream changes
todd-herbert Jun 17, 2024
7581753
Leave the GitHub runner alone
todd-herbert Jun 17, 2024
dcacac5
Merge pull request #14 from todd-herbert/master
caveman99 Jun 17, 2024
2b40aff
speed up code when autodetected too.
caveman99 Jun 18, 2024
9d393fe
Merge pull request #9 from dizcza/master
jp-bennett Jun 24, 2024
e16cee1
Make the FrameCallback a std::function to make lambdas easier
jp-bennett Jun 24, 2024
3e9fce8
Fix wrong I2C number detection for ESP32C6 target (#16)
alexbegoon Jan 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 1 addition & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/thingpulse/library/ESP8266%20and%20ESP32%20OLED%20driver%20for%20SSD1306%20displays.svg)](https://registry.platformio.org/libraries/thingpulse/ESP8266%20and%20ESP32%20OLED%20driver%20for%20SSD1306%20displays)
[![Build Status](https://github.com/ThingPulse/esp8266-oled-ssd1306/actions/workflows/main.yml/badge.svg)](https://github.com/ThingPulse/esp8266-oled-ssd1306/actions)

This is a driver for SSD1306 and SH1106 128x64, 128x32, 64x48 and 64x32 OLED displays running on the Arduino/ESP8266 & ESP32 and mbed-os platforms.
This is a driver for SSD1306 128x64, 128x32, 64x48 and 64x32 OLED displays running on the Arduino/ESP8266 & ESP32 and mbed-os platforms.
Can be used with either the I2C or SPI version of the display.

This library drives the OLED display included in the [ThingPulse IoT starter kit](https://thingpulse.com/product/esp8266-iot-electronics-starter-kit-weatherstation-planespotter-worldclock/) aka classic kit aka weather station kit.
Expand Down Expand Up @@ -262,27 +262,6 @@ void setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment);
void setFont(const uint8_t* fontData);
```

## Arduino `Print` functionality

Because this class has been "derived" from Arduino's `Print` class, you can use the functions it provides. In plain language, this means that you can use `print`, `println` and `printf` to the display. Internally, a buffer holds the text that was printed to the display previously (that would still fit on the display) and every time you print something, this buffer is put on the screen, using the functions from the previous section.

What that means is that printing using `print` and "manually" putting things on the display are somewhat mutually exclusive: as soon as you print, everything that was on the display already is gone and only what you put there before with `print`, `println` or `printf` remains. Still, using `print` is a very simple way to put something on the display quickly.

One extra function is provided: `cls()`
```cpp
// cls() will clear the display immediately and empty the logBuffer, meaning
// the next print statement will print at the top of the display again.
// cls() should not be confused with clear(), which only clears the internal
// graphics buffer, which can then be shown on the display with display().
void cls();

> _Note that printing to the display, contrary to what you might expect, does not wrap your lines, so everything on a line that doesn't fit on the screen is cut off._
```

 

<hr>

## Ui Library (OLEDDisplayUi)

The Ui Library is used to provide a basic set of user interface elements called `Frames` and `Overlays`. A `Frame` is used to provide
Expand Down
11 changes: 10 additions & 1 deletion examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ void drawCircle(void) {
}

void printBuffer(void) {
// Initialize the log buffer
// allocate memory to store 8 lines of text and 30 chars per line.
display.setLogBuffer(5, 30);

// Some test data
const char* test[] = {
"Hello",
Expand All @@ -185,10 +189,15 @@ void printBuffer(void) {
"scrolling is",
"working"
};
display.clear();

for (uint8_t i = 0; i < 11; i++) {
display.clear();
// Print to the screen
display.println(test[i]);
// Draw it to the internal screen buffer
display.drawLogBuffer(0, 0);
// Display it on the screen
display.display();
delay(500);
}
}
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ESP8266 and ESP32 OLED driver for SSD1306 displays",
"version": "4.5.0",
"version": "4.4.1",
"keywords": "ssd1306, oled, display, i2c",
"description": "I2C display driver for SSD1306 OLED displays connected to ESP8266, ESP32, Mbed-OS",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=ESP8266 and ESP32 OLED driver for SSD1306 displays
version=4.5.0
version=4.4.1
author=ThingPulse, Fabrice Weinberg
maintainer=ThingPulse <info@thingpulse.com>
sentence=I2C display driver for SSD1306 OLED displays connected to ESP8266, ESP32, Mbed-OS
Expand Down
309 changes: 309 additions & 0 deletions src/AutoOLEDWire.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
* Copyright (c) 2018 by Fabrice Weinberg
*
* 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.
*
* ThingPulse invests considerable time and money to develop these open source libraries.
* Please support us by buying our products (and not the clones) from
* https://thingpulse.com
*
*/

#ifndef AutoOLEDWire_h
#define AutoOLEDWire_h

#include "OLEDDisplay.h"
#include <Wire.h>
#include <algorithm>

#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_STM32)
#define _min min
#define _max max
#endif
#if defined(ARDUINO_ARCH_ESP32)
#define I2C_MAX_TRANSFER_BYTE 128 /** ESP32 can Transfer 128 bytes */
#define I2C_OLED_TRANSFER_BYTE 64
#else
#define I2C_MAX_TRANSFER_BYTE 17
#define I2C_OLED_TRANSFER_BYTE 16
#endif

#define SSD1306_DETECTED 1
#define SH1106_DETECTED 2
#define SH1107_DETECTED 3
#define UNKNOWN_DETECTED 0


#define SH1106_SET_PUMP_VOLTAGE 0X30
#define SH1106_SET_PUMP_MODE 0XAD
#define SH1106_PUMP_ON 0X8B
#define SH1106_PUMP_OFF 0X8A
//--------------------------------------

class AutoOLEDWire : public OLEDDisplay {
private:
uint8_t _address;
int _sda;
int _scl;
bool _doI2cAutoInit = false;
TwoWire* _wire = NULL;
int _frequency;
uint8_t _detected;

public:

/**
* Create and initialize the Display using Wire library
*
* Beware for retro-compatibility default values are provided for all parameters see below.
* Please note that if you don't wan't SD1306Wire to initialize and change frequency speed ot need to
* ensure -1 value are specified for all 3 parameters. This can be usefull to control TwoWire with multiple
* device on the same bus.
*
* @param _address I2C Display address
* @param _sda I2C SDA pin number, default to -1 to skip Wire begin call
* @param _scl I2C SCL pin number, default to -1 (only SDA = -1 is considered to skip Wire begin call)
* @param g display geometry dafault to generic GEOMETRY_128_64, see OLEDDISPLAY_GEOMETRY definition for other options
* @param _i2cBus on ESP32 with 2 I2C HW buses, I2C_ONE for 1st Bus, I2C_TWO fot 2nd bus, default I2C_ONE
* @param _frequency for Frequency by default Let's use ~700khz if ESP8266 is in 160Mhz mode, this will be limited to ~400khz if the ESP8266 in 80Mhz mode
*/
AutoOLEDWire(uint8_t _address, int _sda = -1, int _scl = -1, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64, HW_I2C _i2cBus = I2C_ONE, int _frequency = 700000) {
setGeometry(g);

this->_address = _address;
this->_sda = _sda;
this->_scl = _scl;
#if !defined(ARDUINO_ARCH_ESP32) && !defined(ARCH_RP2040)
this->_wire = &Wire;
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
this->_wire = &Wire;
#else
this->_wire = (_i2cBus==I2C_ONE) ? &Wire : &Wire1;
#endif
this->_frequency = _frequency;
}

bool connect() {
#if !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP8266)
_wire->begin();
#else
// On ESP32 arduino, -1 means 'don't change pins', someone else has called begin for us.
if(this->_sda != -1)
_wire->begin(this->_sda, this->_scl);
#endif
// Let's use ~700khz if ESP8266 is in 160Mhz mode
// this will be limited to ~400khz if the ESP8266 in 80Mhz mode.
if(this->_frequency != -1)
_wire->setClock(this->_frequency);
return true;
}

void display(void) {
initI2cIfNeccesary();
int x_offset = 0;
if (this->_detected == SSD1306_DETECTED) {
x_offset = (128 - this->width()) / 2;
}
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
uint8_t minBoundY = UINT8_MAX;
uint8_t maxBoundY = 0;

uint8_t minBoundX = UINT8_MAX;
uint8_t maxBoundX = 0;
uint8_t x, y;

// Calculate the Y bounding box of changes
// and copy buffer[pos] to buffer_back[pos];
if (this->_detected == SSD1306_DETECTED) {
for (y = 0; y < (this->height() / 8); y++) {
for (x = 0; x < this->width(); x++) {
uint16_t pos = x + y * this->width();
if (buffer[pos] != buffer_back[pos]) {
minBoundY = std::min(minBoundY, y);
maxBoundY = std::max(maxBoundY, y);
minBoundX = std::min(minBoundX, x);
maxBoundX = std::max(maxBoundX, x);
}
buffer_back[pos] = buffer[pos];
}
yield();
}
} else {
for (y = 0; y < (displayHeight / 8); y++) {
for (x = 0; x < displayWidth; x++) {
uint16_t pos = x + y * displayWidth;
if (buffer[pos] != buffer_back[pos]) {
minBoundY = std::min(minBoundY, y);
maxBoundY = std::max(maxBoundY, y);
minBoundX = std::min(minBoundX, x);
maxBoundX = std::max(maxBoundX, x);
}
buffer_back[pos] = buffer[pos];
}
yield();
}
}

// If the minBoundY wasn't updated
// we can savely assume that buffer_back[pos] == buffer[pos]
// holdes true for all values of pos

if (minBoundY == UINT8_MAX) return;

uint8_t k = 0;

if (this->_detected == SSD1306_DETECTED) {
sendCommand(COLUMNADDR);
sendCommand(x_offset + minBoundX);
sendCommand(x_offset + maxBoundX);

sendCommand(PAGEADDR);
sendCommand(minBoundY);
sendCommand(maxBoundY);

for (y = minBoundY; y <= maxBoundY; y++) {
for (x = minBoundX; x <= maxBoundX; x++) {
if (k == 0) {
_wire->beginTransmission(_address);
_wire->write(0x40);
}

_wire->write(buffer[x + y * this->width()]);
k++;
if (k == (I2C_MAX_TRANSFER_BYTE - 1)) {
_wire->endTransmission();
k = 0;
}
}
yield();
}
} else {
// Calculate the colum offset
uint8_t minBoundXp2H = (minBoundX + 2) & 0x0F;
uint8_t minBoundXp2L = 0x10 | ((minBoundX + 2) >> 4 );

if (this->_detected == SH1107_DETECTED) {
// we have an SH1107
minBoundXp2H = (minBoundX) & 0x0F;
minBoundXp2L = 0x10 | ((minBoundX) >> 4 );
}

for (y = minBoundY; y <= maxBoundY; y++) {
sendCommand(0xB0 + y);
sendCommand(minBoundXp2H);
sendCommand(minBoundXp2L);
for (x = minBoundX; x <= maxBoundX; x++) {
if (k == 0) {
_wire->beginTransmission(_address);
_wire->write(0x40);
}
_wire->write(buffer[x + y * displayWidth]);
k++;
if (k == I2C_OLED_TRANSFER_BYTE) {
_wire->endTransmission();
k = 0;
}
}
if (k != 0) {
_wire->endTransmission();
k = 0;
}
yield();
}
}

if (k != 0) {
_wire->endTransmission();
}
#else
if (this->_detected == SSD1306_DETECTED) {
sendCommand(COLUMNADDR);
sendCommand(x_offset);
sendCommand(x_offset + (this->width() - 1));

sendCommand(PAGEADDR);
sendCommand(0x0);

for (uint16_t i=0; i < displayBufferSize; i++) {
_wire->beginTransmission(this->_address);
_wire->write(0x40);
for (uint8_t x = 0; x < (I2C_MAX_TRANSFER_BYTE - 1); x++) {
_wire->write(buffer[i]);
i++;
}
i--;
_wire->endTransmission();
}
}else{
uint8_t * p = &buffer[0];
for (uint8_t y=0; y<8; y++) {
sendCommand(0xB0+y);
sendCommand(0x02);
sendCommand(0x10);
for( uint8_t x=0; x<(128/I2C_OLED_TRANSFER_BYTE); x++) {
_wire->beginTransmission(_address);
_wire->write(0x40);
for (uint8_t k = 0; k < I2C_OLED_TRANSFER_BYTE; k++) {
_wire->write(*p++);
}
_wire->endTransmission();
}
}
}
#endif
}

void setI2cAutoInit(bool doI2cAutoInit) {
_doI2cAutoInit = doI2cAutoInit;
}

void setDetected(uint8_t detected) {
_detected = detected;
}

private:
int getBufferOffset(void) {
return 0;
}
inline void sendCommand(uint8_t command) __attribute__((always_inline)){
if (this->_detected == SSD1306_DETECTED) {
initI2cIfNeccesary();
}
_wire->beginTransmission(_address);
_wire->write(0x80);
_wire->write(command);
_wire->endTransmission();
}

void initI2cIfNeccesary() {
if (_doI2cAutoInit) {
#if !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP8266)
_wire->begin();
#else
_wire->begin(this->_sda, this->_scl);
#endif
}
}

};

#endif
Loading