Random garbage ASCII chars on display?

Using Adafruit_SSD1306 and Adafruit_GFX.h library running latest version.

Initially my ssd1306 works fine, but then at a certain point when I add too many global variables, the display starts showing these random garbage pixels in the lower right corner.


As you can see this is 3 images taken a few seconds apart. The rightmost portion of the garbage stays the same, while the leftmost portion changes every time loop() iterates.

(However my loop function has no display related code whatsoever- it literally just checks for button presses, and if there aren't any, it does nothing.)

If I add a few more functions to my sketch, the display will outright fail its allocation.

Obviously it is memory related.

I have already swapped out the display with another ssd1306 from a different source to rule that out.

But I want to know:

Where is this garbage data coming from?
Why is it being updated every loop(), despite nothing happening in loop()?
Why is only the left part changing while the right part stays the same?

I know this is a pretty specific thing, I was hoping someone is familiar with the Adafruit ssd1306 and recognizes this.

Are there pull-up resistors on SCL & SDA ?

Do you think that it would help if you posted your code ?

Nope. Connected directly to the display.

It is definitely not code related. Two reasons- the garbage is changing every time loop() runs, however there is nothing in loop() that alters the display.

Also it only happens in a sweet spot where there is exactly enough memory used up so that something goes wrong, but not enough used to cause the allocation to fail. Literally adding an additional unused global string variable filled with random characters will cause the garbage pixels to occur, and then adding a second String variable will cause a failed allocation.

For example I added these three variables:

If I run the sketch with only eatMemory1 uncommented, it works fine.
If I run it with only eatMemory2 uncommented, it displays the garbage pixels.
If I run it with only the third uncommented, the allocation fails.

I'm 99% sure it is a bug in the Adafruit library code that miscalculates the memory necessary to allocate the display. Which is why it only happens right in that sweet spot before failure.

I wish that I shared your confidence

Which is, of course, controlled by the sketch

So the problem is caused by the sketch after all

Yes of course, but I'm not worried about fixing the problem, but rather why it is happening in such a specific way. The sketch only has display.print() commands in it, so it is not responsible for showing random garbage pixels in the lower right corner, that change every time loop() completes, despite there being no controlling code in loop.

Sorry, I should have worded my question differently. I was hoping someone familiar with the Adafruit libraries or the ssd1306's would recognize this garbage pattern.

I didn't want to burden someone with having to read through a thousand lines of code and/or replicate my circuit with identical hardware to reproduce the error.

Go on. You are well aware of the Adafruit_SSD1306 memory use. It allocates 1024 bytes of SRAM for a 128x64 buffer at runtime.

So your "Works great" sketch with 822 bytes (40%) at compile time turns into 1846 bytes (90%) at runtime.

This leaves only 202 bytes for stack, auto variables, dynamic memory.
Which is probably ok for modest programming with C strings i.e. char arrays.
However you appear to use C++ String which makes things very risky.

The normal advice is to put anonymous data into Flash memory. e.g. oled.println(F("unchangeable message"));
Try to get your compile-time SRAM use below 614 bytes (30%). i.e. runtime < 80%.

Oh, you wanted to know why the garbage is at the bottom right hand corner of the screen. This is where the stack has encroached onto the 128x64 buffer.


Awesome! Thank you. That makes a lot of sense.

So the OLED is getting random bytes overwritten in the end of its buffer, and since the buffer starts at (0,0) for the top left and ends at (128,64) for the lower right, this is why it is happening in the lower right corner only, and not all over the screen?

So I would have assumed that the display.begin() function would return "SSD1306 allocation failed" if there wasn't enough memory. However it seems that is not always the case.

Is this in fact a bug in the library, that is happening because the ssd1306 is failing to allocate enough ram for itself, or is it simply an unwritten rule of arduino that stuff like this will happen when you approach the memory limit, and this is why you are telling me the <80% advice?

(I had assumed that since all of my memory allocation in the sketch is static (no use of malloc), the compiler would have given me the
warning if I was in danger of running out)

Is that really the case ?

Please post your full sketch

Traditionally, Arduino programs allocate global SRAM at compile-time. Hence the memory report is useful. A good rule of thumb is:

Flash <= 100%
SRAM <= 80%

The original Adafruit_SSD1306 constructors did not have width and height arguments. The size of buffer was determined by a #define

This meant that the buffer allocation was known at compile-time. e.g. for 128x32, 128x64, 96x16, ...

The current behaviour is to allocate at run-time. It is assumed that you can judge the SRAM yourself.

But the simple rules are :
anonymous data in Flash.
appropriate variable types and array sizes.
avoid dynamic String