Skip to content

Commit

Permalink
New SPI display SSD1309 for 4LD.
Browse files Browse the repository at this point in the history
Fixed global I2C usage (no pin allocation in usermods).
Enabled option dor Multi relay.
  • Loading branch information
blazoncek committed Jun 21, 2023
1 parent c04c73b commit cf48ad0
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 77 deletions.
7 changes: 4 additions & 3 deletions usermods/BH1750_v2/usermod_bh1750.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ class Usermod_BH1750 : public Usermod
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;
}
Expand Down Expand Up @@ -174,7 +173,9 @@ class Usermod_BH1750 : public Usermod
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"));
Expand Down
3 changes: 1 addition & 2 deletions usermods/BME280_v2/usermod_bme280.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,7 @@ class UsermodBME280 : public Usermod
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())
{
Expand Down
7 changes: 3 additions & 4 deletions usermods/RTC/usermod_rtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
}
Expand Down
3 changes: 1 addition & 2 deletions usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
3 changes: 1 addition & 2 deletions usermods/mpu6050_imu/usermod_mpu6050_imu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions usermods/multi_relay/usermod_multi_relay.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -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;
Expand Down
18 changes: 4 additions & 14 deletions usermods/sht/usermod_sht.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;


Expand Down Expand Up @@ -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."));
Expand All @@ -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;
Expand Down Expand Up @@ -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');"));
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion wled00/wled.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit cf48ad0

Please sign in to comment.