New SPI display SSD1309 for 4LD.

Fixed global I2C usage (no pin allocation in usermods).
Enabled option dor Multi relay.
This commit is contained in:
Blaz Kristan 2023-06-21 23:31:15 +02:00
parent c04c73bbd7
commit cf48ad06ed
10 changed files with 55 additions and 77 deletions

View File

@ -113,8 +113,7 @@ private:
public:
void setup()
{
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; // allocate pins
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) return;
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
sensorFound = lightMeter.begin();
initDone = true;
}
@ -174,7 +173,9 @@ public:
user = root.createNestedObject(F("u"));
JsonArray lux_json = user.createNestedArray(F("Luminance"));
if (!sensorFound) {
if (!enabled) {
lux_json.add(F("disabled"));
} else if (!sensorFound) {
// if no sensor
lux_json.add(F("BH1750 "));
lux_json.add(F("Not Found"));

View File

@ -184,8 +184,7 @@ private:
public:
void setup()
{
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; // allocate pins
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { sensorType=0; return; }
if (i2c_scl<0 || i2c_sda<0) { enabled = false; sensorType = 0; return; }
if (!bme.begin())
{

View File

@ -12,8 +12,7 @@ class RTCUsermod : public Usermod {
public:
void setup() {
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { disabled = true; return; }
if (i2c_scl<0 || i2c_sda<0) { disabled = true; return; }
RTC.begin();
time_t rtcTime = RTC.get();
if (rtcTime) {
@ -25,8 +24,8 @@ class RTCUsermod : public Usermod {
}
void loop() {
if (strip.isUpdating()) return;
if (!disabled && toki.isTick()) {
if (disabled || strip.isUpdating()) return;
if (toki.isTick()) {
time_t t = toki.second();
if (t != RTC.get()) RTC.set(t); //set RTC to NTP/UI-provided value
}

View File

@ -50,8 +50,7 @@ class UsermodVL53L0XGestures : public Usermod {
public:
void setup() {
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
sensor.setTimeout(150);
if (!sensor.init())

View File

@ -85,8 +85,7 @@ class MPU6050Driver : public Usermod {
* setup() is called once at boot. WiFi is not yet connected at this point.
*/
void setup() {
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.setClock(400000U); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE

View File

@ -14,6 +14,9 @@
#ifndef MULTI_RELAY_PINS
#define MULTI_RELAY_PINS -1
#define MULTI_RELAY_ENABLED false
#else
#define MULTI_RELAY_ENABLED true
#endif
#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)
@ -336,7 +339,7 @@ byte MultiRelay::IOexpanderRead(int address) {
MultiRelay::MultiRelay()
: _switchTimerStart(0)
, enabled(false)
, enabled(MULTI_RELAY_ENABLED)
, initDone(false)
, usePcf8574(USE_PCF8574)
, addrPcf8574(PCF8574_ADDRESS)
@ -479,7 +482,7 @@ void MultiRelay::publishHomeAssistantAutodiscovery() {
void MultiRelay::setup() {
// pins retrieved from cfg.json (readFromConfig()) prior to running setup()
// if we want PCF8574 expander I2C pins need to be valid
if (i2c_sda == i2c_scl && i2c_sda == -1) usePcf8574 = false;
if (i2c_sda<0 || i2c_scl<0) usePcf8574 = false;
uint8_t state = 0;
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
@ -765,7 +768,7 @@ bool MultiRelay::readFromConfig(JsonObject &root) {
usePcf8574 = top[FPSTR(_pcf8574)] | usePcf8574;
addrPcf8574 = top[FPSTR(_pcfAddress)] | addrPcf8574;
// if I2C is not globally initialised just ignore
if (i2c_sda == i2c_scl && i2c_sda == -1) usePcf8574 = false;
if (i2c_sda<0 || i2c_scl<0) usePcf8574 = false;
periodicBroadcastSec = top[FPSTR(_broadcast)] | periodicBroadcastSec;
periodicBroadcastSec = min(900,max(0,(int)periodicBroadcastSec));
HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;

View File

@ -16,7 +16,6 @@ class ShtUsermod : public Usermod
private:
bool enabled = false; // Is usermod enabled or not
bool firstRunDone = false; // Remembers if the first config load run had been done
bool pinAllocDone = true; // Remembers if we have allocated pins
bool initDone = false; // Remembers if the mod has been completely initialised
bool haMqttDiscovery = false; // Is MQTT discovery enabled or not
bool haMqttDiscoveryDone = false; // Remembers if we already published the HA discovery topics
@ -94,7 +93,7 @@ void ShtUsermod::initShtTempHumiditySensor()
case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break;
}
shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl);
shtTempHumidSensor->begin(shtI2cAddress); // uses &Wire
if (shtTempHumidSensor->readStatus() == 0xFFFF) {
DEBUG_PRINTF("[%s] SHT init failed!\n", _name);
cleanup();
@ -132,13 +131,6 @@ void ShtUsermod::cleanupShtTempHumiditySensor()
void ShtUsermod::cleanup()
{
cleanupShtTempHumiditySensor();
if (pinAllocDone) {
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
pinManager.deallocateMultiplePins(pins, 2, PinOwner::HW_I2C);
pinAllocDone = false;
}
enabled = false;
}
@ -237,14 +229,12 @@ void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
void ShtUsermod::setup()
{
if (enabled) {
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
// GPIOs can be set to -1 and allocateMultiplePins() will return true, so check they're gt zero
if (i2c_sda < 0 || i2c_scl < 0 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) {
DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name);
// GPIOs can be set to -1 , so check they're gt zero
if (i2c_sda < 0 || i2c_scl < 0) {
DEBUG_PRINTF("[%s] I2C bus not initialised!\n", _name);
cleanup();
return;
}
pinAllocDone = true;
initShtTempHumiditySensor();

View File

@ -82,13 +82,14 @@ void DisplayTaskCode(void * parameter);
typedef enum {
NONE = 0,
SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C
SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C
SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C
SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C
SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI
SSD1306_SPI64 // U8X8_SSD1306_128X64_NONAME_HW_SPI
SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C
SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C
SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C
SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C
SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI
SSD1306_SPI64, // U8X8_SSD1306_128X64_NONAME_HW_SPI
SSD1309_SPI64 // U8X8_SSD1309_128X64_NONAME0_4W_HW_SPI
} DisplayType;
@ -533,24 +534,18 @@ void FourLineDisplayUsermod::sleepOrClock(bool enabled) {
// gets called once at boot. Do all initialization that doesn't depend on
// network here
void FourLineDisplayUsermod::setup() {
if (type == NONE || !enabled) return;
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64 || type == SSD1309_SPI64);
// check if pins are -1 and disable usermod as PinManager::allocateMultiplePins() will accept -1 as a valid pin
if (isSPI) {
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (ioPin[0]==-1 || ioPin[1]==-1 || ioPin[1]==-1) { type=NONE; return; }
if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { type=NONE; return; }
PinManagerPinType pins[2] = { { spi_sclk, true }, { spi_mosi, true } };
if (spi_sclk==-1 || spi_mosi==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_SPI)) {
pinManager.deallocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay);
if (spi_sclk<0 || spi_mosi<0 || ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) {
type = NONE;
return;
} else {
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { type = NONE; }
}
} else {
PinManagerPinType pins[2] = { {i2c_scl, true }, { i2c_sda, true } };
if (i2c_scl==-1 || i2c_sda==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { type=NONE; return; }
if (i2c_scl<0 || i2c_sda<0) { type=NONE; }
}
DEBUG_PRINTLN(F("Allocating display."));
@ -563,20 +558,16 @@ void FourLineDisplayUsermod::setup() {
case SSD1305_64: u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(); break;
// U8X8 uses global SPI variable that is attached to VSPI bus on ESP32
case SSD1306_SPI: u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
case SSD1306_SPI64: u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
case SSD1306_SPI64: u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
case SSD1309_SPI64: u8x8 = (U8X8 *) new U8X8_SSD1309_128X64_NONAME0_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
// catchall
default: u8x8 = (U8X8 *) new U8X8_NULL(); break;
default: u8x8 = (U8X8 *) new U8X8_NULL(); enabled = false; break; // catchall to create U8x8 instance
}
if (nullptr == u8x8) {
DEBUG_PRINTLN(F("Display init failed."));
if (isSPI) {
int8_t pins[] = {spi_sclk, spi_mosi};
pinManager.deallocateMultiplePins((const uint8_t*)pins, 2, PinOwner::HW_SPI);
pinManager.deallocateMultiplePins((const uint8_t*)ioPin, 3, PinOwner::UM_FourLineDisplay);
} else {
int8_t pins[] = {i2c_scl, i2c_sda};
pinManager.deallocateMultiplePins((const uint8_t*)pins, 2, PinOwner::HW_I2C);
}
type = NONE;
return;
@ -1215,6 +1206,7 @@ void FourLineDisplayUsermod::appendConfigData() {
oappend(SET_F("addOption(dd,'SSD1305 128x64',5);"));
oappend(SET_F("addOption(dd,'SSD1306 SPI',6);"));
oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);"));
oappend(SET_F("addOption(dd,'SSD1309 SPI 128x64',8);"));
oappend(SET_F("addInfo('4LineDisplay:type',1,'<br><i class=\"warn\">Change may require reboot</i>','');"));
oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');"));
oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');"));
@ -1306,38 +1298,30 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
bool pinsChanged = false;
for (byte i=0; i<3; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true; break; }
if (pinsChanged || type!=newType) {
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
bool newSPI = (newType == SSD1306_SPI || newType == SSD1306_SPI64);
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64 || type == SSD1309_SPI64);
bool newSPI = (newType == SSD1306_SPI || newType == SSD1306_SPI64 || newType == SSD1309_SPI64);
if (isSPI) {
if (pinsChanged || !newSPI) pinManager.deallocateMultiplePins((const uint8_t*)oldPin, 3, PinOwner::UM_FourLineDisplay);
if (!newSPI) {
// was SPI but is no longer SPI
int8_t oldPins[] = {spi_sclk, spi_mosi};
pinManager.deallocateMultiplePins((const uint8_t*)oldPins, 2, PinOwner::HW_SPI);
PinManagerPinType pins[2] = { {i2c_scl, true }, { i2c_sda, true } };
if (i2c_scl==-1 || i2c_sda==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { newType=NONE; }
if (i2c_scl<0 || i2c_sda<0) { newType=NONE; }
} else {
// still SPI but pins changed
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (ioPin[0]==-1 || ioPin[1]==-1 || ioPin[1]==-1) { newType=NONE; }
if (ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) { newType=NONE; }
else if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
}
} else if (newSPI) {
// was I2C but is now SPI
int8_t oldPins[] = {i2c_scl, i2c_sda};
pinManager.deallocateMultiplePins((const uint8_t*)oldPins, 2, PinOwner::HW_I2C);
PinManagerPinType pins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (ioPin[0]==-1 || ioPin[1]==-1 || ioPin[1]==-1) { newType=NONE; }
else if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
else {
PinManagerPinType pins[2] = { { spi_sclk, true }, { spi_mosi, true } };
if (spi_sclk==-1 || spi_mosi==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_SPI)) {
pinManager.deallocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay);
newType = NONE;
}
if (spi_sclk<0 || spi_mosi<0) {
newType=NONE;
} else {
PinManagerPinType pins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) { newType=NONE; }
else if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
}
} else {
// just I2C tye changed
// just I2C type changed
}
type = newType;
switch (type) {
@ -1369,8 +1353,12 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
u8x8_SetPin_4Wire_HW_SPI(u8x8->getU8x8(), ioPin[0], ioPin[1], ioPin[2]); // Pins are cs, dc, reset
break;
case SSD1309_SPI64:
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1309_128x64_noname0, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
u8x8_SetPin_4Wire_HW_SPI(u8x8->getU8x8(), ioPin[0], ioPin[1], ioPin[2]); // Pins are cs, dc, reset
default:
u8x8_Setup(u8x8->getU8x8(), u8x8_d_null_cb, u8x8_cad_empty, u8x8_byte_empty, u8x8_dummy_cb);
enabled = false;
break;
}
startDisplay();

View File

@ -474,7 +474,7 @@ void RotaryEncoderUIUsermod::setup()
DEBUG_PRINTLN(F("Usermod Rotary Encoder init."));
if (usePcf8574) {
if ((i2c_sda == i2c_scl && i2c_sda == -1) || pinA<0 || pinB<0 || pinC<0) {
if (i2c_sda < 0 || i2c_scl < 0 || pinA < 0 || pinB < 0 || pinC < 0) {
DEBUG_PRINTLN(F("I2C and/or PCF8574 pins unused, disabling."));
enabled = false;
return;

View File

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2306180
#define VERSION 2306210
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG