[Solved] Trouble with multiple SPI displays

I'm having my first try at multiple displays, and it isn't going great. I'm sure this is something I'm doing wrong, obviously, but I can't figure it out.

I have a mix of little .96 128x64 OLEDs, with a mix of interfaces:

  • 2x I2C
  • 2x SPI with 7 pins (one white display, one yellow/blue, if that matters)
  • 1x SPI with 6 pins (no reset)

I'd like to use (any) two for this project.

Unfortunately as far as I understand I can't use both I2C displays without re-soldering a tiny SMD on the back. Correct me if that's wrong.

Before I risk that I figure I could try the SPI. To at least get things to work I am sticking with only the two SPI with 7 pins. Even though the colors in the display are different, I assume they both function the same connection-wise and code-wise?

Regarding multiple SPI devices, I have read two slightly contradictory things:

  1. SPI devices can share all of the pins except each device must have its own CS pin.

...or...

  1. Each device must have its own CS AND Reset pin.

I've tried both of those options.

As you can see in the photo, the CLK (D0), MOSI (D1), and DC pins from the left go to the corresponding pins on the right, then over to the Redboard.

The CS always go to separate pins on the Redboard. In this photo the RST pins also go straight from each display to the Redboard. (But, again, I also tried with both Reset pins going to the same pin on the Redboard.)

Here is my code:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for SSD1306 display connected using software SPI (default case):
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11

#define OLED_CS_left    7
#define OLED_RESET_left 8

#define OLED_CS_right   12
#define OLED_RESET_right 13

Adafruit_SSD1306 display_left(SCREEN_WIDTH, SCREEN_HEIGHT, OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET_left, OLED_CS_left);
Adafruit_SSD1306 display_right(SCREEN_WIDTH, SCREEN_HEIGHT, OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET_right, OLED_CS_right);

void setup() {
  Serial.begin(9600);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display_left.begin(SSD1306_SWITCHCAPVCC)) {
    Serial.println(F("SSD1306 allocation failed: left"));
    for (;;); // Don't proceed, loop forever
  }

  display_left.clearDisplay();
  display_left.setTextColor(WHITE);
  display_left.setCursor(30,20);
  display_left.setTextSize(2);
  display_left.print("LEFT");
  display_left.display();
  
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display_right.begin(SSD1306_SWITCHCAPVCC)) {
    Serial.println(F("SSD1306 allocation failed: right"));
    for (;;); // Don't proceed, loop forever
  }

  display_right.clearDisplay();
  display_right.setTextColor(WHITE);
  display_right.setCursor(30,20);
  display_right.setTextSize(2);
  display_right.print("RIGHT");
  display_right.display();
  
  delay(10000);
}

void loop() {
}

No matter what I try, I can only get the left display to work. The Serial monitor just says "SSD1306 allocation failed: right".

I can switch the actual displays, and still only the left one works, so it's not a faulty display.

I assume I'm missing something obvious, and I apologize about my lack of knowledge regarding this.

Also, I assume I could mix one SPI and one I2C, but I feel like I should learn how this works anyhow, before going with a workaround like that.

Thanks for your help.

Update: I managed to get it to work on a Particle Photon.

I think by using the built-in pins for MOSI (A5) and CLK (A3) (i.e.., hardware SPI?)

I also think I tried that on the Redboard, and I also think that the software SPI as I did it should work, so clearly I'm not understanding something, and I should still learn what that is, even though I can move ahead for now.

My brain is spaghetti at this point, hope it makes sense, and thanks for any pointers on what I'm missing.

Also, I was able to start one as an I2C device and one as SPI, so now I have two "white" screens, but...ha ha ha, they aren't the same color or brightness. :slight_smile:

(I still can't get the display that doesn't even have a Reset pin to work at all.)

Time for a new order of several that are hopefully from the same batch.

Tip #1. Post links to your custom boards e.g. Particle Photon and Redboard. Also your screens.

It appears that Particle Photon has an M3 chip with plenty of SRAM
And the Redboard has a humble ATmega328P with a meagre 2048 bytes.

Adafruit_SSD1306 library allocates 1024 bytes for each screen buffer at run time. The Reboard will never be able to handle two screens.

It should be possible to use 2 screens with Adafruit_SSD1306 on the M3.
It should be possible to use 2 screens with U8g2 on the M3 and on the 328P. (but software is different)

David.

Thanks for the info.

Now that you mention it, in all the posts I read about multiple displays I only recall once talk of allocating 1024 bytes for a screen, so thanks for explaining that. Since it was just one blip in what I was finding - and whoever that was didn't mention it as a problem, per se - it didn't register as a possible issue for me.

