I have written an I2C master for the DE10-Nano FPGA which is meant to communicate with the SSD1306 OLED display driver.

The issue I'm having is that it simply is not working when I actually test it on hardware. According to my debug lights the slave (SSD1306) is not sending the ack signal after receiving its address causing the master to go back to the 'idle' state. I know its the correct address (0x3C/0b00111100) because when I use the same address to control this display with an Arduino it works just fine.

I was wondering if anyone who is familiar with I2C could look at my waveforms and check for any glaring mistakes. The DE10-Nano has a 50 MHz clock which is down sampled to 10 KHz for the scl signal. I've also made sure to only change sda when scl is low and made sure I'm meeting all the timing requirements of the I2C spec.

sda goes low:

sda goes low to start transmition

  • scl starts after sda has been low for 5 clock cyles (10 Khz)
  • Ack state where cursor is checks if sda is pulled low (code was edited to pull low for the sim, would normally be set to 'H' so the slave can pull it low its self)

enter image description here

Another thing to note is that I'm supplying the SSD1306 with 3.3 V and the sda and scl pins are 3.3 V. When this display is working on the Arduino the sda and scl pins are 5 V as well as the supply but I know the display is able to operate with a 3.3 V supply.

If anyone wants to see any part of the VHDL I will post it.

  • \$\begingroup\$ Do you have a way to observe the signals between the FPGA and the screen to verify that the pins are well mapped ? \$\endgroup\$
    – BEN
    Commented Jul 28, 2022 at 21:31
  • \$\begingroup\$ @BEN I don't have any such tool. \$\endgroup\$
    – IanRider
    Commented Jul 29, 2022 at 0:19
  • \$\begingroup\$ The start sequence in your second diagram looks wrong, there is a stop condition when PresentState changes from start sequence to transmit address. What do you think? \$\endgroup\$ Commented Jul 29, 2022 at 8:01

1 Answer 1


You are sending the wrong address.

The address is 0x3C in 7-bit notation without R/W bit, which Arduino uses.

The address is 0x78 in 8-bit notation including R/W bit, which you use.

  • \$\begingroup\$ Thanks for the response. This doesn't seem to have fixed the problem as it still reverts back to the idle state instead of going to the transmit data state. But this does clear up the confusion I had about the address that worked for Arduino being different from the address that was listed in the data sheet of the SSD1306. \$\endgroup\$
    – IanRider
    Commented Jul 29, 2022 at 0:23
  • \$\begingroup\$ I'm now thinking about if the SSD1306 is able to drive the sda line low. As soon as it enters the check acknowledge state the code sets the sda line to 'H' or high pull-up which should allow it to be driven low externally. \$\endgroup\$
    – IanRider
    Commented Jul 29, 2022 at 0:24
  • 2
    \$\begingroup\$ @IanRider Are you sure you're setting your SCL output to open-collector, not push-pull? If it's push-pull, the slave device may be unable to pull the line low for the ACK. \$\endgroup\$
    – DoxyLover
    Commented Jul 29, 2022 at 5:09
  • 1
    \$\begingroup\$ @DoxyLover AFAIK the SCL line is not pulled low for ACK, but for clock stretching. The SDA line is pulled low for ACK. \$\endgroup\$ Commented Jul 29, 2022 at 6:53
  • \$\begingroup\$ @busybee you and DoxyLover are talking about different things now. The point was that both SDA and SCL must not be in push-pull but in open-drain mode, and during ACK the master must not pull SDA low so the slave can do it. \$\endgroup\$
    – Justme
    Commented Jul 29, 2022 at 7:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.