发现问题

大家好,我是大牙哥!在对立创ESP32S3开发板的QMI8658板块学习过程中,发现立创提供的参考代码和自己下载的ESPIDF参考代码内容有差异。特别是在I2C的配置里面使用了不一样的结构体。


具体问题及其解决办法

具体问题是新版API里面在I2C的配置里面使用了不一样的结构体,以下我将会分享新版函数的用法,以及会和大家分享在开发过程中需要注意的一些小细节。

概述

参考乐鑫官方文章
“外设 - ESP32-S3 - — ESP-IDF 编程指南 v5.5 文档”

https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32s3/migration-guides/release-5.x/5.2/peripherals.html

我们可以发现在ESPIDF的 5.1->5.2 这两个版本是有函数用法上面的更新的。主要是在I2C上面进行了更新。但是旧版的用法乐鑫官方是有继续保留使用的,下面我们一起来看一下。

初始化部分

旧版函数

立创官方使用的旧版参考函数是ESPIDF 5.1.4的版本,对应路径是examples\peripherals\i2c\i2c_simple

#include <stdio.h>
#include "esp32_s3_szp.h"
#include "esp_err.h"
#include "driver/i2c.h"

esp_err_t bsp_i2c_init(void)
{
    i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = BSP_I2C_SDA,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_io_num = BSP_I2C_SCL,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = BSP_I2C_FREQ_HZ
    };
    i2c_param_config(BSP_I2C_NUM, &i2c_conf);

    return i2c_driver_install(BSP_I2C_NUM, i2c_conf.mode, 0, 0, 0);
}

观察这部分初始化代码,我们可以发现这里的风格是和STM32等主流芯片的底层配置非常相似的

主要有I2C模式配置、引脚选择、上拉电阻/下拉电阻。

新版函数

这里这里我使用ESPIDF的 5.3.3版本进行比较对应路径是examples\peripherals\i2c\i2c_tools\main\cmd_i2ctools.c

    i2c_master_bus_config_t i2c_bus_config = {
        .clk_source = I2C_CLK_SRC_DEFAULT,
        .i2c_port = i2c_port,
        .scl_io_num = i2c_gpio_scl,
        .sda_io_num = i2c_gpio_sda,
        .glitch_ignore_cnt = 7,
        .flags.enable_internal_pullup = true,
    };

    if (i2c_new_master_bus(&i2c_bus_config, &tool_bus_handle) != ESP_OK) {
        return 1;
    }

此处为cmd_i2ctools.c的76-87行(主要执行主机初始化)

    i2c_device_config_t i2c_dev_conf = {
        .scl_speed_hz = i2c_frequency,
        .device_address = chip_addr,
    };
    i2c_master_dev_handle_t dev_handle;
    if (i2c_master_bus_add_device(tool_bus_handle, &i2c_dev_conf, &dev_handle) != ESP_OK) {
        return 1;
    }

此处为cmd_i2ctools.c的174-182行(主要执行从机初始化)
我们首先可以注意到,新版函数会分成两个部分,一个是主机初始化,另一个是从机初始化,我们可以根据乐鑫开发文档和这里的使用方法进行整合,这里新版函数的思路是将从机和主机是分开我们可以独立调用 i2c_master_bus_config_ti2c_slave_config_t进行配置。同时废除了旧版的i2c_mode_t

新版函数使用方法

这里我们参考乐鑫新版函数对应的开发文档进行学习

static i2c_master_bus_handle_t i2c_bus_handle = NULL;
static i2c_master_dev_handle_t i2c_dev_handle = NULL;

esp_err_t bsp_i2c_init(void)
{
    // 初始化 I2C 总线
    i2c_master_bus_config_t bus_config = {
        .clk_source = I2C_CLK_SRC_DEFAULT,//默认时钟
        .i2c_port = BSP_I2C_NUM,//iic0
        .sda_io_num = BSP_I2C_SDA,
        .scl_io_num = BSP_I2C_SCL,
        .glitch_ignore_cnt = 7,//防抖
        .flags.enable_internal_pullup = true//上拉电阻
    };
    ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &i2c_bus_handle));

    // 初始化从设备(QMI8658)
    i2c_device_config_t dev_config = {
        // .dev_addr_length = I2C_ADDR_BIT_LEN_7,//可有可无
        .device_address = QMI8658_SENSOR_ADDR,//从机地址
        .scl_speed_hz = BSP_I2C_FREQ_HZ,//频率
    };
    ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_handle, &dev_config, &i2c_dev_handle));

    return ESP_OK;
}

主要的流程依旧是配置结构体,以及使用函数进行初始化。但是如果我们有对SD-Card进行开发的话我们会发现新版函数和SD-Card部分初始化整体风格更加相似,新版函数明显提高代码的整体性,对于我们维护和学习是很有帮助的!

读写部分

旧版函数

这里使用qmi8658芯片读写作为例子展示旧版函数的读写

esp_err_t qmi8658_register_read(uint8_t reg_addr, uint8_t *data, size_t len)
{
    return i2c_master_write_read_device(BSP_I2C_NUM, QMI8658_SENSOR_ADDR,  &reg_addr, 1, data, len, 1000 / portTICK_PERIOD_MS);
}

esp_err_t qmi8658_register_write_byte(uint8_t reg_addr, uint8_t data)
{
    uint8_t write_buf[2] = {reg_addr, data};

    return i2c_master_write_to_device(BSP_I2C_NUM, QMI8658_SENSOR_ADDR, write_buf, sizeof(write_buf), 1000 / portTICK_PERIOD_MS);
}

新版函数

这里使用qmi8658芯片读写作为例子展示新版函数的读写

esp_err_t qmi8658_register_write_byte(uint8_t reg_addr, uint8_t data)
{
    uint8_t write_buf[2] = {reg_addr, data};
    return i2c_master_transmit(i2c_dev_handle, write_buf, sizeof(write_buf), 1000 / portTICK_PERIOD_MS);
}
esp_err_t qmi8658_register_read(uint8_t reg_addr, uint8_t *data, size_t len)
{
    return i2c_master_transmit_receive(i2c_dev_handle, &reg_addr, 1, data, len, 1000 / portTICK_PERIOD_MS);
}

这里我们通过观察新/旧版本的函数差异,主要更新在
函数名称
【旧版】i2c_master_write_read_devicei2c_master_write_to_device
更新成
【新版】i2c_master_transmiti2c_master_transmit_receive
使用方法
主要是接收的函数有改变,在变量添加了对应的句柄。其他和旧版几乎一致。

总结

本文主要说明了ESPIDF的版本更新的API换代导致的I2C使用方式更改,大家可以参考本文进行参考进行代码的修改和迭代。
同时大家可以配合自己IDF的版本进行文档查询。

希望能够和大家一起进步!

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