Inter-Integrated Circuit (I2C, pronounced "eye-squared-see" or "eye-two-see") is a serial, one-to-many communication protocol based on the master/slave model. In simple terms, it allows a microcontrollers (uC) to talk to other devices like temperature sensors, displays, or memory chips.
I2C is designed to be simple, low-cost, and good for short distances inside electronic devices. On EVT, we often use I2C buses to connect our microcontrollers to onboard peripherals.
As a one-to-many communication protocol, multiple devices can share the same I2C bus. Each slave device has a unique address, and when the master sends a message to a specific address, only the matching device responds, with the others ignoring it.
The main advantage that I2C has over other communication protocols is that it requires only two wires no matter the number of slave devices: one for Data (SDA) and one for Clock (SCL). This simplicity makes it great for small systems. However, I2C does have limitations; mainly slower speed and shorter range, making it best suited for talking to nearby, low-bandwidth devices.
More information about I2C can be found on Wikipedia.
Each I2C bus can have one master and many slave devices. In most cases, the master will be an STM32 uC, and the slaves will be peripherals. The master and all the slaves are connected to the same two wires, Serial Data (SDA) and Serial Clock (SCL). For I2C to work properly, the master and all slaves will also need to be connected to the same Ground (GND). The SDA wire is used to send data across the bus, and SCL wire is used to help all devices properly interpret the data. Both SCL and SDA require pull-up resistors.
All I2C communication is handled with transactions. All transactions are initiated by the master device, which starts each communication by sending the address of the slave that it would like to communicate with. All slaves read the address, but only the slave with the matching address acknowledges the message and continues with the transaction. After sending the slave address, the master will either send data to the slave or receive data from it.
The image below is a screenshot from Logic, the Saleae logic analyzer software. See Saleae Logic Analyzer for more information. The screenshot shows an I2C transaction where the master device reads two bits of information from the slave at address 0x24. Notice the green circle and orange square, representing the start and end of a transaction, respectively. SCL oscillates between high and low at a consistent frequency whenever data is being sent on the bus. Whenever SCL has a rising edge, going from low to high, the data on SDA is read, either by a slave or the master.
If SCL and SDA aren't held high before and after the transaction, there is some issue with the I2C bus. Likewise, if you're working with I2C, and your SCL isn't this consistent, you may have electrical issues with your setup. If Logic isn't able to decode the data on the bus, but it looks good to you, play around with your settings. If they seem to be fine, there may be an issue with the waveforms that you're missing.
When reading a datasheet for an I2C device, there are a two important things you need to find. First and foremost, you need to find the slave address for the device. Without that, there's no way to identify the device on the bus. Most devices are configurable, either in software or hardware, to work with more than one address. Make sure you understand how the device can be configured and what configuration your device is in. This will likely require some coordination with the electrical team.
Once you have the slave address, you'll also need to find register addresses for the data you're interested in. Most of the time, the devices will have more data than we need, so you won't need all of the registers. Make sure you understand the end goal of the driver you're working on, so you get the data you need without pulling everything.