当前位置: 首页 > news >正文

【ESP32-IDF 笔记】04-I2C配置

简介

I2C是一种串行、同步、多设备、半双工的通信协议,允许多个主机和从机在同一总线上共存。I2C使用两条双向开漏线路:串行数据线(SDA)和串行时钟线(SCL),并通过上拉电阻拉高。

ESP32有2个I2C控制器(也称为端口),负责处理I2C总线上的通信。单个I2C控制器既可以作为主机,也可以作为从机。

通常,I2C从设备具有7位地址或10位地址。ESP32支持I2C标准模式(Sm)和快速模式(Fm),其速率分别可达100KHz和400KHz。

警告:

主模式下 SCL 的时钟频率不应大于 400 KHz

备注:

SCL 的频率受上拉电阻和导线电容的影响。因此,强烈建议用户选择合适的上拉电阻,以使频率准确。上拉电阻器的推荐值通常在 1K 欧姆到 10K 欧姆之间。

请记住,频率越高,上拉电阻应越小(但不小于 1 KOhms)。事实上,大 resistor 会降低电流,这将增加 clock switching time 并降低频率。我们通常推荐 2 KOhms 至 5 KOhms 的范围,但用户可能还需要根据其电流消耗要求进行一些调整。

I2C 时钟配置

  • i2c_clock_source_t::I2C_CLK_SRC_DEFAULT:默认 I2C 源时钟。
  • i2c_clock_source_t::I2C_CLK_SRC_APB:APB 时钟作为 I2C 时钟源。

I2C 文件结构

在这里插入图片描述

需要包含在 I2C 应用程序中的公共标头

  • i2c.h:旧版 I2C API 的头文件(适用于使用旧版驱动程序的应用程序)。
  • i2c_master.h:提供标准通信模式特定 API 的头文件(适用于使用具有主模式的新驱动程序的应用程序)。
  • i2c_slave.h:提供标准通信模式特定 API 的头文件(适用于使用具有从属模式的新驱动程序的应用程序)。

备注:

旧驱动程序不能与新驱动程序共存。Include 以使用旧驱动程序,或其他两个标头以使用新驱动程序。请记住,旧版驱动程序现已弃用,并将在将来删除。i2c.h

已包含在上述标头中的公共标头

  • i2c_types_legacy.h:仅在旧版驱动程序中使用的旧版公共类型。
  • i2c_types.h:提供公共类型的头文件。

功能概述

I2C 驱动程序提供以下服务:

  • 资源分配 - 介绍如何使用适当的配置集分配 I2C 总线。它还介绍了如何在资源完成工作后回收资源。
  • I2C 主控制器 - 涵盖 I2C 主控制器的行为。引入数据传输、数据接收以及数据传输和接收。
  • I2C 从控制器 - 涵盖 I2C 从控制器的行为。涉及数据传输和接收。
  • 电源管理 - 描述不同的源时钟将如何影响功耗。
  • IRAM Safe - 描述有关如何使 I2C 中断在禁用缓存的情况下更好地工作的提示。
  • 线程安全 - 列出驱动程序保证哪些 API 是线程安全的。
  • Kconfig 选项 - 列出支持的 Kconfig 选项,这些选项可以为驱动程序带来不同的效果。

资源配置

I2C 主总线和 I2C 从总线(如果支持)在驱动程序中都由 表示。可用端口在资源池中进行管理,该资源池根据请求分配可用端口。i2c_bus_handle_t

安装 I2C 主总线和设备

I2C 主控器基于总线器件模型设计。因此、需要分别分配 I2C 主总线实例和 I2C 器件实例。
在这里插入图片描述

I2C 主总线需要由以下指定的配置:

  • i2c_master_bus_config_t::i2c_port设置控制器使用的 I2C 端口。
  • i2c_master_bus_config_t::sda_io_num设置串行数据总线 (SDA) 的 GPIO 编号。
  • i2c_master_bus_config_t::scl_io_num设置串行时钟总线 (SCL) 的 GPIO 编号。
  • i2c_master_bus_config_t::clk_source选择 I2C 总线的源时钟。中列出了可用的时钟。有关不同 clock source 对 power consumption 的影响,请参阅 Power Management 部分。
  • i2c_master_bus_config_t::glitch_ignore_cnt设置 Master Bus 的 Glitch Period,如果线路上的 Glitch Period小于此值,可以过滤掉,通常值为 7。
  • i2c_master_bus_config_t::intr_priority设置中断的优先级。如果设置为 ,则驱动程序将使用低优先级或中优先级的中断(优先级可以是 1,2 或 3 之一),否则使用请使用数字形式 (1,2,3) 指示的优先级,而不是位掩码形式 ((1<<1),(1<<2),(1<<3))。0
  • i2c_master_bus_config_t::trans_queue_depth内部传输队列的深度。仅在异步事务中有效。
  • i2c_master_bus_config_t::enable_internal_pullup启用内部 pullups。注意:这不足以在高速频率下拉总线。建议使用合适的外部上拉。

