SOLVED: Recalcitrant 6 pin SPI SSD1306 0.96" OLED - SAMD21 woes

SOLUTION - click to go to the post with the solution

So, the Christmas holidays have allowed me to return to my DIY Arduboy/girl build, based on a SAMD21. In the first iteration, I was attempting to switch to a new LCD display and do some porting of libraries to ARM SAMD21. As progress ground to a halt in August, I thought what better way to carve up the problem than by attaching the original SPI OLED to a SAMD21 dev board and working through the library port first, followed by a switch to the new LCD display later.

So I bought what I thought sounded like the right spec for this - a SPI 12864 OLED based on the SSD1306. It didn’t come with a CS header pin but that wouldn’t matter for testing my library port, right? So this weekend I got out the offending display, plugged it into my “Wemos” Arduino M0 clone and popped the demo code from the Adafruit_SSD1306 and u8glib2 libraries on. No display using HW SPI, but I can get both showing good results using SW SPI. Same issue on Adafruit ItsyBitsy M4. Tried the ArduboyZ fork library “Hello World” example from @MLXXXp and tried to see if I could emulate what he did using the Sparkfun dev board but no joy (noted that the DC/RST pins change for the SAMD architectures). Even tried a page-buffer example from u8glib2 on the Arduino Uno HW SPI with no success.

My oscilloscope shows the SW SPI SCK toggling at 1MHz, so I went into the Adafruit and u8glib2 files and changed the HW clock to 1MHz, and verified this with the oscilloscope. No joy on the display. I can see SPI data coming out of the MOSI/SCK in the SW pins and, as far as I can tell without a full logic analyser setup, the same coming out of the HW SPI MOSI/SCK, using the decoding on my oscilloscope.

Has anyone else tried using this kind of six pin OLED? Anyone else had dramas getting an SSD1306 OLED working of HW SPI on a SAMD21/51? This “logical” approach of splitting the original problem into smaller parts is now sinking my time fast and I will have to put things on hold again in the New Year.

Pin connections:
DC - display library DC pin
RES - display library reset pin
DI - hardware/software MOSI
D0 - hardware/software SCK
VCC - 3.3V
Anyone see anything wrong with the populated/unpopulated parts on the back for SPI?

I’ve ordered a 7 pin version which will take a while to arrive but I’m unsure whether this is a SW or HW problem, as the evidence has been so patchy, from where I’m looking. Hoping that putting it out here will get someone who hasn’t gone “bug blind” to see what I have done wrong or could try next.

1 Like

If it works with software SPI, I think that rules out any problems with the display itself. It sounds like either a wiring or timing problem. Can you use your scope to compare the signals on the pins when it’s working with software SPI and when it doesn’t with hardware SPI?

1 Like

The Hardware mode is configured for mode 0?

One thing I could imagine is is that there could be a spurious SPI clock pulse after powering up or configuring (change of SPI mode) causing transfers to be out of sync.

Normally CS would get you back in sync but this is not an option for your display. So to get back in synch you’d need to reset the display.

I’d say check how the library handles SPI setup and display reset

1 Like

The ArduboyZ library pulls the display reset line low for 10mS after configuring SPI and just before sending the init commands, so a spurious SPI clock pulse before that wouldn’t cause problems.


You can communicate with 1306 over i2c as well, my guess is this is designed for that only?

1 Like

Claims not to be:
but thank you.

I tried to disconnect #CS pin (in red below) from GND and greenwire to it but the flexPCB via was too far back and I couldn’t get the blade in and retain access to tinned pad on the kapton. I also checked the BS mode select pins (in green below) are all connected to ground to ensure 4 wire SPI. So I’m inclined to agree with @MLXXXp that SW is the place to start looking.

Trying a “bare minimum” sketch comparison on the scope now, using just the display.begin() command in loop, every 5 seconds. Digging back into Adafruit and u8glib2 files to slow the clocks down again…

It’s already working with software SPI, so how could it be wired for I2C?

Software SPI top:

Hardware SPI below:

Well the oscilloscope gets the message, but so far sadly nothing on the OLED with HW SPI. The data is the first section of the display.begin() function from the Adafruit example.

And how does that compare to software SPI?

It doesn’t have all the pins broken out. The data pins are the same. Just depends how you initialize the data connection.

Basically the manufacturer handicapped the PCB.

Only CS is missing. It’s only needed if you want to connect more devices to the same SPI interface. I have an OLED module with the same missing CS and have never had a problem with it.

SW and HW SPI were next to each other for comparison in that message. They look reasonably similar zoomed out.

Just had a look a bit closer. (magenta trace is RESET and blue trace is D/C)


And closer still.


No, you have to hard wire the display for either SPI or I2C using the BS0-2 pins. You can’t switch modes in software (unless you have an external means of setting BS1).


Looking on your 1st posted images. I noticed while looking at the 0x00 byte, SDA is low while idle using software (easier to spot at right side of byte transfer) but it’s high with hardware. Can’t clearly see the relation to SCK though.

*idle: time between transferred bytes

What I noticed in your latest image, on software data is set before rising edge of SCK (as it should) and also kept stable on faling edge of SCK. However on hardware the data changes simultatiously with faling edge.
1 Like

@MLXXXp @Mr.Blinky here’s where I think the culprit is - permanently wired CS, just as @Mr.Blinky suggested. The HW SPI is idling the MOSI and SCK lines high. Ordinarily, the deassertion of CS would prevent the transition of SCK to idle HIGH from being read by the slave but here, the SSD1306 is listening to everything. This single bit every now and again could be throwing everything off.
Software SPI - lines idle LOW, so no erroneous clock edges:

Hardware SPI - lines idle HIGH, but idling is being treated as legitimate signalling by the SSD1306:

I will wait until I get my 7 pin OLED with CS pin broken out, rather than wasting any more time on this heinous module. Shame, as I was hoping to make some decent progress with my Ardugirl.

I was just thinking that they may be idling high because of the 10K pullup resistors on the display module. You could try a 1K pull down on SCK

Another thing you could try is configuring the pins as output and set them low before the SPI hardware is initialized
1 Like

Have you checked the hardware SPI data bit order?

on SAM3X it’s fixed and I think I had an issue with the bit order being the wrong way around. I had to flip data in software.

Spam something like 0xF2 and check on the oscilloscope which side the ‘2’ is closer to.

EDIT: Ah nevermind, I read the text but didn’t look at the pictures. Just saw the signal analyser screenshots.

EDIT2: What if you reset the OLED after initializing the hardware SPI and keeping the hardware SPI active so it doesn’t idle high?

1 Like

R.I.P. Me I was wrong :skull: @MLXXXp inherits Arduboy, Inc and all of it’s tax liabilities. May the force be with you.

Aaand we have a winner: @Mr.Blinky :trophy: :1st_place_medal: . Traced the 10k pullups to VREG and D0/D1. Removed them, tried the Adafruit example with success, so moved over to the ArduboyZ “Hello World” again and voila:

This episode has at least one silver lining, which is that I hadn’t realised @MLXXXp’s ArduboyZ had done lots of the bare minimum conversion for SAMD21 which is needed. That will be exceptionally useful when running through Arduboy2 and trying to get a minimal port going.