In researching my problem I saw many different people using two or more displays successfully, with many different micro controllers. In looking again, with your advice in mind, I do see that very few of the examples are Uno variants. Mostly Megas, Pros, ESP32, etc.

I don't recall any examples saying "HEY, don't do this with an Uno, it can't handle it!" but maybe I overlooked it.

Some are indeed using the U8g library. I don't recall reading anything about "I used this library or that library because of memory allocation" but again, maybe I missed it.

Last thought: it seemed odd to me that if it was trying to allocate more memory than was available for the board that I would get a warning uploading to the Redboard:

Sketch uses 13568 bytes (42%) of program storage space. Maximum is 32256 bytes.
Global variables use 561 bytes (27%) of dynamic memory, leaving 1487 bytes for local variables. Maximum is 2048 bytes.

So now I know about "compile time" vs "run time", thanks again.

No matter how hard I try, I never seem to be able to post a question without being criticized for something. In all the hundreds of forums posts I've read I hardly ever recall seeing somebody post links to the dev boards themselves, especially not with something as common as a Sparkfun Redboard and a Particle Photon. Sorry.

I realize you've already figured it out, but if somebody comes across this question in the future, here are the boards I've referenced:

Sparkfun Redboard:

Particle Photon:
https://docs.particle.io/datasheets/wi-fi/photon-datasheet/

I don't know where I got the various displays. As I mentioned, they are the ubiquitous .96in 128x64 OLEDs.

I'm sure one day I will craft the perfect forum post, complete with properly-formatted code, photos of wiring, links to boards and devices, prove that I tried to solve the problem myself first, links to research done, etc....then be criticized for writing too long of a post or including extraneous details. Or just not get read at all because it's just too long to read.

For my own future reference:

First photo, I2C displays:

  1. Do I understand correctly that the only way I can use these two I2C displays at the same time (no matter which dev board / chip) would be to move the resistor (circled in blue) to the right on one of them? There's no way to change my sketch or the library?

