Skip to content

Commit 530e8b3

Browse files
committed
Added SSD1306 SPI display option to 4 Line Display
1 parent 50aeee2 commit 530e8b3

File tree

1 file changed

+112
-48
lines changed

1 file changed

+112
-48
lines changed

usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h

Lines changed: 112 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,43 @@
3131
#ifndef FLD_PIN_SDA
3232
#define FLD_PIN_SDA 21
3333
#endif
34+
#ifndef FLD_PIN_CLOCKSPI
35+
#define FLD_PIN_CLOCKSPI 18
36+
#endif
37+
#ifndef FLD_PIN_DATASPI
38+
#define FLD_PIN_DATASPI 23
39+
#endif
40+
#ifndef FLD_PIN_DC
41+
#define FLD_PIN_DC 19
42+
#endif
43+
#ifndef FLD_PIN_CS
44+
#define FLD_PIN_CS 5
45+
#endif
46+
#ifndef FLD_PIN_RESET
47+
#define FLD_PIN_RESET 26
48+
#endif
3449
#else
3550
#ifndef FLD_PIN_SCL
3651
#define FLD_PIN_SCL 5
3752
#endif
3853
#ifndef FLD_PIN_SDA
3954
#define FLD_PIN_SDA 4
4055
#endif
56+
#ifndef FLD_PIN_CLOCKSPI
57+
#define FLD_PIN_CLOCKSPI 14
58+
#endif
59+
#ifndef FLD_PIN_DATASPI
60+
#define FLD_PIN_DATASPI 13
61+
#endif
62+
#ifndef FLD_PIN_DC
63+
#define FLD_PIN_DC 12
64+
#endif
65+
#ifndef FLD_PIN_CS
66+
#define FLD_PIN_CS 15
67+
#endif
68+
#ifndef FLD_PIN_RESET
69+
#define FLD_PIN_RESET 16
70+
#endif
4171
#endif
4272

