From 686c468d3933042635da05e7e2c909666bbde10e Mon Sep 17 00:00:00 2001 From: kotovasia <76496357+kotovasia5120@users.noreply.github.com> Date: Fri, 23 Jan 2026 22:06:09 +0000 Subject: [PATCH] Add SPI support for SSD1306 display and boot status UI Introduces optional SPI support for SSD1306 displays via USE_SPI_SSD1306 (Note: current display implementation shares the same SPI bus as the radio.), including relevant pin and SPI class configuration. Also adds optional on-screen boot status messages in main.cpp for boards with a display, improving user feedback during initialization. --- examples/companion_radio/main.cpp | 51 ++++++++++++++++++++++++++++++- src/helpers/ui/SSD1306Display.cpp | 7 +++++ src/helpers/ui/SSD1306Display.h | 39 +++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 7e636acee..d4f95cecc 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -2,6 +2,16 @@ #include #include "MyMesh.h" +// Optional on-screen boot status for boards with a display. +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) +static void showBootStatus(DisplayDriver* disp, const char* msg) { + if (!disp) return; + disp->startFrame(); + disp->drawTextCentered(disp->width() / 2, 28, msg); + disp->endFrame(); +} +#endif + // Believe it or not, this std C function is busted on some platforms! static uint32_t _atoi(const char* sp) { uint32_t n = 0; @@ -123,11 +133,22 @@ void setup() { } #endif - if (!radio_init()) { halt(); } +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "Radio..."); +#endif + if (!radio_init()) { +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "Radio fail"); +#endif + halt(); + } fast_rng.begin(radio_get_rng_seed()); #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "FS..."); +#endif InternalFS.begin(); #if defined(QSPIFLASH) if (!QSPIFlash.begin()) { @@ -142,6 +163,9 @@ void setup() { #endif #endif store.begin(); +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "Mesh..."); +#endif the_mesh.begin( #ifdef DISPLAY_CLASS disp != NULL @@ -154,11 +178,20 @@ void setup() { serial_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin()); #else serial_interface.begin(Serial); +#endif +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "Iface..."); #endif the_mesh.startInterface(serial_interface); #elif defined(RP2040_PLATFORM) +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "FS..."); +#endif LittleFS.begin(); store.begin(); +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "Mesh..."); +#endif the_mesh.begin( #ifdef DISPLAY_CLASS disp != NULL @@ -181,10 +214,19 @@ void setup() { #else serial_interface.begin(Serial); #endif +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "Iface..."); +#endif the_mesh.startInterface(serial_interface); #elif defined(ESP32) +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "FS..."); +#endif SPIFFS.begin(true); store.begin(); +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "Mesh..."); +#endif the_mesh.begin( #ifdef DISPLAY_CLASS disp != NULL @@ -204,6 +246,9 @@ void setup() { serial_interface.begin(companion_serial); #else serial_interface.begin(Serial); +#endif +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "Iface..."); #endif the_mesh.startInterface(serial_interface); #else @@ -215,6 +260,10 @@ void setup() { #ifdef DISPLAY_CLASS ui_task.begin(disp, &sensors, the_mesh.getNodePrefs()); // still want to pass this in as dependency, as prefs might be moved #endif + +#if defined(DISPLAY_CLASS) && defined(DISPLAY_BOOT_STATUS) + showBootStatus(disp, "Ready"); +#endif } void loop() { diff --git a/src/helpers/ui/SSD1306Display.cpp b/src/helpers/ui/SSD1306Display.cpp index c9da0cf8d..ce7dcde7d 100644 --- a/src/helpers/ui/SSD1306Display.cpp +++ b/src/helpers/ui/SSD1306Display.cpp @@ -1,16 +1,23 @@ #include "SSD1306Display.h" +#ifndef USE_SPI_SSD1306 bool SSD1306Display::i2c_probe(TwoWire& wire, uint8_t addr) { wire.beginTransmission(addr); uint8_t error = wire.endTransmission(); return (error == 0); } +#endif bool SSD1306Display::begin() { #ifdef DISPLAY_ROTATION display.setRotation(DISPLAY_ROTATION); #endif +#ifdef USE_SPI_SSD1306 + DISPLAY_SPI.begin(PIN_OLED_SCK, PIN_OLED_MISO, PIN_OLED_MOSI, PIN_OLED_CS); + return display.begin(SSD1306_SWITCHCAPVCC, 0, true, false); +#else return display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_ADDRESS, true, false) && i2c_probe(Wire, DISPLAY_ADDRESS); +#endif } void SSD1306Display::turnOn() { diff --git a/src/helpers/ui/SSD1306Display.h b/src/helpers/ui/SSD1306Display.h index 1a3a9602b..4accb9f89 100644 --- a/src/helpers/ui/SSD1306Display.h +++ b/src/helpers/ui/SSD1306Display.h @@ -5,11 +5,44 @@ #include #define SSD1306_NO_SPLASH #include +#ifdef USE_SPI_SSD1306 // Note: current display implementation shares the same SPI bus as the radio. + #include + #if defined(DISPLAY_SPI) && (DISPLAY_SPI == 1) + #undef DISPLAY_SPI + #define DISPLAY_SPI spi + #endif + #ifndef DISPLAY_SPI + #define DISPLAY_SPI SPI + #endif + extern SPIClass DISPLAY_SPI; +#endif #ifndef PIN_OLED_RESET #define PIN_OLED_RESET 21 // Reset pin # (or -1 if sharing Arduino reset pin) #endif +#ifdef USE_SPI_SSD1306 + #ifndef PIN_OLED_CS + #define PIN_OLED_CS 5 + #endif + #ifndef PIN_OLED_DC + #define PIN_OLED_DC 4 + #endif + #ifndef PIN_OLED_SCK + #define PIN_OLED_SCK SCK + #endif + #ifndef PIN_OLED_MISO + #ifdef P_LORA_MISO + #define PIN_OLED_MISO P_LORA_MISO + #else + #define PIN_OLED_MISO MISO + #endif + #endif + #ifndef PIN_OLED_MOSI + #define PIN_OLED_MOSI MOSI + #endif +#endif + #ifndef DISPLAY_ADDRESS #define DISPLAY_ADDRESS 0x3C #endif @@ -19,9 +52,15 @@ class SSD1306Display : public DisplayDriver { bool _isOn; uint8_t _color; +#ifndef USE_SPI_SSD1306 bool i2c_probe(TwoWire& wire, uint8_t addr); +#endif public: +#ifdef USE_SPI_SSD1306 + SSD1306Display() : DisplayDriver(128, 64), display(128, 64, &DISPLAY_SPI, PIN_OLED_DC, PIN_OLED_RESET, PIN_OLED_CS) { _isOn = false; } +#else SSD1306Display() : DisplayDriver(128, 64), display(128, 64, &Wire, PIN_OLED_RESET) { _isOn = false; } +#endif bool begin(); bool isOn() override { return _isOn; }