如果指定了 i2c_master_bus_config_t中的配置,用户可以调用 i2c_new_master_bus()来分配并初始化一个 I2C 主机总线。如果此函数正常运行,它将返回 I2C 总线句柄。具体来说,当没有更多的 I2C 端口可用时,此函数将返回ESP_ERR_NOT_FOUND错误。

I2C 主设备需要由以下指定的配置:

  • i2c_device_config_t::dev_addr_length配置从设备的地址位长度。用户可以从枚举器I2C_ADDR_BIT_LEN_7或 I2C_ADDR_BIT_LEN_10(如果支持) 中进行选择。

  • i2c_device_config_t::device_addressI2C 设备原始地址。请直接解析该成员的设备地址。例如,设备地址为 0x28,则解析0x28为 ,

    i2c_device_config_t::device_address,不要携带写/读位。

  • i2c_device_config_t::scl_speed_hz设置此设备的 SCL 线路频率。

  • i2c_device_config_t::scl_wait_us.SCL 等待时间 (在美国)。通常这个值不应该很小,因为 slave stretch 会在很长一段时间内发生。(甚至可以拉伸 12 毫秒)。设置 0 表示使用默认 reg 值。

一旦i2c_device_config_t结构中填充了强制性参数,用户就可以调用i2c_master_bus_add_device()以分配 I2C 设备实例并挂载到主总线。如果 I2C 设备运行正常,此函数将返回 I2C 设备句柄。具体来说,当 I2C 总线没有正确初始化时,调用此函数将返回ESP_ERR_INVALID_ARG错误。

示例

#include "driver/i2c_master.h"

i2c_master_bus_config_t i2c_mst_config = {
    .clk_source = I2C_CLK_SRC_DEFAULT,
    .i2c_port = TEST_I2C_PORT,
    .scl_io_num = I2C_MASTER_SCL_IO,
    .sda_io_num = I2C_MASTER_SDA_IO,
    .glitch_ignore_cnt = 7,
    .flags.enable_internal_pullup = true,
};

i2c_master_bus_handle_t bus_handle;
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));

i2c_device_config_t dev_cfg = {
    .dev_addr_length = I2C_ADDR_BIT_LEN_7,
    .device_address = 0x58,
    .scl_speed_hz = 100000,
};

i2c_master_dev_handle_t dev_handle;
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
通过端口获取 I2C 主手柄

鉴于 i2c 主句柄已经在某个模块(例如音频模块)中初始化,另一个模块(例如视频模块)不方便重用该句柄。我们有一个辅助函数i2c_master_get_bus_handle()用于通过 port 获取初始化的句柄。但是,请确保 handle 已提前初始化。否则将报告错误。

// Source File 1
#include "driver/i2c_master.h"
i2c_master_bus_handle_t bus_handle;
i2c_master_bus_config_t i2c_mst_config = {
    ... // same as others
};
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));

// Source File 2
#include "driver/i2c_master.h"
i2c_master_bus_handle_t handle;
ESP_ERROR_CHECK(i2c_master_get_bus_handle(0, &handle));
卸载 I2C 主总线和设备

如果不再需要以前安装的 I2C 总线或设备,建议通过调用i2c_master_bus_rm_device()i2c_del_master_bus()来回收资源,以便释放底层硬件。

安装 I2C 从设备

I2C slave 需要 :

  • i2c_slave_config_t::i2c_port设置控制器使用的 I2C 端口。
  • i2c_slave_config_t::sda_io_num设置串行数据总线 (SDA) 的 GPIO 编号。
  • i2c_slave_config_t::scl_io_num设置串行时钟总线 (SCL) 的 GPIO 编号。
  • i2c_slave_config_t::clk_source选择 I2C 总线的源时钟。i2c_clock_source_t中列出了可用的时钟。有关不同 clock source 对 power consumption 的影响,请参阅 Power Management 部分。
  • i2c_slave_config_t::send_buf_depth设置发送缓冲区长度。
  • i2c_slave_config_t::slave_addr设置从地址
  • i2c_master_bus_config_t::intr_priority设置中断的优先级。如果设置为 ,则驱动程序将使用低优先级或中优先级的中断(优先级可以是 1,2 或 3 之一),否则使用请使用数字形式 (1,2,3) 指示的优先级,而不是位掩码形式 ((1<<1),(1<<2),(1<<3))。请注意,一旦设置了中断优先级,就不能更改,直到i2c_del_master_bus()被调用。0
  • i2c_slave_config_t::addr_bit_len如果需要从站具有 10 位地址,则设置为 true。