I read that you can have many I2C devices, and the controller knows how to address them, but I think I'm understanding that when people say this, they mean multiple devices of different kinds, which are likely to have different addresses from the factory. My displays - in fact most/all of these displays - have the same address, and it's "hard coded" with that resistor on the back?

  1. Is it possible for me to move that resistor with just a normal soldering iron? (To be complete: Hakko FX-888D with the default tip (flat, fairly narrow blade...not sure of its model number).

...maybe I should try it tomorrow morning before coffee.

Apologies if this next one should be a new thread. If so, let me know and I'll start it instead of continuing in this one.

Second photo, SPI display with no reset pin:

  1. Is there something to be done with these empty pads on the back? (green circle)

  2. Is this thing in the red circle: just sloppy manufacturing? Do I need to fix it?

  3. I can probably google this, but while I'm here: how do I connect this display, since it doesn't have a reset pin? Just put "-1" in the code for that pin?

I bought a few more 128x64 OLED I2C displays and, lacking answers, experimented to find my own.

So, in case somebody finds this thread searching for the same info I was:

  1. As far as I can tell, yes, physically moving the resistor is the only way to change addresses. Every such display that I have seem to have the same two options, so you can move the resistor to have one of two addresses, but without using an I2C multiplier chip, you're limited to two of these I2C OLED displays. Which is fine for me for now.

  2. Yes, it is possible to remove the tiny SMD resistor with a normal soldering iron. Tweezers, a magnifying glass, and patience help.

So I have two I2C displays connected to my Particle Photon. I am having trouble getting things to display reliably on one or the other, but since this thread is about SPI displays I'll start a new one.

Regarding the SPI display with no reset pin questions: still no idea. Can't get it to work. At this point don't care right now though.

You can remove the 0R with a soldering iron. Just put a blob of solder on the tip. Heat the whole 0R via the solder blob. The 0R will leave the pcb.

Subsequent I2C selection can be made with a big solder blob. The original 0R has probably fallen on the floor anyway.

Regarding your 6-pin SPI. D1 looks secure. I would leave it. If you had a hot air gun you could probably re-heat D1 and it would centre itself nicely.

The display should work without the RST pin. It will get a power-on Reset.
I can't read pin#3. Does it say SDI or SDA ?

David.

Thanks for the info!

Regarding the 6-pin SPI:

I can't read pin#3. Does it say SDI or SDA ?

Just to make sure, we're talking about this image?

The pins, from left to right, are labeled:

D/C
CS
MOSI
CLK
GND
VCC

Ah-ha. MOSI means the same thing. The MasterOutSlaveIn is the same as SlaveDataIn.

So just now I have tried the following with that display, all using the Adafruit SSD1306_128x64_spi library example (on the Sparkfun RedBoard):

  1. Software SPI (the default code, straight from the Library example, with the following connections and code. Since there is no reset pin on the display, there is nothing connected to pin 13.
// Declaration for SSD1306 display connected using software SPI (default case):
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
  OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
  1. Software SPI, but I changed the sketch to:
//#define OLED_RESET 13
#define OLED_RESET -1
  1. Hardware SPI...I think:

Display MOSI - RedBoard 11
Display CLK - RedBoard 13
Display CS - RedBoard 7
Display D/C - RedBoard 6

From what I can find online, the Hardware pins are MOSI = 11 and CLK = 13...?

// Comment out above, uncomment this block to use hardware SPI
#define OLED_DC     6
#define OLED_CS     7
#define OLED_RESET  8
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
  &SPI, OLED_DC, OLED_RESET, OLED_CS);
  1. Same as above but changed the OLED_RESET to -1

I really don't need to waste your time on this little $3 display right now. I'm fine just setting it aside and using others. I just thought there might be something fundamental I should understand about this (an SPI display with no reset pin broken out) that I'm not understanding.

If there isn't some larger lesson to be learned here, we can just move on. :slight_smile:

I assume that (1) and (2) both work.

From what I can find online, the Hardware pins are MOSI = 12 and CLK = 13...?

No, they are not. MOSI=11 and CLK=13

Change all the defines to suit your Redboard wiring. Verify with the SW SPI constructor.

Then try the HW SPI constructor.

David.

david_prentice:
I assume that (1) and (2) both work.

No, I can't get any of these to work. So if, as you say, these should work, then I think the display is just bricked.

david_prentice:
No, they are not. MOSI=11 and CLK=13

Change all the defines to suit your Redboard wiring. Verify with the SW SPI constructor.

Then try the HW SPI constructor.

I noticed that I had "12" instead of "11" after I posted, and I very quickly changed to 11 and 13. Hoped I did it before anyone noticed - within a minute or two. You posted 45 minutes after me, by which time I had already long ago fixed my goof. I'm surprised you were able to quote the old text. Anyhow, sorry for the confusion, but 11 and 13 still don't work - nothing shows up on the display using any of those four example sketches.

ballpoint_pen:
I'm having my first try at multiple displays, and it isn't going great. I'm sure this is something I'm doing wrong, obviously, but I can't figure it out.

I have a mix of little .96 128x64 OLEDs, with a mix of interfaces:

  • 2x I2C
  • 2x SPI with 7 pins (one white display, one yellow/blue, if that matters)
  • 1x SPI with 6 pins (no reset)

I'd like to use (any) two for this project.

Unfortunately as far as I understand I can't use both I2C displays without re-soldering a tiny SMD on the back. Correct me if that's wrong.

Before I risk that I figure I could try the SPI. To at least get things to work I am sticking with only the two SPI with 7 pins. Even though the colors in the display are different, I assume they both function the same connection-wise and code-wise?

Regarding multiple SPI devices, I have read two slightly contradictory things:

  1. SPI devices can share all of the pins except each device must have its own CS pin.

...or...

  1. Each device must have its own CS AND Reset pin.

Multiple SPI displays should work. Separate CS pins. Separate RST pins (or RST= -1 in constructor)
Multiple I2C displays should work. Separate Slave address 0x3C, 0x3D.
Multiple SPI and I2C.

Adafruit libraries allocate 1024 bytes SRAM for each 128x64 display. So you need a BIG Arduino.
U8g2 library can use a small "paged" buffer. The coding is different. But you can fit multiple 128x64 on a Uno.

David.

Thank you for all your help with this over the past few days, I appreciate it!

I am having the same problem:

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, OLED1_SDA, OLED1_SCK, OLED1_DC, OLED1_RESET, OLED1_CS);

Adafruit_SSD1306 display2(SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, OLED2_DC, OLED2_RESET, OLED2_CS); // (SCREEN_WIDTH, SCREEN_HEIGHT, OLED2_SDA, OLED2_SCK, OLED2_DC, OLED2_RESET, OLED2_CS);

void setup() {
Serial.begin(9600);

if(!display.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}

if(!display2.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed-2"));
for(;;); // Don't proceed, loop forever
}

// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display.display();

// Clear the buffer
display.clearDisplay();

Display 2 does not initiate... Please, could you help me?