I2C Basic Example

[中文]

Note

This document is automatically translated using AI. Please excuse any detailed errors. The official English version is still in progress.

Example Description

This example demonstrates how to initialize and configure the I2C interface, as well as how to communicate with the MPU9250 sensor via the I2C master, including reading data from the slave register and releasing related resources after completion.

How to Run

The complete code for the example can be found at I2C Basic Master Example. Instructions for configuration before running, corresponding GPIO pins, build and flash process can be found in the README.md file in the example directory.

For custom configuration items and default values, refer to the Macro Definition Description section.

Header File Description

The header files used in this example cover basic modules such as FreeRTOS task management, log output, I2C driver, and system configuration. They provide support for I2C initialization, data reading, and resource release.

The header files are categorized by function as follows:

  1. FreeRTOS Task Scheduling : Provides task creation and scheduling functions.

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
  1. System Tools : Provides input and output, system configuration, and log output functions.

#include <stdio.h>
#include "sdkconfig.h"
#include "esp_log.h"
  1. I2C Driver : Provides initialization, read and write operations, and resource release functions in I2C master mode.

#include "driver/i2c_master.h"

Macro Definition Description

The macro definitions involved in this example are mainly used to configure the pins, port number, working frequency, and timeout of the I2C master, and also define the slave address and key register address of the MPU9250 sensor.

The macro definitions are categorized by function as follows:

  1. I2C Master Configuration

  • Use configuration macros to define the GPIO pin numbers used by the I2C clock line (SCL) and data line (SDA). In the example, the clock line corresponds to GPIO 4; the data line corresponds to GPIO 5.

#define I2C_MASTER_SCL_IO           CONFIG_I2C_MASTER_SCL
#define I2C_MASTER_SDA_IO           CONFIG_I2C_MASTER_SDA
  • Define the port number used by I2C, this example uses I2C_NUM_0.

#define I2C_MASTER_NUM              I2C_NUM_0
  • Use configuration macros to define the clock frequency of the I2C master. In the example, the clock frequency is 400000 Hz.

#define I2C_MASTER_FREQ_HZ          CONFIG_I2C_MASTER_FREQUENCY
  • Define the send buffer and receive buffer in master mode. Both are disabled (set to 0) in this example because the I2C master does not need to use internal buffers.

#define I2C_MASTER_TX_BUF_DISABLE   0
#define I2C_MASTER_RX_BUF_DISABLE   0
  • Define the timeout period, used to limit the waiting time in I2C read and write operations, to avoid bus blocking, in milliseconds.

#define I2C_MASTER_TIMEOUT_MS       1000

Note

  • Configuration macros start with CONFIG_, which are automatically generated by the ESP-IDF build system based on the menuconfig settings and saved in the sdkconfig file.

  • When defining GPIO pins, use configuration macros instead of directly writing pin numbers. This allows for flexible modification of pins at compile time without modifying the source code, facilitating project expansion and management.

  • If you want to change the pins used, just modify menuconfig and rebuild/compile the example, and it will automatically update without manually changing the code.

  • Disabling send and receive buffers helps save resources and is suitable for general host communication scenarios.

  1. MPU9250 Sensor Configuration :

  • Define the slave address of the MPU9250 device and the key register addresses for subsequent register read and write operations.

#define MPU9250_SENSOR_ADDR         0x68
#define MPU9250_WHO_AM_I_REG_ADDR   0x75
#define MPU9250_PWR_MGMT_1_REG_ADDR 0x6B
#define MPU9250_RESET_BIT           7

Note

  • The slave device address and register address are determined by the specific I2C slave model, not user-defined. If you are using other I2C slaves, you need to refer to the target device manual to modify the corresponding macro definitions.

  • The WHO_AM_I register is used to read the sensor chip ID to verify whether the device is properly connected.

  • The PWR_MGMT_1 register is used for power management, and the reset operation can be completed by setting the 7th bit (RESET_BIT).

Task Function Description

This example includes three core functions to implement communication between the I2C host and the MPU9250 sensor: the I2C host initialization function, the register read function, and the register write function.

I2C Host Initialization Function

i2c_master_init() is used to initialize the I2C host and bind the target device.

This initialization step is universal and applicable to all scenarios involving I2C peripherals. You only need to modify the port number, slave address, and related configuration parameters according to the specific device. For a detailed explanation of the steps and the involved structure members, refer to the I2C Initialization section.

Parameter Explanation

Input Parameter

Parameter Function

Parameter Description

bus_handle

I2C bus handle pointer

The valid handle returned after the bus is successfully created, used for subsequent read and write operations on this bus.

dev_handle

I2C device handle pointer

The valid device handle returned after adding the device to the I2C bus, used for subsequent communication with this device.

Register Write and Read Function

mpu9250_register_read() is used to read the contents of the MPU6050 register address.

Parameter Explanation

Input Parameter

Parameter Function

Parameter Description

