I have a ST7567S 128 x 64 LCD display connected via I2C to an Adafruit Feather M0. After a random amount of time (seconds to minutes), the processor gets stuck in the sendBuffer() routine. Then, if I unplug the module, the controller resumes like nothing had happend. It seems to wait for some response from the display that never comes. This happens also with another display (same type) and another microcontroller (Arduino Nano). After a lot of investigation with the help of the guy who wrote the I2C library (discussion is here: https://github.com/olikraus/u8g2/issues/2182) I found out it is an issue with the I2C bus.
The master transmits lots of data to the slave, everything is fine. But then, a transmitted byte gets pre-maturely acknowledged by the slave with the 8th clock, but it should be with the 9th clock.
Then, there is no more clock cycle and the clock line remains high. The data line is driven low by the display (slave). The levels of data and clock line remain in their last state forever. The problem is, the microcontroller waits forever for a proper acknowledge and no program is executed any more.
So here is my in-depth-analysis of everything:
Scope Setup:
- Ch1: SDA, 0.5V/div, offset 0 div
- Ch2: SCL, 1V/div, offset -3 div
Complete transmission, time scale 50µs/div:
Address, command, then 20 successful data bytes, then one more which is acknowledged prematurely. Clock stops and data line remains low.
Acknowlege level from the display is 0.6V, low level from the microcontroller is 0.0V.
Detail: Start of transmission, time scale 5µs/div:
- First byte: 01111110:
- address = 0x3F
- RW = 0
- Second byte: 01000000:
- Co = 0 → Last control byte. Only a stream of data bytes is allowed to follow. This stream may only be terminated by a STOP or RE-START condition.
- A0 = 1 → display data bytes will be stored
- Third byte and following are data bytes.
Detail: Last, unsuccessful byte, time scale 2µs/div:
Transmitted byte gets pre-maturely acknowledged with the 8th clock, but it should be with the 9th clock.
Then, there is no more clock cycle and the clock line remains high. The data line is driven low by the display (slave). The levels of data and clock line remain in their last state forever:
So I am wondering why this is happening? And what can I do to stop this problem from happening.
EDIT: Most posts hint at the less-than-optimal waveforms. An analysis of the board attached to the LCD revealed a lot of protection curcuitry that gets in the way: There is 470 Ohm series resistor, which I already replaced with a 100 Ohm. Both I replaced with a direct jumper wire. Additionally, there is a Zener to ground (hence the series resistor), clamping voltage levels at 2.2V. This I also removed. The 3.3V-LDO I already shorted for the above measurements. Here is my reverse-engineered circuit diagram, modifications are in green:
The LCD is this one on Aliexpress. The display's controller datasheet is on buydisplay.com
With those modifications it seems to work! It's running now for an hour. Thank you everybody for your valuable hints!