As a part of one of my projects, I was trying to port the Arduino I2C OLED library to an ARM based platform. I had managed to figure out almost everything, the code seemed correct, the registers were all ported fine, timing wasn’t an issue, and yet there was only one problem : the display wasn’t actually showing anything.
To debug, I did the simplest thing first : tested the display with a standard Arduino Uno and the I2C OLED library. Worked like a charm. So the display was fine. Next up was testing the messages sent by the ARM chip and compare them against the messages sent by an Arduino. For this, I had the following setup.
First, I connected the display and the Arduino on the I2C SDA and SCL lines as usual via a breadboard.Further, I connected the I2C lines from another Arduino to the same SDA SCL lines from the breadboard, to snoop on the connections going on in the wire. I then wrote a small Arduino script to display the snooped messages.
The link to the script is here :I2C Snooping script for Arduino
When I repeated the exercise with the ARM chip, and compared the logs, I found that there were some flags that were being sent that were different. To reduce the chances of error, I dug through the code in the ARM causing the difference and fixed it. Now, the messages sent by both the Arduino and the ARM chip seemed exactly the same. Yet, the display was still just as dead. The issue was probably deeper than the byte level. The signal level then.
Luckily, my friend Mahesh at Electronut had a Saleae Logic Analyser that seemed to be the right tool for the job. I installed Logic from Saleae’s website (install the standalone version on Windows, the installers often don’t work on x64 systems). I then used probes to record the signals from both the Arduino and the ARM chip. Below are images of the capture. I also used the internal functionality to analyse the signals by specifying that they were I2C signals. See the difference ?
ARM chip (not working)
Yep, there is a difference in the signals after two bytes are sent. A little bit of reading quickly revealed that the errant signal was a start bit (see footnote for explanation). I edited the code from the I2C application code in the ARM chip, and sure enough, the display started working.
Why couldn’t the Arduino catch this difference ?
I was using the Arduino I2C library for snooping. The Arduino I2C code I wrote probably ignored the start bit, thinking it was just another packet. Basically, my snooping code did not distinguish between a long packet of data or when it started or ended, because I broke them down too fine, at the byte level, not recording higher packet size level markers.
Moral of the story ?
1. Tools are great friends. Arduino, Logic analysers, even the humble ammeter sometimes. Take the time to learn how to use them. If you can afford them, buy them. They will save you hours, if not days, of wasted effort and time and frustration.
2. Dig deep. Then dig deeper.
I hope this is useful to somebody when debugging. Cheers !
The I2C OLED display requires instructions in a specific format. It is generally in the form of “Address, command” i.e. address of the setting to be changed, followed by the actual setting to be changed.
Now, I2C is a serial communication protocol and specifies how low lying signals are to be generated for reliable communication. The way to distinguish between two data frames is by letting the lines idle for a specified time, then pushing out a start bit. The ARM chip had a method to wait for pending transfers to complete. By calling that method, it assumed that this package transmission was complete, so the next time I called the method to send data, it emitted the Start bit again, as is polite between microcontrollers that are gentlemen and gentlewomen. Since the OLED actually expected a long packet, all I had to do was restructure my command to make sure it didn’t insert unnecessary breaks between packets.