跳转至

I2C 代码

组件架构

- driver
    - node_i2c
        - include
            - node_i2c.h
        - node_i2c.c
        - CMakeLists.txt

driver/node_i2c/CMakeLists.txt

set(src_dirs
    .
)

set(include_dirs
    include
)

set(requires
    driver
    log
)

idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})

Note

注意,在驱动程序中,我们使用了 ESP-IDF 内置的 driver 库中的i2c和gpio相关函数,因此,我们需要在 CMakeLists.txt 文件的 REQUIRES 字段中指明这个依赖关系。

node_i2c.h

/**
 * @file node_i2c.h
 * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
 * @brief This file contains the function prototypes for i2c master initialization. This is to serve the peripherals that require I2C communication.
 * @version 1.0
 * @date 2025-10-22
 *
 * @copyright Copyright (c) 2025
 *
 */

#pragma once

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c_master.h"
#include "esp_system.h"

#define I2C_MASTER_SCL_IO 10       /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO 11       /*!< gpio number for I2C master data  */
#define I2C_MASTER_NUM I2C_NUM_0  /*!< I2C port number for master dev */
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */

/* I2C Bus and Device Handles */
extern i2c_master_bus_handle_t i2c_bus_handle;

   /**
    * @brief i2c master bus initialization
    * @return esp_err_t ESP_OK on success, error code on failure
    */
   esp_err_t i2c_bus_init(void);

   /**
    * @brief i2c master bus deinitialization
    * @return esp_err_t ESP_OK on success, error code on failure
    */
   esp_err_t i2c_bus_deinit(void);

   /**
    * @brief add i2c device to bus
    * @param device_addr I2C device address
    * @param scl_speed_hz SCL clock speed in Hz
    * @param dev_handle pointer to store device handle
    * @return esp_err_t ESP_OK on success, error code on failure
    */
   esp_err_t i2c_add_device(uint8_t device_addr, uint32_t scl_speed_hz, i2c_master_dev_handle_t *dev_handle);

   /**
    * @brief remove i2c device from bus
    * @param dev_handle device handle to remove
    * @return esp_err_t ESP_OK on success, error code on failure
    */
   esp_err_t i2c_remove_device(i2c_master_dev_handle_t dev_handle);

   /**
    * @brief write data to i2c device
    * @param dev_handle device handle
    * @param data data to write
    * @param data_len length of data
    * @param timeout_ms timeout in milliseconds
    * @return esp_err_t ESP_OK on success, error code on failure
    */
   esp_err_t i2c_write_data(i2c_master_dev_handle_t dev_handle, const uint8_t *data, size_t data_len, int timeout_ms);

   /**
    * @brief read data from i2c device
    * @param dev_handle device handle
    * @param data buffer to store read data
    * @param data_len length of data to read
    * @param timeout_ms timeout in milliseconds
    * @return esp_err_t ESP_OK on success, error code on failure
    */
   esp_err_t i2c_read_data(i2c_master_dev_handle_t dev_handle, uint8_t *data, size_t data_len, int timeout_ms);

   /**
    * @brief write then read data from i2c device (combined transaction)
    * @param dev_handle device handle
    * @param write_data data to write
    * @param write_len length of write data
    * @param read_data buffer to store read data
    * @param read_len length of data to read
    * @param timeout_ms timeout in milliseconds
    * @return esp_err_t ESP_OK on success, error code on failure
    */
   esp_err_t i2c_write_read_data(i2c_master_dev_handle_t dev_handle, 
                                 const uint8_t *write_data, size_t write_len,
                                 uint8_t *read_data, size_t read_len, 
                                 int timeout_ms);

#ifdef __cplusplus
}
#endif

node_i2c.c

/**
 * @file node_i2c.c
 * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
 * @brief This file contains the functions for i2c master initialization using ESP-IDF 6.0 i2c_master driver.
 * @version 1.0
 * @date 2025-10-22
 *
 * @copyright Copyright (c) 2025
 *
 */