一旦i2c_slave_config_t结构填充了强制性参数,用户就可以调用i2c_new_slave_device()以分配和初始化 I2C 主总线。如果此函数正常运行,它将返回 I2C 总线句柄。具体来说,当没有更多的 I2C 端口可用时,此函数将返回ESP_ERR_NOT_FOUND错误。

i2c_slave_config_t i2c_slv_config = {
    .addr_bit_len = I2C_ADDR_BIT_LEN_7,
    .clk_source = I2C_CLK_SRC_DEFAULT,
    .i2c_port = TEST_I2C_PORT,
    .send_buf_depth = 256,
    .scl_io_num = I2C_SLAVE_SCL_IO,
    .sda_io_num = I2C_SLAVE_SDA_IO,
    .slave_addr = 0x58,
};

i2c_slave_dev_handle_t slave_handle;
ESP_ERROR_CHECK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
卸载 I2C 从设备

如果不再需要以前安装的 I2C 总线,建议通过调用 i2c_del_slave_device()来回收资源,以便释放底层硬件。

I2C 主控制器

通过 i2c_new_master_bus()安装 i2c 主驱动后,ESP32 就可以与其他 I2C 设备通信了。I2C API 允许标准事务。像这样挥手:

在这里插入图片描述

I2C 主机写入数据

成功安装 I2C 主总线后,您只需调用i2c_master_transmit()即可将数据写入从设备。这个函数的原理可以用下图来解释。

为了组织该过程,驱动程序使用命令链接,该链接应填充一系列命令,然后传递给 I2C 控制器执行。

在这里插入图片描述
将数据写入 从机 的简单示例:

#define DATA_LENGTH 100
i2c_master_bus_config_t i2c_mst_config = {
    .clk_source = I2C_CLK_SRC_DEFAULT,
    .i2c_port = I2C_PORT_NUM_0,
    .scl_io_num = I2C_MASTER_SCL_IO,
    .sda_io_num = I2C_MASTER_SDA_IO,
    .glitch_ignore_cnt = 7,
};
i2c_master_bus_handle_t bus_handle;

ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));

i2c_device_config_t dev_cfg = {
    .dev_addr_length = I2C_ADDR_BIT_LEN_7,
    .device_address = 0x58,
    .scl_speed_hz = 100000,
};

i2c_master_dev_handle_t dev_handle;
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));

ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1));
I2C 主机读取数据

成功安装 I2C 主总线后,您只需调用i2c_master_receive()即可从从设备读取数据。这个函数的原理可以用下图来解释。
在这里插入图片描述
从 从机 读取数据的简单示例:

#define DATA_LENGTH 100
i2c_master_bus_config_t i2c_mst_config = {
    .clk_source = I2C_CLK_SRC_DEFAULT,
    .i2c_port = I2C_PORT_NUM_0,
    .scl_io_num = I2C_MASTER_SCL_IO,
    .sda_io_num = I2C_MASTER_SDA_IO,
    .glitch_ignore_cnt = 7,
};
i2c_master_bus_handle_t bus_handle;

ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));

i2c_device_config_t dev_cfg = {
    .dev_addr_length = I2C_ADDR_BIT_LEN_7,
    .device_address = 0x58,
    .scl_speed_hz = 100000,
};

i2c_master_dev_handle_t dev_handle;
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));

i2c_master_receive(dev_handle, data_rd, DATA_LENGTH, -1);
I2C 主机写/读数据

一些 I2C 设备在从中读取数据之前需要写入配置,因此,一个名为i2c_master_transmit_receive()函数 可以提供帮助。这个函数的原理可以用下图来解释。
在这里插入图片描述

从 slave 写入和读取的简单示例:

i2c_device_config_t dev_cfg = {
    .dev_addr_length = I2C_ADDR_BIT_LEN_7,
    .device_address = 0x58,
    .scl_speed_hz = 100000,
};

