While demonstrating the OLED display in class this week, I messed up the lesson -- twice -- because I forgot a really important detail: timing.
When putting information on the OLED display it's important to take into consideration timing. But that timing is not always important to consider. Where I messed up was in demonstrating the OLED display without refreshing it... just updating the value once and then exiting the program. What happened in that case is that I didn't give the SSD1306 OLED controller sufficient time to fill the screen with information before the Firmata program ended... resulting in a glitched OLED display.
You can see this in the following display, where I have the update-to-update time reduced to really small values (in the millisecond range). The updates are fine.
But, then, when I try to finish the program and apply the stop() method, I don't provide sufficient time for the SSD1306 to finish its work. I gave it 200ms... that's not enough. So a glitch occurs:
The trick is to extend that last delay to between 500 and 1000 ms. Here's the code that shows the failure:
/* Project: Firmata_Demo_OLED_TimingFail
*
* Dependencies (via Maven) :
* JSSC 2.9.4
* Firmata4j 2.3.8
* SLF4J-JCL; 1.7.3
*
* Reference:
* 1. https://www.yorku.ca/professor/drsmith/2022/02/25/easy-java-arduino-with-firmata/
* 2. https://youtu.be/RVUjxVQkkh4?feature=shared
*
* Author: James Andrew Smith. Date: March 6, 2025
* --------------------------------------------------------------- */
package ca.yorku.eecs.eecs1021;
import org.firmata4j.I2CDevice;
import org.firmata4j.I2CListener;
import org.firmata4j.Pin;
import org.firmata4j.firmata.FirmataDevice;
import org.firmata4j.ssd1306.MonochromeCanvas;
import org.firmata4j.ssd1306.SSD1306;
import java.io.IOException;
import java.util.Random;
public class MainClass {
static final String USBPORT = "/dev/cu.usbserial-0001";
static final int POTA0 = 14;
static final int BUTTOND6 = 6;
static final byte OLEDI2Caddress = 0x3C;
static final int BUTTON_DOWN = 1;
static final int BUTTON_UP = 0;
static final int DRAWDELAY_SHORT = 200;
static final int DRAWDELAY_LONG = 800;
static final int DRAWDELAY_REALLY_LONG = 3000;
public static void main(String[] args) throws IOException, InterruptedException {
var myArduino = new FirmataDevice(USBPORT);
myArduino.start();
myArduino.ensureInitializationIsDone();
/* set up the pot and the button */
Pin myPot = myArduino.getPin(POTA0);
Pin myButton = myArduino.getPin(BUTTOND6); myButton.setMode(Pin.Mode.INPUT);
I2CDevice thei2ccomms = myArduino.getI2CDevice((byte)0x3c);
SSD1306 myOled = new SSD1306(thei2ccomms, SSD1306.Size.SSD1306_128_64);
myOled.init(); // initialize the OLED.
myOled.clear(); // blank out the memory for hte controller.
Thread.sleep(DRAWDELAY_SHORT); // Required to clear out the buffer properly.
myOled.getCanvas().setTextsize(1);
myOled.getCanvas().setCursor(0,10);
//myOled.getCanvas().write("Hello");
myOled.display();
Thread.sleep(DRAWDELAY_LONG); // Required to ensure that the text gets placed correctly.
// loop as long as the button is not pressed down.
System.out.println("Printing nine values to the OLED...");
for (int m = 1; m <= 10; m++) {
int fraction_short_delay = (int)( ((float)DRAWDELAY_SHORT) / ((float)m));
System.out.println("Delay value of DRAWDELAY_SHORT divided by " + m + " = " + fraction_short_delay + " ms.");
System.out.println("Printing five times....");
for (int i = 0; i < 5; i++) {
// Create 9 random numbers
int[] randomNumbers = new Random().ints(9, 100, 1000).toArray();
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
myOled.getCanvas().setCursor(j * 50, k * 25);
myOled.getCanvas().write(String.valueOf(randomNumbers[j * 3 + k]));
}
}
// Now that buffer is written, run the display() method & wait
myOled.display();
Thread.sleep(fraction_short_delay);
}
}
// wait before exiting....
Thread.sleep(DRAWDELAY_SHORT); // 200ms : this will glitch out.
//Thread.sleep(DRAWDELAY_REALLY_LONG); // 3000ms : this will result in no glitch
myArduino.stop();
}
}
Now, if I set the last delay from 200 to 3000... or DRAWDELAY_SHORT to DRAWDELAY_REALLY_LONG, then it's okay.

James Andrew Smith is a Professional Engineer and Associate Professor in the Electrical Engineering and Computer Science Department of York University’s Lassonde School, with degrees in Electrical and Mechanical Engineering from the University of Alberta and McGill University. Previously a program director in biomedical engineering, his research background spans robotics, locomotion, human birth, music and engineering education. While on sabbatical in 2018-19 with his wife and kids he lived in Strasbourg, France and he taught at the INSA Strasbourg and Hochschule Karlsruhe and wrote about his personal and professional perspectives. James is a proponent of using social media to advocate for justice, equity, diversity and inclusion as well as evidence-based applications of research in the public sphere. You can find him on Twitter. You can find him on BlueSky. Originally from Québec City, he now lives in Toronto, Canada.