#include "node_i2c.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Global I2C Bus Handle */
i2c_master_bus_handle_t i2c_bus_handle = NULL;

/**
 * @brief i2c master bus initialization using ESP-IDF 6.0 i2c_master driver
 * @return esp_err_t ESP_OK on success, error code on failure
 */
esp_err_t i2c_bus_init(void)
{
    esp_err_t ret;

    /* Configure I2C master bus */
    i2c_master_bus_config_t i2c_bus_config = {
        .clk_source = I2C_CLK_SRC_DEFAULT,
        .i2c_port = I2C_MASTER_NUM,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .glitch_ignore_cnt = 7,
        .flags.enable_internal_pullup = true
    };

    ret = i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
    if (ret != ESP_OK) {
        ESP_LOGE("I2C", "I2C bus creation failed: %s", esp_err_to_name(ret));
        return ret;
    }

    ESP_LOGI("I2C", "I2C master bus initialized successfully");
    return ESP_OK;
}

/**
 * @brief i2c master bus deinitialization
 * @return esp_err_t ESP_OK on success, error code on failure
 */
esp_err_t i2c_bus_deinit(void)
{
    esp_err_t ret = ESP_OK;

    if (i2c_bus_handle != NULL) {
        ret = i2c_del_master_bus(i2c_bus_handle);
        if (ret != ESP_OK) {
            ESP_LOGE("I2C", "I2C bus deletion failed: %s", esp_err_to_name(ret));
            return ret;
        }
        i2c_bus_handle = NULL;
    }

    ESP_LOGI("I2C", "I2C master bus deinitialized successfully");
    return ESP_OK;
}

/**
 * @brief add i2c device to bus
 * @param device_addr I2C device address
 * @param scl_speed_hz SCL clock speed in Hz
 * @param dev_handle pointer to store device handle
 * @return esp_err_t ESP_OK on success, error code on failure
 */
esp_err_t i2c_add_device(uint8_t device_addr, uint32_t scl_speed_hz, i2c_master_dev_handle_t *dev_handle)
{
    esp_err_t ret;

    if (i2c_bus_handle == NULL) {
        ESP_LOGE("I2C", "I2C bus not initialized");
        return ESP_ERR_INVALID_STATE;
    }

    i2c_device_config_t dev_cfg = {
        .dev_addr_length = I2C_ADDR_BIT_LEN_7,
        .device_address = device_addr,
        .scl_speed_hz = scl_speed_hz
    };

    ret = i2c_master_bus_add_device(i2c_bus_handle, &dev_cfg, dev_handle);
    if (ret != ESP_OK) {
        ESP_LOGE("I2C", "I2C device addition failed: %s", esp_err_to_name(ret));
        return ret;
    }

    ESP_LOGI("I2C", "I2C device 0x%02X added successfully", device_addr);
    return ESP_OK;
}

/**
 * @brief remove i2c device from bus
 * @param dev_handle device handle to remove
 * @return esp_err_t ESP_OK on success, error code on failure
 */
esp_err_t i2c_remove_device(i2c_master_dev_handle_t dev_handle)
{
    esp_err_t ret = i2c_master_bus_rm_device(dev_handle);
    if (ret != ESP_OK) {
        ESP_LOGE("I2C", "I2C device removal failed: %s", esp_err_to_name(ret));
        return ret;
    }

    ESP_LOGI("I2C", "I2C device removed successfully");
    return ESP_OK;
}

/**
 * @brief write data to i2c device
 * @param dev_handle device handle
 * @param data data to write
 * @param data_len length of data
 * @param timeout_ms timeout in milliseconds
 * @return esp_err_t ESP_OK on success, error code on failure
 */
esp_err_t i2c_write_data(i2c_master_dev_handle_t dev_handle, const uint8_t *data, size_t data_len, int timeout_ms)
{
    esp_err_t ret = i2c_master_transmit(dev_handle, data, data_len, timeout_ms);
    if (ret != ESP_OK) {
        ESP_LOGE("I2C", "I2C write failed: %s", esp_err_to_name(ret));
        return ret;
    }

    ESP_LOGD("I2C", "I2C write successful, %d bytes", data_len);
    return ESP_OK;
}