i2c_master_dev_handle_t dev_handle;
ESP_ERROR_CHECK(i2c_master_bus_add_device(I2C_PORT_NUM_0, &dev_cfg, &dev_handle));
uint8_t buf[20] = {0x20};
uint8_t buffer[2];
ESP_ERROR_CHECK(i2c_master_transmit_receive(i2c_bus_handle, buf, sizeof(buf), buffer, 2, -1));
I2C 主机探针

I2C 驱动程序可使用i2c_master_probe()检测特定设备是否已连接到 I2C 总线上。如果此函数返回 ,则表示已检测到该设备。ESP_OK

注意:

调用此函数时,上拉电阻必须连接到 SCL 和 SDA 引脚。如果在正确解析 xfer_timeout_ms 时得到 ESP_ERR_TIMEOUT,则应检查 pull-up resistors。如果附近没有合适的 resistor,将 flags.enable_internal_pullup 设置为 true 也是可以接受的。

探测 I2C 器件的简单示例

i2c_master_bus_config_t i2c_mst_config_1 = {
    .clk_source = I2C_CLK_SRC_DEFAULT,
    .i2c_port = TEST_I2C_PORT,
    .scl_io_num = I2C_MASTER_SCL_IO,
    .sda_io_num = I2C_MASTER_SDA_IO,
    .glitch_ignore_cnt = 7,
    .flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t bus_handle;

ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config_1, &bus_handle));
ESP_ERROR_CHECK(i2c_master_probe(bus_handle, 0x22, -1));
ESP_ERROR_CHECK(i2c_del_master_bus(bus_handle));

I2C 从机控制器

通过i2c_new_slave_device() 安装 i2c slave 驱动程序后,ESP32 就可以作为 slave 与其他 I2C Master 通信了。

I2C 从机写入数据

I2C slave 的 send buffer 用作 FIFO 来存储要发送的数据。数据将排队,直到 主机 请求它们。您可以调用 i2c_slave_transmit()发送数据。

将数据写入 FIFO 的简单示例:

uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH);

i2c_slave_config_t i2c_slv_config = {
    .addr_bit_len = I2C_ADDR_BIT_LEN_7,   // 7-bit address
    .clk_source = I2C_CLK_SRC_DEFAULT,    // set the clock source
    .i2c_port = 0,                        // set I2C port number
    .send_buf_depth = 256,                // set tx buffer length
    .scl_io_num = 2,                      // SCL gpio number
    .sda_io_num = 1,                      // SDA gpio number
    .slave_addr = 0x58,                   // slave address
};

i2c_bus_handle_t i2c_bus_handle;
ESP_ERROR_CHECK(i2c_new_slave_device(&i2c_slv_config, &i2c_bus_handle));
for (int i = 0; i < DATA_LENGTH; i++) {
    data_wr[i] = i;
}

ESP_ERROR_CHECK(i2c_slave_transmit(i2c_bus_handle, data_wr, DATA_LENGTH, 10000));
I2C 从机读取数据

每当 主机 向 从机 写入数据时,从机 会自动将数据存储在接收缓冲区中。这允许从属应用程序自行决定调用函数i2c_slave_receive()。Asi2c_slave_receive() 设计为非阻塞接口。因此,用户需要通过i2c_slave_register_event_callbacks()注册回调函数 才能知道接收何时完成。

static IRAM_ATTR bool i2c_slave_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data)
{
    BaseType_t high_task_wakeup = pdFALSE;
    QueueHandle_t receive_queue = (QueueHandle_t)user_data;
    xQueueSendFromISR(receive_queue, edata, &high_task_wakeup);
    return high_task_wakeup == pdTRUE;
}

uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH);
uint32_t size_rd = 0;

i2c_slave_config_t i2c_slv_config = {
    .addr_bit_len = I2C_ADDR_BIT_LEN_7,
    .clk_source = I2C_CLK_SRC_DEFAULT,
    .i2c_port = TEST_I2C_PORT,
    .send_buf_depth = 256,
    .scl_io_num = I2C_SLAVE_SCL_IO,
    .sda_io_num = I2C_SLAVE_SDA_IO,
    .slave_addr = 0x58,
};

i2c_slave_dev_handle_t slave_handle;
ESP_ERROR_CHECK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));

s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t));
i2c_slave_event_callbacks_t cbs = {
    .on_recv_done = i2c_slave_rx_done_callback,
};
ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue));

i2c_slave_rx_done_event_data_t rx_data;
ESP_ERROR_CHECK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH));
xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(10000));
// Receive done.

注册事件回调

I2C 主机回调

