From 2749d67de6eddc132066b494350a36e3595bfa8c Mon Sep 17 00:00:00 2001 From: Max-Plastix Date: Sat, 29 Jan 2022 23:46:48 -0800 Subject: [PATCH] Autodetect SSD1306 vs SH1106 OLED type --- main/configuration.h | 5 --- main/main.cpp | 20 +++++---- main/screen.cpp | 78 ++++++++++++++++++++++++++++++++-- main/screen.h | 2 +- tbeam-workspace.code-workspace | 3 +- 5 files changed, 89 insertions(+), 19 deletions(-) diff --git a/main/configuration.h b/main/configuration.h index b52b3e0..7329a94 100644 --- a/main/configuration.h +++ b/main/configuration.h @@ -169,11 +169,6 @@ along with this program. If not, see . #endif #define RED_LED 4 // GPIO4 on T-Beam v1.1 -// ----------------------------------------------------------------------------- -// OLED -// ----------------------------------------------------------------------------- - -#define SSD1306_ADDRESS 0x3C // ----------------------------------------------------------------------------- // GPS diff --git a/main/main.cpp b/main/main.cpp index 3b73533..387c634 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -99,8 +99,9 @@ float min_dist_moved = MIN_DIST; AXP20X_Class axp; bool pmu_irq = false; // true when PMU IRQ pending -bool ssd1306_found = false; +bool oled_found = false; bool axp192_found = false; +uint8_t oled_addr = 0; // i2c address of OLED controller bool packetQueued; bool isJoined = false; @@ -498,7 +499,7 @@ void lora_msg_callback(uint8_t message) { void scanI2Cdevice(void) { byte err, addr; int nDevices = 0; - for (addr = 1; addr < 127; addr++) { + for (addr = 1; addr < 0x7F; addr++) { Wire.beginTransmission(addr); err = Wire.endTransmission(); if (err == 0) { @@ -511,9 +512,10 @@ void scanI2Cdevice(void) { #endif nDevices++; - if (addr == SSD1306_ADDRESS) { - ssd1306_found = true; - Serial.println("SSD1306 OLED display"); + if (addr == 0x3C || addr == 0x78 || addr == 0x7E) { + oled_addr = addr; + oled_found = true; + Serial.printf("OLED at %02X\n", oled_addr); } if (addr == AXP192_SLAVE_ADDRESS) { axp192_found = true; @@ -720,11 +722,11 @@ void setup() { // Don't init display if we don't have one or we are waking headless due to a // timer event if (0 && wakeCause == ESP_SLEEP_WAKEUP_TIMER) - ssd1306_found = false; // forget we even have the hardware + oled_found = false; // forget we even have the hardware // This creates the display object, so if we don't call it.. all screen ops are do-nothing. - if (ssd1306_found) - screen_setup(); + if (oled_found) + screen_setup(oled_addr); is_screen_on = true; // GPS power on, so it has time to setttle. @@ -794,7 +796,7 @@ void low_power_sleep(uint32_t seconds) { if (axp192_found) { axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS power // axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // OLED power - // if (ssd1306_found) + // if (oled_found) // screen_setup(); } diff --git a/main/screen.cpp b/main/screen.cpp index e221024..99488d9 100644 --- a/main/screen.cpp +++ b/main/screen.cpp @@ -25,6 +25,7 @@ along with this program. If not, see . #include #include "OLEDDisplay.h" +#include "SH1106Wire.h" #include "SSD1306Wire.h" #include "configuration.h" #include "credentials.h" @@ -34,9 +35,12 @@ along with this program. If not, see . #define SCREEN_HEADER_HEIGHT 24 -SSD1306Wire *display; +OLEDDisplay *display; uint8_t _screen_line = SCREEN_HEADER_HEIGHT - 1; +enum display_types { DISPLAY_UNKNOWN, DISPLAY_SSD1306, DISPLAY_SH1106 }; +enum display_types display_type = DISPLAY_UNKNOWN; + void screen_show_logo() { if (!display) return; @@ -99,9 +103,77 @@ void screen_update() { display->display(); } -void screen_setup() { +/* + * The SSD1306 and SH1106 controllers are almost the same, but different. + * Most importantly here, the SH1106 allows reading from the frame buffer, while the SSD1306 does not. + * We exploit this by writing two bytes and reading them back. A mismatch probably means SSD1306. + * Probably. + */ +enum display_types display_get_type(uint8_t id) { + uint8_t err; + uint8_t b1, b2; + + Wire.begin(I2C_SDA, I2C_SCL); + Wire.setClock(7000000); + + Wire.beginTransmission(id); + uint8_t a[] = {0, 0, 0x10, 0xB0}; + Wire.write(a, sizeof(a)); + if ((err = Wire.endTransmission(false)) != 0) { + Serial.printf("err=%d EndTransmission=%d(%s)", err, Wire.lastError(), Wire.getErrorText(Wire.lastError())); + return DISPLAY_UNKNOWN; + } + + Wire.beginTransmission(id); + uint8_t b[] = {0x40, 'M', 'P'}; + Wire.write(b, sizeof(b)); + if ((err = Wire.endTransmission(false)) != 0) { + Serial.printf("err=%d EndTransmission=%d(%s)", err, Wire.lastError(), Wire.getErrorText(Wire.lastError())); + return DISPLAY_UNKNOWN; + } + + Wire.beginTransmission(id); + uint8_t c[] = {0, 0, 0x10}; + Wire.write(c, sizeof(c)); + if ((err = Wire.endTransmission(false)) != 0) { + Serial.printf("err=%d EndTransmission=%d(%s)", err, Wire.lastError(), Wire.getErrorText(Wire.lastError())); + return DISPLAY_UNKNOWN; + } + + Wire.beginTransmission(id); + Wire.write(0x40); + if ((err = Wire.endTransmission(false)) != 0) { + Serial.printf("err=%d EndTransmission=%d(%s)", err, Wire.lastError(), Wire.getErrorText(Wire.lastError())); + return DISPLAY_UNKNOWN; + } + + err = Wire.requestFrom((int)id, (int)3, (int)1); + if (err != 3) { + return DISPLAY_UNKNOWN; + } + Wire.read(); // Discard + b1 = Wire.read(); + b2 = Wire.read(); + Wire.endTransmission(); + + if (b1 == 'M' && b2 == 'P') + return DISPLAY_SH1106; + else + return DISPLAY_SSD1306; +} + +void screen_setup(uint8_t addr) { + /* Attempt to determine which kind of display we're dealing with */ + if (display_type == DISPLAY_UNKNOWN) + display_type = display_get_type(addr); + // Display instance - display = new SSD1306Wire(SSD1306_ADDRESS, I2C_SDA, I2C_SCL); + if (display_type == DISPLAY_SSD1306) + display = new SSD1306Wire(addr, I2C_SDA, I2C_SCL); + else if (display_type == DISPLAY_SH1106) + display = new SH1106Wire(addr, I2C_SDA, I2C_SCL); + else + return; display->init(); display->flipScreenVertically(); display->setFont(Custom_ArialMT_Plain_10); diff --git a/main/screen.h b/main/screen.h index e736478..e5227ae 100644 --- a/main/screen.h +++ b/main/screen.h @@ -16,5 +16,5 @@ void screen_off(void); void screen_on(void); void screen_show_logo(void); -void screen_setup(void); +void screen_setup(uint8_t addr); void screen_end(void); diff --git a/tbeam-workspace.code-workspace b/tbeam-workspace.code-workspace index e978ff9..90f8396 100644 --- a/tbeam-workspace.code-workspace +++ b/tbeam-workspace.code-workspace @@ -13,7 +13,8 @@ "string": "cpp", "unordered_map": "cpp", "unordered_set": "cpp", - "initializer_list": "cpp" + "initializer_list": "cpp", + "*.tcc": "cpp" } } } \ No newline at end of file