7272#define LINE_BUFFER_SIZE 16 +1
7373#define MAX_JSON_CHARS 19 +1
7474#define MAX_MODE_LINE_SPACE 13 +1
75+ #define MAX_PINS 4
7576
7677
7778#ifdef ARDUINO_ARCH_ESP32
@@ -112,10 +113,10 @@ class FourLineDisplayUsermod : public Usermod {
112113 U8X8 *u8x8 = nullptr ; // pointer to U8X8 display object
113114
114115 #ifndef FLD_SPI_DEFAULT
115- int8_t ioPin[3 ] = {-1 , -1 , -1 }; // I2C pins: SCL, SDA
116+ int8_t ioPin[MAX_PINS ] = {-1 , -1 , -1 , - 1 }; // I2C pins: SCL, SDA, RST, Vext
116117 uint32_t ioFrequency = 400000 ; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
117118 #else
118- int8_t ioPin[3 ] = {FLD_PIN_CS , FLD_PIN_DC , FLD_PIN_RESET }; // custom SPI pins: CS, DC, RST
119+ int8_t ioPin[MAX_PINS ] = {FLD_PIN_CS , FLD_PIN_DC , FLD_PIN_RESET , - 1 }; // custom SPI pins: CS, DC, RST, Vext
119120 uint32_t ioFrequency = 1000000 ; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz)
120121 #endif
121122
@@ -537,25 +538,30 @@ void FourLineDisplayUsermod::setup() {
537538
538539 // check if pins are -1 and disable usermod as PinManager::allocateMultiplePins() will accept -1 as a valid pin
539540 if (isSPI) {
540- if (spi_sclk<0 || spi_mosi<0 || ioPin[0 ]<0 || ioPin[1 ]<0 || ioPin[1 ]<0 ) {
541- type = NONE ;
542- } else {
543- PinManagerPinType cspins[3 ] = { { ioPin[0 ], true }, { ioPin[1 ], true }, { ioPin[2 ], true } };
544- if (!PinManager::allocateMultiplePins (cspins, 3 , PinOwner::UM_FourLineDisplay)) { type = NONE ; }
545- }
541+ if (spi_sclk<0 || spi_mosi<0 || ioPin[0 ]<0 || ioPin[1 ]<0 || ioPin[2 ]<0 ) { type = NONE ; }
546542 } else {
547- if (i2c_scl<0 || i2c_sda<0 ) { type=NONE ; }
543+ if (i2c_scl<0 || i2c_sda<0 ) { type = NONE ; }
544+ }
545+ if (!PinManager::allocateMultiplePins (ioPin, MAX_PINS , PinOwner::UM_FourLineDisplay, true )) { type = NONE ; }
546+
547+ // Pull the Vext power rail enable pin LOW before display init.
548+ // Required on boards like the Heltec WiFi LoRa 32 V3 where the OLED is
549+ // powered via a switchable rail (GPIO36) rather than always-on VCC.
550+ if (ioPin[3 ] >= 0 ) {
551+ pinMode (ioPin[3 ], OUTPUT );
552+ digitalWrite (ioPin[3 ], LOW );
553+ delay (5 );
548554 }
549555
550556 DEBUGUM_PRINTLN (F (" Allocating display." ));
551557 switch (type) {
552558 // U8X8 uses Wire (or Wire1 with 2ND constructor) and will use existing Wire properties (calls Wire.begin() though)
553- case SSD1306 : u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C (); break ;
554- case SH1106 : u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C (); break ;
555- case SSD1306_64 : u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C (); break ;
556- case SSD1305 : u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C (); break ;
557- case SSD1305_64 : u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C (); break ;
558- case SSD1309_64 : u8x8 = (U8X8 *) new U8X8_SSD1309_128X64_NONAME0_HW_I2C (); break ;
559+ case SSD1306 : u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C (ioPin[ 2 ] ); break ;
560+ case SH1106 : u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C (ioPin[ 2 ] ); break ;
561+ case SSD1306_64 : u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C (ioPin[ 2 ] ); break ;
562+ case SSD1305 : u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C (ioPin[ 2 ] ); break ;
563+ case SSD1305_64 : u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C (ioPin[ 2 ] ); break ;
564+ case SSD1309_64 : u8x8 = (U8X8 *) new U8X8_SSD1309_128X64_NONAME0_HW_I2C (ioPin[ 2 ] ); break ;
559565 // U8X8 uses global SPI variable that is attached to VSPI bus on ESP32
560566 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
561567 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
@@ -566,9 +572,7 @@ void FourLineDisplayUsermod::setup() {
566572
567573 if (nullptr == u8x8) {
568574 DEBUGUM_PRINTLN (F (" Display init failed." ));
569- if (isSPI) {
570- PinManager::deallocateMultiplePins ((const uint8_t *)ioPin, 3 , PinOwner::UM_FourLineDisplay);
571- }
575+ PinManager::deallocateMultiplePins ((const uint8_t *)ioPin, 4 , PinOwner::UM_FourLineDisplay);
572576 type = NONE ;
573577 return ;
574578 }
@@ -1214,7 +1218,8 @@ void FourLineDisplayUsermod::appendConfigData() {
12141218 oappend (F (" addInfo('4LineDisplay:type',1,'<br><i class=\" warn\" >Change may require reboot</i>','');" ));
12151219 oappend (F (" addInfo('4LineDisplay:pin[]',0,'','SPI CS');" ));
12161220 oappend (F (" addInfo('4LineDisplay:pin[]',1,'','SPI DC');" ));
1217- oappend (F (" addInfo('4LineDisplay:pin[]',2,'','SPI RST');" ));
1221+ oappend (F (" addInfo('4LineDisplay:pin[]',2,'','SPI/I2C RST');" ));
1222+ oappend (F (" addInfo('4LineDisplay:pin[]',3,'','Vext');" ));
12181223}
12191224
12201225/*
@@ -1237,7 +1242,7 @@ void FourLineDisplayUsermod::addToConfig(JsonObject& root) {
12371242
12381243 top[" type" ] = type;
12391244 JsonArray io_pin = top.createNestedArray (" pin" );
1240- for (int i= 0 ; i< 3 ; i++) io_pin.add (ioPin[i]);
1245+ for (int i = 0 ; i < MAX_PINS ; i++) io_pin.add (ioPin[i]);
12411246 top[FPSTR (_flip)] = (bool ) flip;
12421247 top[FPSTR (_contrast)] = contrast;
12431248 top[FPSTR (_contrastFix)] = (bool ) contrastFix;
@@ -1263,7 +1268,7 @@ void FourLineDisplayUsermod::addToConfig(JsonObject& root) {
12631268bool FourLineDisplayUsermod::readFromConfig (JsonObject& root) {
12641269 bool needsRedraw = false ;
12651270 DisplayType newType = type;
1266- int8_t oldPin[3 ]; for (unsigned i= 0 ; i< 3 ; i++) oldPin[i] = ioPin[i];
1271+ int8_t oldPin[MAX_PINS ]; for (int i = 0 ; i < MAX_PINS ; i++) oldPin[i] = ioPin[i];
12671272
12681273 JsonObject top = root[FPSTR (_name)];
12691274 if (top.isNull ()) {
@@ -1274,7 +1279,7 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
12741279
12751280 enabled = top[FPSTR (_enabled)] | enabled;
12761281 newType = top[" type" ] | newType;
1277- for (unsigned i= 0 ; i< 3 ; i++) ioPin[i] = top[" pin" ][i] | ioPin[i];
1282+ for (int i = 0 ; i < MAX_PINS ; i++) ioPin[i] = top[" pin" ][i] | ioPin[i];
12781283 flip = top[FPSTR (_flip)] | flip;
12791284 contrast = top[FPSTR (_contrast)] | contrast;
12801285 #ifndef ARDUINO_ARCH_ESP32
@@ -1300,58 +1305,55 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
13001305 DEBUGUM_PRINTLN (F (" config (re)loaded." ));
13011306 // changing parameters from settings page
13021307 bool pinsChanged = false ;
1303- for (unsigned i= 0 ; i< 3 ; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true ; break ; }
1308+ for (int i = 0 ; i < MAX_PINS ; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true ; break ; }
13041309 if (pinsChanged || type!=newType) {
13051310 bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64 || type == SSD1309_SPI64 );
13061311 bool newSPI = (newType == SSD1306_SPI || newType == SSD1306_SPI64 || newType == SSD1309_SPI64 );
1312+ if (pinsChanged) PinManager::deallocateMultiplePins ((const uint8_t *)oldPin, MAX_PINS , PinOwner::UM_FourLineDisplay);
13071313 if (isSPI) {
1308- if (pinsChanged || !newSPI) PinManager::deallocateMultiplePins ((const uint8_t *)oldPin, 3 , PinOwner::UM_FourLineDisplay);
13091314 if (!newSPI) {
13101315 // was SPI but is no longer SPI
1311- if (i2c_scl<0 || i2c_sda<0 ) { newType= NONE ; }
1316+ if (i2c_scl<0 || i2c_sda<0 ) { newType = NONE ; }
13121317 } else {
13131318 // still SPI but pins changed
1314- PinManagerPinType cspins[3 ] = { { ioPin[0 ], true }, { ioPin[1 ], true }, { ioPin[2 ], true } };
1315- if (ioPin[0 ]<0 || ioPin[1 ]<0 || ioPin[1 ]<0 ) { newType=NONE ; }
1316- else if (!PinManager::allocateMultiplePins (cspins, 3 , PinOwner::UM_FourLineDisplay)) { newType=NONE ; }
1319+ if (ioPin[0 ]<0 || ioPin[1 ]<0 || ioPin[2 ]<0 ) { newType = NONE ; }
13171320 }
13181321 } else if (newSPI) {
13191322 // was I2C but is now SPI
13201323 if (spi_sclk<0 || spi_mosi<0 ) {
1321- newType= NONE ;
1324+ newType = NONE ;
13221325 } else {
1323- PinManagerPinType pins[3 ] = { { ioPin[0 ], true }, { ioPin[1 ], true }, { ioPin[2 ], true } };
1324- if (ioPin[0 ]<0 || ioPin[1 ]<0 || ioPin[1 ]<0 ) { newType=NONE ; }
1325- else if (!PinManager::allocateMultiplePins (pins, 3 , PinOwner::UM_FourLineDisplay)) { newType=NONE ; }
1326+ if (ioPin[0 ]<0 || ioPin[1 ]<0 || ioPin[2 ]<0 ) { newType = NONE ; }
13261327 }
13271328 } else {
1328- // just I2C type changed
1329+ // just I2C type changed (but may have RST and Vext pins set)
13291330 }
1331+ if (!PinManager::allocateMultiplePins (ioPin, MAX_PINS , PinOwner::UM_FourLineDisplay, true )) { newType = NONE ; }
13301332 type = newType;
13311333 switch (type) {
13321334 case SSD1306 :
13331335 u8x8_Setup (u8x8->getU8x8 (), u8x8_d_ssd1306_128x32_univision, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
1334- u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), U8X8_PIN_NONE , U8X8_PIN_NONE , U8X8_PIN_NONE );
1336+ u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), ioPin[ 2 ] , U8X8_PIN_NONE , U8X8_PIN_NONE );
13351337 break ;
13361338 case SH1106 :
13371339 u8x8_Setup (u8x8->getU8x8 (), u8x8_d_sh1106_128x64_winstar, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
1338- u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), U8X8_PIN_NONE , U8X8_PIN_NONE , U8X8_PIN_NONE );
1340+ u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), ioPin[ 2 ] , U8X8_PIN_NONE , U8X8_PIN_NONE );
13391341 break ;
13401342 case SSD1306_64 :
13411343 u8x8_Setup (u8x8->getU8x8 (), u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
1342- u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), U8X8_PIN_NONE , U8X8_PIN_NONE , U8X8_PIN_NONE );
1344+ u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), ioPin[ 2 ] , U8X8_PIN_NONE , U8X8_PIN_NONE );
13431345 break ;
13441346 case SSD1305 :
13451347 u8x8_Setup (u8x8->getU8x8 (), u8x8_d_ssd1305_128x32_adafruit, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
1346- u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), U8X8_PIN_NONE , U8X8_PIN_NONE , U8X8_PIN_NONE );
1348+ u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), ioPin[ 2 ] , U8X8_PIN_NONE , U8X8_PIN_NONE );
13471349 break ;
13481350 case SSD1305_64 :
13491351 u8x8_Setup (u8x8->getU8x8 (), u8x8_d_ssd1305_128x64_adafruit, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
1350- u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), U8X8_PIN_NONE , U8X8_PIN_NONE , U8X8_PIN_NONE );
1352+ u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), ioPin[ 2 ] , U8X8_PIN_NONE , U8X8_PIN_NONE );
13511353 break ;
13521354 case SSD1309_64 :
13531355 u8x8_Setup (u8x8->getU8x8 (), u8x8_d_ssd1309_128x64_noname0, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
1354- u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), U8X8_PIN_NONE , U8X8_PIN_NONE , U8X8_PIN_NONE );
1356+ u8x8_SetPin_HW_I2C (u8x8->getU8x8 (), ioPin[ 2 ] , U8X8_PIN_NONE , U8X8_PIN_NONE );
13551357 break ;
13561358 case SSD1306_SPI :
13571359 u8x8_Setup (u8x8->getU8x8 (), u8x8_d_ssd1306_128x32_univision, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
0 commit comments