当 I2C 主总线触发中断时,将生成特定事件并通知 CPU。如果有一些函数需要在这些事件发生时调用,则可以通过调用 i2c_master_register_event_callbacks()将函数挂接到 ISR(中断服务例程)。由于注册的回调函数是在中断上下文中调用的,因此用户应确保回调函数不会尝试阻塞(例如,确保仅从函数内部调用带有后缀的 FreeRTOS API)。回调函数需要返回一个布尔值,以告诉 ISR 是否唤醒了高优先级任务。ISR

I2C 主事件回调在i2c_master_event_callbacks_t.

虽然 I2C 是一种同步通信协议,但我们也通过注册上述回调来支持异步行为。这样,I2C API 将成为非阻塞接口。但需要注意的是,在同一条总线上,只有一个设备可以采用异步作。

注意:

I2C 主机异步事务仍然是一个实验性功能。(问题是当异步事务非常大时,会导致内存问题。)

I2C 从机回调

当 I2C 从总线触发中断时,将生成特定事件并通知 CPU。如果有一些函数需要在这些事件发生时调用,则可以通过调用 i2c_slave_register_event_callbacks()将函数挂接到 ISR(中断服务例程)。由于注册的回调函数是在中断上下文中调用的,因此用户应确保回调函数不会尝试阻塞(例如,确保仅从函数内部调用带有后缀的 FreeRTOS API)。回调函数有一个布尔返回值,用于告诉调用者是否唤醒了高优先级任务。ISR

I2C 从事件回调在 i2c_slave_event_callbacks_t.中列出。

  • i2c_slave_event_callbacks_t::on_recv_done为 “receive-done” 事件设置回调函数。函数原型在i2c_slave_received_callback_t. 中声明。

主机 API 参考

头文件

#include "driver/i2c_master.h"

需要再CMakeLists.txt添加

REQUIRES driver

PRIV_REQUIRES driver

功能函数

分配 I2C 主总线
esp_err_t i2c_new_master_bus(const i2c_master_bus_config_t *bus_config, i2c_master_bus_handle_t *ret_bus_handle)

参数

  • bus_config[in] I2C 主总线配置。

  • ret_bus_handle[out] I2C 总线手柄

返回

  • ESP_OK:I2C 主总线初始化成功。

  • ESP_ERR_INVALID_ARG:由于参数无效,I2C 总线初始化失败。

  • ESP_ERR_NO_MEM:由于 内存不足,创建 I2C 总线失败。

  • ESP_ERR_NOT_FOUND:不再有免费巴士。

添加 I2C 主 BUS 设备
esp_err_t i2c_master_bus_add_device(i2c_master_bus_handle_t bus_handle、const i2c_device_config_t *dev_config、i2c_master_dev_handle_t *ret_handle)

参数

  • bus_handle[in] I2C 总线手柄。

  • dev_config[in] 设备配置。

  • ret_handle[out] 设备句柄。

返回

  • ESP_OK:成功创建 I2C 主设备。

  • ESP_ERR_INVALID_ARG:由于参数无效,I2C 总线初始化失败。

  • ESP_ERR_NO_MEM:由于 内存不足,创建 I2C 总线失败。

取消初始化 I2C 主总线并删除句柄
esp_err_t i2c_del_master_bus(i2c_master_bus_handle_t bus_handle)

参数

  • bus_handle[in] I2C 总线手柄。

返回

  • ESP_OK:删除 I2C 总线成功,否则失败。

  • 其他:某些模块删除失败。

I2C 主总线删除设备
esp_err_t i2c_master_bus_rm_device(i2c_master_dev_handle_t handle)

参数

  • handle – I2C 设备句柄

返回

  • ESP_OK:如果设备删除成功。
I2C 主机发送数据
esp_err_t i2c_master_transmit(i2c_master_dev_handle_t i2c_dev、const uint8_t *write_buffer、size_t write_size、int xfer_timeout_ms)

参数

  • i2c_dev – 由 创建的 I2C 主器件句柄。i2c_master_bus_add_device

  • write_buffer[in] 在 I2C 总线上发送的数据字节。

  • write_size[in] 写缓冲区的大小 (以字节为单位)。

  • xfer_timeout_ms[in] 等待超时,以毫秒为单位。注意:-1 表示永远等待。

返回

  • ESP_OK:I2C 主站发送成功

  • ESP_ERR_INVALID_ARG:I2C 主控发送参数无效。

  • ESP_ERR_TIMEOUT:由于总线繁忙或硬件崩溃,作超时(大于 xfer_timeout_ms)。

