【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))。0i2c_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_address
I2C 设备原始地址。请直接解析该成员的设备地址。例如,设备地址为 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)。
注意:
- 如果 回调已注册 ,则事务将是异步的,因此,此函数将直接返回,而不会阻塞。您将从 callback 获得完成信息。此外,注册 callback 时,数据缓冲区应始终准备好,否则会导致数据损坏。
i2c_master_register_event_callbacks
- 在 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)。
注意:
- 如果 回调已注册 ,则事务将是异步的,因此,此函数将直接返回,而不会阻塞。您将从 callback 获得完成信息。此外,注册 callback 时,数据缓冲区应始终准备好,否则会导致数据损坏。
i2c_master_register_event_callbacks
- 在 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:由于总线繁忙或硬件崩溃,作超时(大于
注意:
- 如果 回调已注册 ,则事务将是异步的,因此,此函数将直接返回,而不会阻塞。您将从 callback 获得完成信息。此外,注册 callback 时,数据缓冲区应始终准备好,否则会导致数据损坏。
i2c_master_register_event_callbacks
- 在 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)。
注意:
- 探测 I2C 地址,如果地址正确且收到 ACK,则此函数将返回 ESP_OK。
- 调用此函数时,上拉电阻必须连接到 SCL 和 SDA 引脚。
- 此功能的原理是通过 write 命令发送设备地址。如果器件位于 I2C 总线上,则会出现 ACK 信号,并且函数返回。如果器件不在您的 I2C 总线上,则会有 NACK 信号并且函数返回。 不是预期的故障,这表明 I2C 探针工作不正常,通常是上拉电阻没有正确连接造成的。建议检查 SDA/SCL 线路上的数据,当 i2c 探测功能失败时,查看是否有 ACK/NACK 信号在线。
- 世界上有很多 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事务回调因其他错误而失败
注意:
- 用户可以通过调用此函数并将结构中的回调成员设置为 NULL 来取消注册以前注册的回调。
- 启用 CONFIG_I2C_ISR_IRAM_SAFE 后,回调本身及其调用的函数应放置在 IRAM 中。函数中使用的变量也应该在 SRAM 中。也应驻留在 SRAM 中。
- 如果该回调用于帮助异步事务。在同一总线上,只有一个设备可用于执行异步作。
重置 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 模式
注意:
- 将字节写入 I2C slave 数据的内部 ringbuffer。当 TX fifo 为空时, ISR 将用内部 ringbuffer 的数据填充硬件 FIFO。
- 如果将此 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事务回调因其他错误而失败
注意
- 用户可以通过调用此函数并将结构中的回调成员设置为 NULL 来取消注册以前注册的回调。
cbs
- 启用 CONFIG_I2C_ISR_IRAM_SAFE 后,回调本身及其调用的函数应放置在 IRAM 中。函数中使用的变量也应该在 SRAM 中。也应驻留在 SRAM 中。
user_data