4373
// When to time out to the clock or blank the screen
@@ -64,11 +94,13 @@ typedef enum {
6494

6595
typedef enum {
6696
NONE = 0,
67-
SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C
68-
SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C
69-
SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C
70-
SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C
71-
SSD1305_64 // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
97+
SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C
98+
SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C
99+
SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C
100+
SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C
101+
SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
102+
SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI
103+
SSD1306_SPI64 // U8X8_SSD1306_128X64_NONAME_HW_SPI
72104
} DisplayType;
73105

74106
class FourLineDisplayUsermod : public Usermod {
@@ -80,8 +112,13 @@ class FourLineDisplayUsermod : public Usermod {
80112

81113
// HW interface & configuration
82114
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
83-
int8_t sclPin=FLD_PIN_SCL, sdaPin=FLD_PIN_SDA; // I2C pins for interfacing, get initialised in readFromConfig()
115+
#ifndef FLD_SPI_DEFAULT
116+
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
84117
DisplayType type = SSD1306; // display type
118+
#else
119+
int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST
120+
DisplayType type = SSD1306_SPI; // display type
121+
#endif
85122
bool flip = false; // flip display 180°
86123
uint8_t contrast = 10; // screen contrast
87124
uint8_t lineHeight = 1; // 1 row or 2 rows
@@ -131,53 +168,74 @@ class FourLineDisplayUsermod : public Usermod {
131168
// network here
132169
void setup() {
133170
if (type == NONE) return;
134-
if (!pinManager.allocatePin(sclPin)) { sclPin = -1; type = NONE; return;}
135-
if (!pinManager.allocatePin(sdaPin)) { pinManager.deallocatePin(sclPin); sclPin = sdaPin = -1; type = NONE; return; }
171+
bool allocated = false;
172+
byte i;
173+
if (type == SSD1306_SPI || type == SSD1306_SPI64) {
174+
for (i=0; i<5; i++) if (!pinManager.allocatePin(ioPin[i])) { allocated=true; break; }
175+
if (i<5 && allocated) { for (byte i=0; i<5; i++) pinManager.deallocatePin(ioPin[i]); type=NONE; return; }
176+
} else {
177+
for (i=0; i<2; i++) if (!pinManager.allocatePin(ioPin[i])) { allocated=true; break; }
178+
if (i<2 && allocated) { for (byte i=0; i<5; i++) pinManager.deallocatePin(ioPin[i]); type=NONE; return; }
179+
}
136180
DEBUG_PRINTLN(F("Allocating display."));
137181
switch (type) {
138182
case SSD1306:
139183
#ifdef ESP8266
140-
if (!(sclPin==5 && sdaPin==4))
141-
u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(sclPin, sdaPin); // SCL, SDA, reset
184+
if (!(ioPin[0]==5 && ioPin[1]==4))
185+
u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
142186
else
143187
#endif
144-
u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, sclPin, sdaPin); // Pins are Reset, SCL, SDA
188+
u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
145189
lineHeight = 1;
146190
break;
147191
case SH1106:
148192
#ifdef ESP8266
149-
if (!(sclPin==5 && sdaPin==4))
150-
u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(sclPin, sdaPin); // SCL, SDA, reset
193+
if (!(ioPin[0]==5 && ioPin[1]==4))
194+
u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
151195
else
152196
#endif
153-
u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, sclPin, sdaPin); // Pins are Reset, SCL, SDA
197+
u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
154198
lineHeight = 2;
155199
break;
156200
case SSD1306_64:
157201
#ifdef ESP8266
158-
if (!(sclPin==5 && sdaPin==4))
159-
u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(sclPin, sdaPin); // SCL, SDA, reset
202+
if (!(ioPin[0]==5 && ioPin[1]==4))
203+
u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
160204
else
161205
#endif
162-
u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, sclPin, sdaPin); // Pins are Reset, SCL, SDA
206+
u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
163207
lineHeight = 2;
164208
break;
165209
case SSD1305:
166210
#ifdef ESP8266
167-
if (!(sclPin==5 && sdaPin==4))
168-
u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(sclPin, sdaPin); // SCL, SDA, reset
211+
if (!(ioPin[0]==5 && ioPin[1]==4))
212+
u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
169213
else
170214
#endif
171-
u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, sclPin, sdaPin); // Pins are Reset, SCL, SDA
215+
u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
172216
lineHeight = 1;
173217
break;
174218
case SSD1305_64:
175219
#ifdef ESP8266
176-
if (!(sclPin==5 && sdaPin==4))
177-
u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(sclPin, sdaPin); // SCL, SDA, reset
220+
if (!(ioPin[0]==5 && ioPin[1]==4))
221+
u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
178222
else
179223
#endif
180-
u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, sclPin, sdaPin); // Pins are Reset, SCL, SDA
224+
u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
225+
lineHeight = 2;
226+
break;
227+
case SSD1306_SPI:
228+
if (!(ioPin[0]==FLD_PIN_CLOCKSPI && ioPin[1]==FLD_PIN_DATASPI)) // if not overridden these sould be HW accellerated
229+
u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
230+
else
231+
u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
232+
lineHeight = 1;
233+
break;
234+
case SSD1306_SPI64:
235+
if (!(ioPin[0]==FLD_PIN_CLOCKSPI && ioPin[1]==FLD_PIN_DATASPI)) // if not overridden these sould be HW accellerated
236+
u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
237+
else
238+
u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
181239
lineHeight = 2;
182240
break;
183241
default:
@@ -255,6 +313,12 @@ class FourLineDisplayUsermod : public Usermod {
255313
(static_cast<U8X8*>(u8x8))->setPowerSave(save);
256314
}
257315

316+
void center(String &line, uint8_t width) {
317+
int len = line.length();
318+
if (len<width) for (byte i=(width-len)/2; i>0; i--) line = ' ' + line;
319+
for (byte i=line.length(); i<width; i++) line += ' ';
320+
}
321+
258322
/**
259323
* Redraw the screen (but only if things have changed
260324
* or if forceRedraw).
@@ -341,13 +405,14 @@ class FourLineDisplayUsermod : public Usermod {
341405
knownEffectIntensity = effectIntensity;
342406

343407
// Do the actual drawing
344-
408+
String line;
345409
// First row with Wifi name
346410
drawGlyph(0, 0, 80, u8x8_font_open_iconic_embedded_1x1); // home icon
347-
String ssidString = knownSsid.substring(0, getCols() > 1 ? getCols() - 2 : 0);
348-
drawString(1, 0, ssidString.c_str());
411+
line = knownSsid.substring(0, getCols() > 1 ? getCols() - 2 : 0);
412+
center(line, getCols()-2);
413+
drawString(1, 0, line.c_str());
349414
// Print `~` char to indicate that SSID is longer, than our display
350-
if (knownSsid.length() > getCols()) {
415+
if (knownSsid.length() > getCols()-1) {
351416
drawString(getCols() - 1, 0, "~");
352417
}
353418

@@ -358,12 +423,12 @@ class FourLineDisplayUsermod : public Usermod {
358423
drawString(1, lineHeight, apPass);
359424
} else {
360425
// alternate IP address and server name
361-
String secondLine = knownIp.toString();
426+
line = knownIp.toString();
362427
if (showName && strcmp(serverDescription, "WLED") != 0) {
363-
secondLine = serverDescription;
428+
line = serverDescription;
364429
}
365-
for (uint8_t i=secondLine.length(); i<getCols()-1; i++) secondLine += ' ';
366-
drawString(1, lineHeight, secondLine.c_str());
430+
center(line, getCols()-1);
431+
drawString(1, lineHeight, line.c_str());
367432
}
368433

369434
// draw third and fourth row
@@ -605,10 +670,10 @@ class FourLineDisplayUsermod : public Usermod {
605670
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
606671
*/
607672
void addToConfig(JsonObject& root) {
608-
JsonObject top = root.createNestedObject(FPSTR(_name));
609-
JsonArray i2c_pin = top.createNestedArray("pin");
610-
i2c_pin.add(sclPin);
611-
i2c_pin.add(sdaPin);
673+
JsonObject top = root.createNestedObject(FPSTR(_name));
674+
JsonArray io_pin = top.createNestedArray("pin");
675+
for (byte i=0; i<5; i++) io_pin.add(ioPin[i]);
676+
top["help4PinTypes"] = F("Clk,Data,CS,DC,RST"); // help for Settings page
612677
top["type"] = type;
613678
top[FPSTR(_flip)] = (bool) flip;
614679
top[FPSTR(_contrast)] = contrast;
@@ -630,8 +695,7 @@ class FourLineDisplayUsermod : public Usermod {
630695
bool readFromConfig(JsonObject& root) {
631696
bool needsRedraw = false;
632697
DisplayType newType = type;
633-
int8_t newScl = sclPin;
634-
int8_t newSda = sdaPin;
698+
int8_t newPin[5]; for (byte i=0; i<5; i++) newPin[i] = ioPin[i];
635699

636700
JsonObject top = root[FPSTR(_name)];
637701
if (top.isNull()) {
@@ -640,9 +704,8 @@ class FourLineDisplayUsermod : public Usermod {
640704
return false;
641705
}
642706

643-
newScl = top["pin"][0] | newScl;
644-
newSda = top["pin"][1] | newSda;
645707
newType = top["type"] | newType;
708+
for (byte i=0; i<5; i++) newPin[i] = top["pin"][i] | ioPin[i];
646709
flip = top[FPSTR(_flip)] | flip;
647710
contrast = top[FPSTR(_contrast)] | contrast;
648711
refreshRate = (top[FPSTR(_refreshRate)] | refreshRate/1000) * 1000;
@@ -653,20 +716,21 @@ class FourLineDisplayUsermod : public Usermod {
653716
DEBUG_PRINT(FPSTR(_name));
654717
if (!initDone) {
655718
// first run: reading from cfg.json
656-
sclPin = newScl;
657-
sdaPin = newSda;
719+
for (byte i=0; i<5; i++) ioPin[i] = newPin[i];
658720
type = newType;
659721
DEBUG_PRINTLN(F(" config loaded."));
660722
} else {
661723
DEBUG_PRINTLN(F(" config (re)loaded."));
662724
// changing parameters from settings page
663-
if (sclPin!=newScl || sdaPin!=newSda || type!=newType) {
725+
bool pinsChanged = false;
726+
for (byte i=0; i<5; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; }
727+
if (pinsChanged || type!=newType) {
664728
if (type != NONE) delete (static_cast<U8X8*>(u8x8));
665-
pinManager.deallocatePin(sclPin);
666-
pinManager.deallocatePin(sdaPin);
667-
sclPin = newScl;
668-
sdaPin = newSda;
669-
if (newScl<0 || newSda<0) {
729+
for (byte i=0; i<5; i++) {
730+
if (ioPin[i]>=0) pinManager.deallocatePin(ioPin[i]);
731+
ioPin[i] = newPin[i];
732+
}
733+
if (ioPin[0]<0 || ioPin[1]<0) { // data & clock must be > -1
670734
type = NONE;
671735
return true;
672736
} else type = newType;
@@ -678,7 +742,7 @@ class FourLineDisplayUsermod : public Usermod {
678742
if (needsRedraw && !wakeDisplay()) redraw(true);
679743
}
680744
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
681-
return true;
745+
return !(top["pin"][2]).isNull();
682746
}
683747

684748
/*

0 commit comments

Comments
 (0)