注意:

  1. 如果 回调已注册 ,则事务将是异步的,因此,此函数将直接返回,而不会阻塞。您将从 callback 获得完成信息。此外,注册 callback 时,数据缓冲区应始终准备好,否则会导致数据损坏。i2c_master_register_event_callbacks
  2. 在 I2C 总线上执行写入事务。事务将一直进行,直到完成或达到提供的超时。
I2C 主机发送 /接收 数据
esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, uint8_t *read_buffer、size_t read_size、int xfer_timeout_ms)

参数

  • i2c_dev – 由 创建的 I2C 主器件句柄。i2c_master_bus_add_device

  • write_buffer[in] 在 I2C 总线上发送的数据字节。

  • write_size[in] 写缓冲区的大小 (以字节为单位)。

  • read_buffer[out] 从 i2c 总线接收到的数据字节。

  • read_size[in] 读取缓冲区的大小 (以字节为单位)。

  • xfer_timeout_ms[in] 等待超时,以毫秒为单位。注意:-1 表示永远等待。

返回

  • ESP_OK:I2C 主站发送-接收成功

  • ESP_ERR_INVALID_ARG:I2C 主控发送参数无效。

  • ESP_ERR_TIMEOUT:由于总线繁忙或硬件崩溃,作超时(大于 xfer_timeout_ms)。

注意:

  1. 如果 回调已注册 ,则事务将是异步的,因此,此函数将直接返回,而不会阻塞。您将从 callback 获得完成信息。此外,注册 callback 时,数据缓冲区应始终准备好,否则会导致数据损坏。i2c_master_register_event_callbacks
  2. 在 I2C 总线上执行 write-read transaction 。事务将一直进行,直到完成或达到提供的超时。
I2C 主机接收数据
esp_err_t i2c_master_receive(i2c_master_dev_handle_t i2c_dev、uint8_t *read_buffer、size_t read_size、int xfer_timeout_ms)

参数

  • i2c_dev – 由 创建的 I2C 主器件句柄。i2c_master_bus_add_device

  • read_buffer[out] 从 i2c 总线接收到的数据字节。

  • read_size[in] 读取缓冲区的大小 (以字节为单位)。

  • xfer_timeout_ms[in] 等待超时,以毫秒为单位。注意:-1 表示永远等待。

