1. Make sure to have pull-up resistors on both SDA and SCL. 10kohm at master, 47kohm at the other end of the bus(use STM32 internal GPIO pull-up feature for it if used as most far away slave).
2. SDA and SCL must be open drain (the high level is generated by the pull up, the low level by devices)
3. For single master operation, starts generating I2C using GPIO and bit banging (SW emulated)
4. Before communicating, make sure by SW that both SDA and SCL are high level (idle)
5. If the bus is not idle, generate 9 STOP bits to flush the bus. Slaves don't have reset pin!
==> This happen if reading a slave data byte of 0x00 and the MCU is reset during the transfer... when the MCU restarts, the SDA line is stuck low by the slave...
6. If using text to draw an I2C transaction, use hexa, S = Start, P = Stop, a = acknowledge (the other end force low), n = nack (the other end does not force low). Example: S A0a 50a S A1a 33a 34a 35n P
7. When addressing a slave, beware of the slave address. It's 7 bit, so some people use 7 bit, some use 8 bit shifted format. For EEPROM, typical slave address is A0 (write) and A1 (read). Some say slave address of 50 (7 bits)... go figure.
8. Most slave devices can have multiple slave address so more than one can co-exist on the same bus using pins tied to GND or VDD... so make sure you get the right address.
9. The first function to develop on MCU is to sweep all addresses from 0x01, 0x03, 0x07... so you can sweep all the slaves address and find out how many slaves are responding. A time saver when something is wrong.
10. The fastest I2C bus speed is determined by the slowest slave on the bus
11. Make sure all devices are powered or the communication may be intermittent or failing.
12. A NACK (non acknowledge bit) is a data bit of 1 generated by the device receiving the data)... Some people understood Missing Acknowledge bit... which generates bus errors.
13. Make sure with oscilloscope the quality of SDA and SCL rise, fall edges and skew between them
14. Power aspect: the bus consume power when sending zero data bits.
15. Voltage aspect: it is possible to support 2 supply voltage levels, say 1.8v i2c and 3.3v devices, by adding a transistor on each signal to level shift, at the cost of a limited max speed. Alternative is to use 2 buses, one for each voltage range.
Here an old board which regulate and level shift which was used to test sensors at different voltages... [LevelShifterBridgeV1_1.pdf]
16. If there is a need to connect 8 same slave devices on an i2c bus and the slave can have only 2 sets of slave address through a config pin, use an i2c io expander to control each config pin of all slaves. Case study was a student challenge on how to put an array of pressure sensors on a kite.
17. Avoid generating i2c communication inside an interrupt and the main loop unless looking for a very long debug period, unless you know what you are doing. It is similar risky business as to editing a network file between two users...
18. I2C has a feature named clock stretching, where slaves that need to ask the master to "hold on" can hold the clock low.
==> To avoid the "indefinitely" scenario, a new standard called SMBUS limits this time.
==> When discussing between intelligent devices (between MCUs) then it becomes important to use HW I2C Cell. Same for Slave function. (a slave function using EXTI GPIO Edge interrupt would be limited in bit rate and require high MCU core frequency)
In attachment, a simple pseudo code which helps get SW GPIO I2C bus up and running with little efforts.
In a separate tip and tricks and example of code to manage I2C EEPROMs of any size. I2C EEPROM Example