/**
 * @brief read data from i2c device
 * @param dev_handle device handle
 * @param data buffer to store read data
 * @param data_len length of data to read
 * @param timeout_ms timeout in milliseconds
 * @return esp_err_t ESP_OK on success, error code on failure
 */
esp_err_t i2c_read_data(i2c_master_dev_handle_t dev_handle, uint8_t *data, size_t data_len, int timeout_ms)
{
    esp_err_t ret = i2c_master_receive(dev_handle, data, data_len, timeout_ms);
    if (ret != ESP_OK) {
        ESP_LOGE("I2C", "I2C read failed: %s", esp_err_to_name(ret));
        return ret;
    }

    ESP_LOGD("I2C", "I2C read successful, %d bytes", data_len);
    return ESP_OK;
}

/**
 * @brief write then read data from i2c device (combined transaction)
 * @param dev_handle device handle
 * @param write_data data to write
 * @param write_len length of write data
 * @param read_data buffer to store read data
 * @param read_len length of data to read
 * @param timeout_ms timeout in milliseconds
 * @return esp_err_t ESP_OK on success, error code on failure
 */
esp_err_t i2c_write_read_data(i2c_master_dev_handle_t dev_handle, 
                              const uint8_t *write_data, size_t write_len,
                              uint8_t *read_data, size_t read_len, 
                              int timeout_ms)
{
    esp_err_t ret = i2c_master_transmit_receive(dev_handle, write_data, write_len, read_data, read_len, timeout_ms);
    if (ret != ESP_OK) {
        ESP_LOGE("I2C", "I2C write-read failed: %s", esp_err_to_name(ret));
        return ret;
    }

    ESP_LOGD("I2C", "I2C write-read successful, wrote %d bytes, read %d bytes", write_len, read_len);
    return ESP_OK;
}

#ifdef __cplusplus
}
#endif

main.c

#include "node_i2c.h"

void app_main(void) {
    // 1. initialize the i2c bus
    esp_err_t ret = i2c_bus_init();
    if (ret != ESP_OK) return;

    // 2. add i2c device to bus
    i2c_master_dev_handle_t dev_handle;
    ret = i2c_add_device(0x68, 400000, &dev_handle);
    if (ret != ESP_OK) return;

    // 3. write data to i2c device
    uint8_t data[] = {0x75};
    i2c_write_data(dev_handle, data, 1, 1000);

    uint8_t response[1];
    i2c_read_data(dev_handle, response, 1, 1000);

    // 4. clean up resources
    i2c_remove_device(dev_handle);
    i2c_bus_deinit();
}

main.cpp

/**
 * @file main.cpp
 * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
 * @brief I2C Test Application
 * @version 1.0
 * @date 2025-10-22
 * 
 * @copyright Copyright (c) 2024
 * 
 */

#include "node_i2c.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Entry point of the program
 * @param None
 * @retval None
 */
void app_main(void) {
    // 1. initialize the i2c bus
    esp_err_t ret = i2c_bus_init();
    if (ret != ESP_OK) return;

    // 2. add i2c device to bus
    i2c_master_dev_handle_t dev_handle;
    ret = i2c_add_device(0x68, 400000, &dev_handle);
    if (ret != ESP_OK) return;

    // 3. write data to i2c device
    uint8_t data[] = {0x75};
    i2c_write_data(dev_handle, data, 1, 1000);

    uint8_t response[1];
    i2c_read_data(dev_handle, response, 1, 1000);

    // 4. clean up resources
    i2c_remove_device(dev_handle);
    i2c_bus_deinit();
}

#ifdef __cplusplus
}
#endif

Note

请注意,本章需要与其他使用i2c的部件联合使用,才能看到效果。在使用基于i2c的外设时,请确保您已经正确配置和初始化了i2c总线。(例如在主程序中调用i2c_bus_init()函数)