This article explains what is the I2C and how to use it through examples
1. What is Inter-integrated circuit (I2C)?
I2C is a two-wire serial communication system used between integrated circuits which was originally created by Philips Semiconductors back in 1982.
The I2C is a multi-master, multi-slave, synchronous, bidirectional, half-duplex serial communication bus.
- SDA (Serial Data) is the line where master and slave send or receive the information (sequence of bits).
- SCL (Serial Clock) is the line dedicated to the clock to synchronize the data flow.
SDA and SCL lines need to be pulled up with resistors. The value of these resistors depends on the bus length (the bus capacitance) and the transmission speed. The common value is 4.7kO. In any case, there are many guides to size them and we refer their reading to the more attentive reader.
1.1. I2C Modes
- Standard-Mode (Sm) with a bit rate up to 100 kbit/s
- Fast-Mode (Fm) with a bit rate up to 400 kbit/s
- Fast-Mode Plus (Fm+) with a bit rate up to 1 Mbit/s
1.2. I2C Frame
- Start Condition (S)
- Stop Condition (P)
- Repeated Start (Restart) Condition (Sr)
- Acknowledge ACK (A)
- Not Acknowledge NACK (/A)
1.3. STM32 I2C Mode selection
The interface can operate in one of the four following modes:
- Slave transmitter
- Slave receiver
- Master transmitter
- Master receiver
1.4. Main I2C HAL functions
I2C in STM32 can be done in 3 methods.
Blocking Mode, interrupt Mode or DMA Mode
- Blocking Mode:
The communication is performed in the polling mode.The status of all data processing is returned by the same function after finishing transfer.
HAL_I2C_Master_Transmit()
HAL_I2C_Master_Receive()
HAL_I2C_Slave_Transmit()
HAL_I2C_Slave_Receive()
HAL_I2C_Mem_Write()
HAL_I2C_Mem_Read()
- No-blocking modes
The communication is performed using Interrupts or DMA. These functions return the status of the transfer startup.
The end of the data processing will be indicated through the dedicated I2C IRQ when using Interrupt mode or the DMA IRQ when using DMA mode.
- Interrupt Mode:
HAL_I2C_Master_Transmit_IT()
HAL_I2C_Master_Receive_IT()
HAL_I2C_Slave_Transmit_IT()
HAL_I2C_Slave_Receive_IT()
HAL_I2C_Mem_Write_IT()
HAL_I2C_Mem_Read_IT()
- DMA Mode:
HAL_I2C_Master_Transmit_DMA()
HAL_I2C_Master_Receive_DMA()
HAL_I2C_Slave_Transmit_DMA()
HAL_I2C_Slave_Receive_DMA()
HAL_I2C_Mem_Write_DMA()
HAL_I2C_Mem_Read_DMA()
2. Configure I2C to communicate between two boards
2.1. Objective
Communicate data between two NUCLEO-L476RG and learn how to set I2C in different modes.
2.2. Create project in STM32CubeIDE
- The NUCLEO-L476RG pinout is helpful to set the wiring between the boards in the project.
- File > New > STM32 Project in main panel.
In this example the NUCLEO-L476RG board is used.
- Select NUCLEO-L476RG board using Board Selector as shown in the below figure.
In case you haven't downloaded the STM32L476 Cube library, it will be downloaded automatically, it may take some time.
- Save the project.
2.3. I2C configuration
- Open the STM32CubeMX project from the workspace
- Select I2C1
- Select PB8: SCL and PB9: SDA for I2C1 if weren't selected
- Set the I2C Mode Standard Mode and the I2C Frequency at 100 KHz
- GPIO Settings
- In the GPIO Settings tab
- Check Pull-UP
- Check GPIO speed
- In the GPIO Settings tab
Interrupt Mode only
- In the NVIC settings tab
- Enable interrupt
- In the NVIC settings tab
DMA Mode only
- In the DMA settings tab
- In the DMA settings tab
- Add I2C1_TX for Master
- Add I2C1_TX for Master
- Add I2C1_RX for Master
- Add I2C1_RX for Master
2.3.1. Generate source code
- Click "Ctrl+S" to generate the project.
2.3.2. Edit main.c
2.3.2.1. On MASTER Board
- Open main.c in Project Explorer / myproject / Src / main.c.
/* USER CODE BEGIN PV */
/* Private variables
uint8_t TX_Buffer [] = "A" ; // DATA to send
/* USER CODE END PV */
Blocking Mode
/* USER CODE BEGIN 2 */
HAL_I2C_Master_Transmit(&hi2c1,20,TX_Buffer,1,1000); //Sending in Blocking mode
HAL_Delay(100);
/* USER CODE END 2 */
Interrupt Mode
/* USER CODE BEGIN 2 */
HAL_I2C_Master_Transmit_IT(&hi2c1,20,TX_Buffer,1); //Sending in Interrupt mode
HAL_Delay(100);
/* USER CODE END 2 */
DMA Mode
/* USER CODE BEGIN 2 */
HAL_I2C_Master_Transmit_DMA(&hi2c1,20,TX_Buffer,1); //Sending in DMA mode
HAL_Delay(100);
/* USER CODE END 2 */
2.3.2.1.1. Compile and flash
2.3.2.2. On SLAVE Board
- Open main.c in Project Explorer / myproject / Src / main.c.
/* USER CODE BEGIN PV */
/* Private variables
uint8_t RX_Buffer [1] ; // DATA to receive
/* USER CODE END PV */
Blocking Mode
/* USER CODE BEGIN 2 */
HAL_I2C_Slave_Receive(&hi2c1 ,(uint8_t *)RX_Buffer, 1,1000); //Receiving in Blocking mode
HAL_Delay(100);
/* USER CODE END 2 */
Interrupt Mode
/* USER CODE BEGIN 2 */
HAL_I2C_Slave_Receive_IT(&hi2c1 ,(uint8_t *)RX_Buffer, 1); //Receiving in Interrupt mode
HAL_Delay(100);
/* USER CODE END 2 */
DMA Mode
/* USER CODE BEGIN 2 */
HAL_I2C_Slave_Receive_DMA(&hi2c1 ,(uint8_t *)RX_Buffer, 1); //Receiving in DMA mode
HAL_Delay(100);
/* USER CODE END 2 */
2.3.2.2.1. Compile and flash
2.4. Project workspace
The following table shows the connection between 2 STM32 boards for using I2C bus. It requires only three wires.
NUCLEO-L476RG MASTER | NUCLEO-L476RG SLAVE | Pin description |
---|---|---|
PB8 | PB8 | SCL |
PB9 | PB9 | SDA |
GND | GND | Ground |
[[category:Getting_started_with_STM32_system_peripherals | 15]]