返回* ESP_OK:I2C 主站接收成功

  • ESP_ERR_INVALID_ARG:I2C 主接收参数无效。
  • ESP_ERR_TIMEOUT:由于总线繁忙或硬件崩溃,作超时(大于

注意:

  1. 如果 回调已注册 ,则事务将是异步的,因此,此函数将直接返回,而不会阻塞。您将从 callback 获得完成信息。此外,注册 callback 时,数据缓冲区应始终准备好,否则会导致数据损坏。i2c_master_register_event_callbacks
  2. 在 I2C 总线上执行读取事务。事务将一直进行,直到完成或达到提供的超时。
探测 I2C 地址
esp_err_t i2c_master_probe(i2c_master_bus_handle_t bus_handle、uint16_t address、int xfer_timeout_ms)

参数

  • bus_handle – 由 创建的 I2C 主器件句柄。i2c_master_bus_add_device

  • address – 要探测的 I2C 设备地址。

  • xfer_timeout_ms[in] 等待超时,以毫秒为单位。注意:-1 表示永远等待(此功能不推荐)。

返回* ESP_OK:I2C 器件探测成功

  • ESP_ERR_NOT_FOUND: I2C 探测失败,找不到您提供的特定地址的设备。
  • ESP_ERR_TIMEOUT:由于总线繁忙或硬件崩溃,作超时(大于 xfer_timeout_ms)。

注意:

  1. 探测 I2C 地址,如果地址正确且收到 ACK,则此函数将返回 ESP_OK。
  2. 调用此函数时,上拉电阻必须连接到 SCL 和 SDA 引脚。
  3. 此功能的原理是通过 write 命令发送设备地址。如果器件位于 I2C 总线上,则会出现 ACK 信号,并且函数返回。如果器件不在您的 I2C 总线上,则会有 NACK 信号并且函数返回。 不是预期的故障,这表明 I2C 探针工作不正常,通常是上拉电阻没有正确连接造成的。建议检查 SDA/SCL 线路上的数据,当 i2c 探测功能失败时,查看是否有 ACK/NACK 信号在线。
  4. 世界上有很多 I2C 设备,我们假设并非所有 I2C 设备都支持这样的行为。因此,如果在线数据很奇怪并且没有 ack/nack 得到响应。请查看器件数据表。device_address+nack/ack
为主设备注册 I2C 事务回调
esp_err_t i2c_master_register_event_callbacks(i2c_master_dev_handle_t i2c_dev, const i2c_master_event_callbacks_t *cbs, void *user_data)

参数

  • i2c_dev – 由 创建的 I2C 主器件句柄。i2c_master_bus_add_device

  • cbs[in] 回调函数组

  • user_data[in] 用户数据,将直接传递给回调函数

返回* ESP_OK:成功设置 I2C 事务回调

  • ESP_ERR_INVALID_ARG:设置 I2C 事务回调因参数无效而失败
  • ESP_FAIL:设置I2C事务回调因其他错误而失败

注意:

  1. 用户可以通过调用此函数并将结构中的回调成员设置为 NULL 来取消注册以前注册的回调。
  2. 启用 CONFIG_I2C_ISR_IRAM_SAFE 后,回调本身及其调用的函数应放置在 IRAM 中。函数中使用的变量也应该在 SRAM 中。也应驻留在 SRAM 中。
  3. 如果该回调用于帮助异步事务。在同一总线上,只有一个设备可用于执行异步作。
重置 I2C 主总线
esp_err_t i2c_master_bus_reset(i2c_master_bus_handle_t bus_handle)

参数

  • bus_handle – I2C 总线手柄。

返回* ESP_OK:重置成功。

  • ESP_ERR_INVALID_ARG:I2C 主总线手柄未初始化。
  • 否则:重置失败。
等待所有待处理的 I2C 事务完成
esp_err_t i2c_master_bus_wait_all_done(i2c_master_bus_handle_t bus_handle, int timeout_ms)

参数* bus_handle[in] I2C 总线手柄

  • timeout_ms[in] 等待超时,以毫秒为单位。特别是,-1 表示永远等待。

返回* ESP_OK:刷新交易成功

  • ESP_ERR_INVALID_ARG:由于参数无效,刷新事务失败
  • ESP_ERR_TIMEOUT:由于超时,刷新事务失败
  • ESP_FAIL:由于其他错误,刷新事务失败
检索指定 I2C 端口号的 I2C 主总线句柄
esp_err_t i2c_master_get_bus_handle(i2c_port_num_t port_num, i2c_master_bus_handle_t *ret_handle)

参数

  • port_num – 要检索其句柄的 I2C 端口号。

  • ret_handle – 指向将存储检索到的句柄的变量的指针。

返回* ESP_OK:成功。已成功检索 handle。

  • ESP_ERR_INVALID_ARG:参数无效,例如端口号无效
  • ESP_ERR_INVALID_STATE:无效状态,例如 I2C 端口未初始化。

注意:

此函数检索给定 I2C 端口号的 I2C 主总线句柄。请确保 handle 已初始化,此函数将仅返回现有 handle。请注意,返回的 handle 仍然不能并发使用

从机 API参考

头文件

#include "driver/i2c_slave.h"

功能函数

I2C 从设备初始化
esp_err_t i2c_new_slave_device(const i2c_slave_config_t *slave_config, i2c_slave_dev_handle_t *ret_handle)

初始化 I2C 从设备。

参数

  • slave_config[in] I2C 从器件配置

  • ret_handle[out] 返回通用 I2C 器件句柄

返回* ESP_OK:I2C 从设备初始化成功

  • ESP_ERR_INVALID_ARG:由于参数无效,I2C 设备初始化失败。
  • ESP_ERR_NO_MEM:由于内存不足,创建 I2C 设备失败。
I2C 从设备 取消初始化
esp_err_t i2c_del_slave_device(i2c_slave_dev_handle_t i2c_slave)

参数

  • i2c_slave – 由 创建的 I2C 从器件句柄。i2c_new_slave_device

返回* ESP_OK:成功删除 I2C 设备。

  • ESP_ERR_INVALID_ARG:由于参数无效,I2C 设备初始化失败。
I2C 从机 从内部缓冲区读取字节。

启动作业以接收 I2C 数据。

esp_err_t i2c_slave_receive(i2c_slave_dev_handle_t i2c_slave、uint8_t *data、size_t buffer_size)

参数

  • i2c_slave – 由 创建的 I2C 从器件句柄。i2c_new_slave_device

  • data – [out] 用于存储来自 I2C fifo 的数据的缓冲区。在 触发 之前 应有效。on_recv_done

  • buffer_size[in] 用户提供的数据的缓冲区大小。

返回* ESP_OK: I2C slave 接收成功。

  • ESP_ERR_INVALID_ARG:I2C slave 接收参数无效。
  • ESP_ERR_NOT_SUPPORTED:此功能应在 fifo 模式下工作,但配置了 I2C_SLAVE_NONFIFO 模式

注意:

此函数是非阻塞的,它启动新的接收作业,然后返回。用户应检查从 注册的回调中接收到的数据。on_recv_donei2c_slave_register_event_callbacks()

I2C 从机发送数据
esp_err_t i2c_slave_transmit(i2c_slave_dev_handle_t i2c_slave, const uint8_t *data, int size, int xfer_timeout_ms)

参数

  • i2c_slave – 由 创建的 I2C 从器件句柄。i2c_new_slave_device

  • data – [in] 写入 slave fifo 的缓冲区,可以由 master 拾取。可以在此函数返回后释放。等于或大于 。size

  • size – [in] 缓冲区的字节数。data

  • xfer_timeout_ms[in] 等待超时,以毫秒为单位。注意:-1 表示永远等待。

返回* ESP_OK:I2C slave 发送成功。

  • ESP_ERR_INVALID_ARG:I2C slave 发送参数无效。
  • ESP_ERR_TIMEOUT:设备繁忙或硬件崩溃导致作超时(大于 xfer_timeout_ms)。
  • ESP_ERR_NOT_SUPPORTED:此功能应在 fifo 模式下工作,但配置了 I2C_SLAVE_NONFIFO 模式

注意:

  1. 将字节写入 I2C slave 数据的内部 ringbuffer。当 TX fifo 为空时, ISR 将用内部 ringbuffer 的数据填充硬件 FIFO。
  2. 如果将此 Slave 设备连接到某个 Master 设备,则数据事务方向是从 Slave 设备到 Master 设备。
为 I2C slave 通道设置 I2C slave 事件回调
esp_err_t i2c_slave_register_event_callbacks(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_event_callbacks_t *cbs, void *user_data)

参数

  • i2c_slave – 由 创建的 I2C 从器件句柄。i2c_new_slave_device

  • cbs[in] 回调函数组

  • user_data[in] 用户数据,将直接传递给回调函数

返回* ESP_OK:成功设置 I2C 事务回调

  • ESP_ERR_INVALID_ARG:设置 I2C 事务回调因参数无效而失败
  • ESP_FAIL:设置I2C事务回调因其他错误而失败

注意

  1. 用户可以通过调用此函数并将结构中的回调成员设置为 NULL 来取消注册以前注册的回调。cbs
  2. 启用 CONFIG_I2C_ISR_IRAM_SAFE 后,回调本身及其调用的函数应放置在 IRAM 中。函数中使用的变量也应该在 SRAM 中。也应驻留在 SRAM 中。user_data
http://www.dtcms.com/a/108231.html

相关文章:

  • Scala基础知识5
  • react中hooks使用
  • 关于mysql 数据库中的 慢SQL 的详细分析,包括定义、原因、解决方法及表格总结
  • 【数字化转型,企业应用上云】---持续集成能力重塑企业软件交付新范式
  • 【node-forge】加解密(RSA),代替node-rsa
  • 洛谷题单3-P5721 【深基4.例6】数字直角三角形-python-流程图重构
  • 在Docker中快速部署Redis:从零开始到生产环境配置指南
  • stack栈的基本使用-c++
  • 23种设计模式-结构型模式-享元
  • 在未归一化的线性回归模型中,特征的尺度差异可能导致模型对特征重要性的误判
  • 墨笔 在线Markdown 编辑器
  • VAE讲解
  • PyTorch中卷积层torch.nn.Conv2d
  • Android 切换prefer APN后建立PDN的日志分析
  • ubuntu改用户权限
  • AI调研 | Omnisql模型家族调研与实测
  • ‌Windows 与 Linux网络命令速查表,含常用场景及参数说明
  • 使用高德api实现天气查询
  • 多电机显示并排序
  • WHAT - 如何理解中间件
  • WPF学习路线
  • 关于Gstreamer+MPP硬件加速推流问题:视频输入video0被占用
  • MYSQL实现获取某个经纬度区域内的数据
  • Cesium系列:从入门到实践,打造属于你的3D地球应用
  • 为 Jenkins Agent 添加污点(Taint)容忍度(Toleration)
  • Dubbo分布式框架学习(1)
  • vue省市区懒加载,用el-cascader 新增和回显
  • 多模态大模型笔记
  • Compressed串行端口终端应用程序(MAC 、WIN、LINUX)打包下载
  • 高级java每日一道面试题-2025年3月19日-Web篇-防止表单重复提交的方法有哪些?