dev_handle

I2C device handle

The valid device handle returned after adding the device to the I2C bus, used to specify the target slave device.

reg_addr

Target register address

The register address of the target device to be read.

data

Data buffer pointer

Used to store data read from the register. After calling the function, data is written to this memory area.

len

Read byte length

Specifies the number of bytes to read from the register, and the buffer size must be sufficient to hold the data.

This function calls i2c_master_transmit_receive() to implement register write and read, with the following execution logic:

  1. Send the target register address as write data to MPU9250 to specify the register and verify the device connection. The slave should acknowledge the successful reception.

  2. The slave sends the register content, the master acknowledges the reception, and reads the specified length of data.

  3. The master stores the received data in the data buffer.

For more explanations and the principle of the function, refer to I2C Master Write then Read. The parameter description of i2c_master_transmit_receive() can be found in I2C Interface.

Register Write Function

mpu9250_register_write_byte() is used to write a single byte of data to the specified register of MPU9250.

Parameter Explanation

Input Parameter

Parameter Function

Parameter Description

dev_handle

I2C device handle

The valid device handle returned after adding the device to the I2C bus, used to specify the target slave device.

reg_addr

Target register address

The address of the target device register to be read.

data

Data to be written

Single byte data.

The function execution logic is as follows:

  1. Combine the register address and the data to be written into the write buffer write_buf[].

  2. Call i2c_master_transmit() to write the buffer data to the specified register of the slave device, achieving register write.

For more explanations and the principle of the function, refer to I2C Master Write. The parameter description of i2c_master_transmit() can be found in I2C Interface.

Main Function Description

This example demonstrates the initialization of the I2C master, communication with the MPU9250 sensor, and resource release.

  1. Define variables:

  • Define the array data[] to store the data read from MPU9250.

  • Define the bus handle bus_handle and device handle dev_handle for subsequent saving of the returned handles.

  1. Call i2c_master_init() to initialize the I2C bus and add the slave device, completing the connection between the master and the slave. After successful execution, it returns the corresponding handle and prints a log to indicate that I2C initialization is complete.

  2. Call mpu9250_register_read() to read the content in the WHO_AM_I register.

  3. Call mpu9250_register_write_byte() to set the RESET_BIT of the PWR_MGMT_1 register to 1, achieving the reset of MPU9250.

  4. Release I2C Resources:

  • Call i2c_master_bus_rm_device() to remove the slave device. For parameter description, refer to I2C Interface.

  • Call i2c_del_master_bus() to delete the I2C bus. For parameter description, refer to I2C Interface.

Note

  • Initialization and resource release are common processes for I2C, ensuring the bus and devices are correctly configured and released to avoid resource leaks.

  • Performing read and write operations are application-specific tasks, and register operations can be modified according to the actual functions of the slave device.

Program Phenomenon

In this example, the program controls read and write operations by sending register addresses to the slave device. The read operation uses a write register address and read data transaction, and the write operation uses a write register address and write data transaction. The corresponding timing diagram is as follows:

I2C-timing-diagram

According to the timing diagram, the program execution can be summarized into the following stages:

  1. Start Condition: Represented as S in the timing diagram, the master sends the start condition, marking the beginning of an I2C transaction. SDA is pulled low from high, while SCL remains high.

  2. Master Address Write: Represented as AW : D0 W in the timing diagram, the master sends a 7-bit slave address plus a 1-bit write flag (W) to the slave on the rising edge of SCL. SDA outputs the address and write flag, and each bit of data is sampled by the slave when SCL is high.

  3. Slave Acknowledge: Represented as A in the timing diagram, the slave pulls SDA low to send ACK after receiving the address and recognizing it as a write operation.

  4. Master Data Write: Represented as Data write: 75 in the timing diagram, the master sends register data to the slave. SDA outputs the data, and each bit of data is sampled corresponding to the high level of SCL.

  5. Slave Acknowledge: Represented as A in the timing diagram, the slave pulls SDA low to send ACK after receiving the data.

  6. Repeated Start Condition: Represented as Sr in the timing diagram, the master sends the repeated start condition, preparing for the read operation. SDA is pulled low from high, while SCL remains high.

  7. Master Address Read: Represented as AR : D1 R in the timing diagram, the master sends a 7-bit slave address plus a 1-bit read flag (R) to the slave on the rising edge of SCL. SDA outputs the address and read flag, and each bit of data is sampled by the slave when SCL is high.

  8. Slave Data Read: Represented as Read write: 68 in the timing diagram, the slave outputs the register data to SDA, and the master samples the data on the rising edge of SCL.

  9. Master Acknowledge: Represented as N in the timing diagram, the master pulls SDA high to send NACK after receiving the last byte, indicating the end of this read operation.

  10. Stop Condition: Represented as P in the timing diagram, the master sends the stop condition, ending this I2C transaction. SDA is pulled high from low, while SCL remains high.