I2C Transmission Problems

Hi all,

I am trying to use I2C functionality on HiFive1 Rev B. In order to test it, I use Arduino Due and Arduino Uno as slave devices. I configured the boards like this:

  • Arduinos use the slave_receiver template from https://www.arduino.cc/en/Tutorial/MasterWriter. The only difference is the slave address is 0x51. (Wire.begin(0x51);). I used just one Arduino at a time. I DO NOT connect both of them to the I2C bus at the same time.
  • HiFive1 Rev B uses 200 MHz coreclock. PRCI pllcfg register has “0x30581” after the clock setup.
  • SCL of HiFive1 Rev B is connected to SCL of Arduino and SDA of HiFive1 Rev B is connected to SDA of Arduino using 2 jumper cables.

In order to send a single byte (‘d’, decimal 100) from HiFive1 Rev B to Arduino, I follow the following steps on HiFive1 Rev B:

  1. Write 0x80 to I2C CTR register to enable I2C.
  2. Calculate the PRER value as (200 MHz / (5 * 100 kHz)) - 1 = 399. So “143” (PRER & 0xFF) is written to PRERlo and “1” ((PRER & 0xFF00) >> 8) is written to PRERhi.
  3. Enable the bits in iof_en and clear the bits in iof_sel corresponding to pins 12 and 13 to enable SDA and SCL respectively.
  4. Write 0xA2 (0x51 << 1) to I2C TX register.
  5. Write 0x90 (STA | WR) to I2C CR register.
  6. Loop until TIP bit of SR register is cleared. ( while(SR & 0x02); )
  7. Check RxACK bit of SR register.
  8. Write ‘d’ (100) to I2C TX register.
  9. Write 0x10 (WR) to I2C CR register.
  10. Loop until TIP bit of SR register is cleared. ( while(SR & 0x02); )
  11. Check RxACK bit of SR register.
  12. Write 0x40 (STO) to I2C CR register.
  13. Wait approximately 100 ms by just polling RTC.
  14. Loop back to step 4

I realized that sometimes I do not get ACK after the writes to Arduino Due. If I do not stop sending data when I see NACK or if I just repeat the last write if I see NACK the values I read from Arduino Due is mostly garbage. Yes, I read the expected value 100 but I also read bunch of other arbitrary numbers.

I tried to switch to an Arduino Uno. The values I read from Arduino Uno seem stable, however I2C communication just stops between HiFive1 Rev B and Arduino Uno after some arbitrary number of bytes sent. When it stops, I see that HiFive1 Rev B just waits TIP bit to be cleared, but it never gets cleared. Resetting HiFive1 Rev B allows it to continue to communicate with Arduino Uno again until it stops for no apparent reason again.

After this point, I was just wondering if the problem was the Arduino boards I have, so I conducted a similar experiment with them but the transmission between two Arduino boards seem fine. I never get random incorrect values or the transmission never stops.

So at this point I do not have any idea about what I am doing wrong on HiFive1 Rev B. I just wanted to ask if you can see a mistake in my I2C procedure.

Thank you.

Today, I observed that changing the PRER value from 399 to a value higher than ~799 solves the problem that I have with the Arduino Uno. The I2C communication no longer stops randomly. But I still do not think that I calculated the PRER value wrong. It should be 399 for the standard 100 kHz clock. Am I wrong here?

Also I realized that I wrote the steps 1 and 2 reverse in the question. In the actual code, I do the step 2 first then the step 1.

I still have the NACK issue with Arduino Due.