|
|
@@ -1,408 +1,548 @@
|
|
|
Inter-Integrated Circuit (I2C)
|
|
|
==============================
|
|
|
|
|
|
-:link_to_translation:`zh_CN:[中文]`
|
|
|
+Introduction
|
|
|
+------------
|
|
|
|
|
|
-Overview
|
|
|
---------
|
|
|
+I2C is a serial, synchronous, multi-device, half-duplex communication protocol that allows co-existence of multiple masters and slaves on the same bus. I2C uses two bidirectional open-drain lines: serial data line (SDA) and serial clock line (SCL), pulled up by resistors.
|
|
|
|
|
|
-I2C is a serial, synchronous, half-duplex communication protocol that allows co-existence of multiple masters and slaves on the same bus. The I2C bus consists of two lines: serial data line (SDA) and serial clock (SCL). Both lines require pull-up resistors.
|
|
|
+{IDF_TARGET_NAME} has {IDF_TARGET_SOC_I2C_NUM} I2C controller (also called port), responsible for handling communication on the I2C bus. A single I2C controller can be a master or a slave.
|
|
|
|
|
|
-With such advantages as simplicity and low manufacturing cost, I2C is mostly used for communication of low-speed peripheral devices over short distances (within one foot).
|
|
|
+Typically, an I2C slave device has a 7-bit address or 10-bit address. {IDF_TARGET_NAME} supports both I2C Standard-mode (Sm) and Fast-mode (Fm) which can go up to 100KHz and 400KHz respectively.
|
|
|
|
|
|
-{IDF_TARGET_NAME} has {IDF_TARGET_SOC_I2C_NUM} I2C controller (also referred to as port), responsible for handling communications on the I2C bus. A single I2C controller can operate as master or slave.
|
|
|
+.. warning::
|
|
|
|
|
|
-Driver Features
|
|
|
----------------
|
|
|
+ The clock frequency of SCL in master mode should not be larger than 400 KHz
|
|
|
|
|
|
-I2C driver governs communications of devices over the I2C bus. The driver supports the following features:
|
|
|
+.. note::
|
|
|
|
|
|
-- Reading and writing bytes in Master mode
|
|
|
+ The frequency of SCL is influenced by both the pull-up resistor and the wire capacitance. Therefore, users are strongly recommended to choose appropriate pull-up resistors to make the frequency accurate. The recommended value for pull-up resistors usually ranges from 1K Ohms to 10K Ohms.
|
|
|
|
|
|
-.. only:: SOC_I2C_SUPPORT_SLAVE
|
|
|
+ Keep in mind that the higher the frequency, the smaller the pull-up resistor should be (but not less than 1 KOhms). Indeed, large resistors will decline the current, which will increase the clock switching time and reduce the frequency. We usually recommend a range of 2 KOhms to 5 KOhms, but users may also need to make some adjustments depending on their current draw requirements.
|
|
|
|
|
|
- - Slave mode
|
|
|
|
|
|
-- Reading and writing to registers which are in turn read/written by the master
|
|
|
+I2C Clock Configuration
|
|
|
+-----------------------
|
|
|
|
|
|
+.. list::
|
|
|
+
|
|
|
+ - :cpp:enumerator:`i2c_clock_source_t::I2C_CLK_SRC_DEFAULT`: Default I2C source clock.
|
|
|
+ :SOC_I2C_SUPPORT_XTAL: - :cpp:enumerator:`i2c_clock_source_t::I2C_CLK_SRC_XTAL`: External crystal for I2C clock source.
|
|
|
+ :SOC_I2C_SUPPORT_RTC: - :cpp:enumerator:`i2c_clock_source_t::I2C_CLK_RC_FAST`: Internal 20MHz rc oscillator for I2C clock source.
|
|
|
+ :SOC_I2C_SUPPORT_APB: - :cpp:enumerator:`i2c_clock_source_t::I2C_CLK_SRC_APB`: APB clock as I2C clock source.
|
|
|
+ :SOC_I2C_SUPPORT_REF_TICK: - :cpp:enumerator:`i2c_clock_source_t::I2C_CLK_SRC_REF_TICK`: 1MHZ clock.
|
|
|
|
|
|
-Driver Usage
|
|
|
-------------
|
|
|
+I2C File Structure
|
|
|
+------------------
|
|
|
+
|
|
|
+.. figure:: ../../../_static/diagrams/i2c/i2c_code_structure.png
|
|
|
+ :align: center
|
|
|
+ :alt: I2C file structure
|
|
|
|
|
|
-{IDF_TARGET_I2C_ROLE:default="master or slave", esp32c2="master"}
|
|
|
+ I2C file structure
|
|
|
|
|
|
-The following sections describe typical steps of configuring and operating the I2C driver:
|
|
|
+**Public headers that need to be included in the I2C application**
|
|
|
|
|
|
-1. :ref:`i2c-api-configure-driver` - set the initialization parameters ({IDF_TARGET_I2C_ROLE} mode, GPIO pins for SDA and SCL, clock speed, etc.)
|
|
|
-2. :ref:`i2c-api-install-driver`- activate the driver on one of the two I2C controllers as a {IDF_TARGET_I2C_ROLE}
|
|
|
-3. Depending on whether you configure the driver for a {IDF_TARGET_I2C_ROLE}, choose the appropriate item
|
|
|
+- ``i2c.h``: The header file of legacy I2C APIs (for apps using legacy driver).
|
|
|
+- ``i2c_master.h``: The header file that provides standard communication mode specific APIs (for apps using new driver with master mode).
|
|
|
+- ``i2c_slave.h``: The header file that provides standard communication mode specific APIs (for apps using new driver with slave mode).
|
|
|
|
|
|
- a) :ref:`i2c-api-master-mode` - handle communications (master)
|
|
|
+.. note::
|
|
|
|
|
|
- .. only:: SOC_I2C_SUPPORT_SLAVE
|
|
|
+ The legacy driver can't coexist with the new driver. Include ``i2c.h`` to use the legacy driver or the other two headers to use the new driver. Please keep in mind that the legacy driver is now deprecated and will be removed in future.
|
|
|
|
|
|
- b) :ref:`i2c-api-slave-mode` - respond to messages from the master (slave)
|
|
|
+**Public headers that have been included in the headers above**
|
|
|
|
|
|
-4. :ref:`i2c-api-interrupt-handling` - configure and service I2C interrupts
|
|
|
-5. :ref:`i2c-api-customized-configuration` - adjust default I2C communication parameters (timings, bit order, etc.)
|
|
|
-6. :ref:`i2c-api-error-handling` - how to recognize and handle driver configuration and communication errors
|
|
|
-7. :ref:`i2c-api-delete-driver`- release resources used by the I2C driver when communication ends
|
|
|
+- ``i2c_types_legacy.h``: The legacy public types that only used in the legacy driver.
|
|
|
+- ``i2c_types.h``: The header file that provides public types.
|
|
|
|
|
|
+Functional Overview
|
|
|
+-------------------
|
|
|
|
|
|
-.. _i2c-api-configure-driver:
|
|
|
+The I2C driver offers following services:
|
|
|
|
|
|
-Configuration
|
|
|
-^^^^^^^^^^^^^
|
|
|
+- `Resource Allocation <#resource-allocation>`__ - covers how to allocate I2C bus with properly set of configurations. It also covers how to recycle the resources when they finished working.
|
|
|
+- `I2C Master Controller <#i2c_master_controller>`__ - covers behavior of I2C master controller. Introduce data transmit, data receive, and data transmit and receive.
|
|
|
+- `I2C Slave Controller <#i2c_slave_controller>`__ - covers behavior of I2C slave controller. Involve data transmit and data receive.
|
|
|
+- `Power Management <#power-management>`__ - describes how different source clock will affect power consumption.
|
|
|
+- `IRAM Safe <#iram-safe>`__ - describes tips on how to make the I2C interrupt work better along with a disabled cache.
|
|
|
+- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver.
|
|
|
+- `Kconfig Options <#kconfig-options>`__ - lists the supported Kconfig options that can bring different effects to the driver.
|
|
|
|
|
|
-To establish I2C communication, start by configuring the driver. This is done by setting the parameters of the structure :cpp:type:`i2c_config_t`:
|
|
|
+Resource Allocation
|
|
|
+^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
-- Set I2C **mode of operation** - {IDF_TARGET_I2C_ROLE} from :cpp:type:`i2c_mode_t`
|
|
|
-- Configure **communication pins**
|
|
|
+Both I2C master bus and I2C slave bus, when supported, are represented by :cpp:type:`i2c_bus_handle_t` in the driver. The available ports are managed in a resource pool that allocates a free port on request.
|
|
|
|
|
|
- - Assign GPIO pins for SDA and SCL signals
|
|
|
- - Set whether to enable {IDF_TARGET_NAME}'s internal pull-ups
|
|
|
+Install I2C master bus and device
|
|
|
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-- (Master only) Set I2C **clock speed**
|
|
|
+The I2C master is designed based on bus-device model. So :cpp:type:`i2c_master_bus_config_t` and :cpp:type:`i2c_device_config_t` are required separately to allocate the I2C master bus instance and I2C device instance.
|
|
|
+
|
|
|
+.. figure:: ../../../_static/diagrams/i2c/i2c_master_module.png
|
|
|
+ :align: center
|
|
|
+ :alt: I2C master bus-device module
|
|
|
+
|
|
|
+ I2C master bus-device module
|
|
|
+
|
|
|
+I2C master bus requires the configuration that specified by :cpp:type:`i2c_master_bus_config_t`:
|
|
|
+
|
|
|
+- :cpp:member:`i2c_master_bus_config_t::i2c_port` sets the I2C port used by the controller.
|
|
|
+- :cpp:member:`i2c_master_bus_config_t::sda_io_num` sets the GPIO number for the serial data bus (SDA).
|
|
|
+- :cpp:member:`i2c_master_bus_config_t::scl_io_num` sets the GPIO number for the serial clock bus (SCL).
|
|
|
+- :cpp:member:`i2c_master_bus_config_t::clk_source` selects the source clock for I2C bus. The available clocks are listed in :cpp:type:`i2c_clock_source_t`. For the effect on power consumption of different clock source, please refer to `Power Management <#power-management>`__ section.
|
|
|
+- :cpp:member:`i2c_master_bus_config_t::glitch_ignore_cnt` sets the glitch period of master bus, if the glitch period on the line is less than this value, it can be filtered out, typically value is 7.
|
|
|
+- :cpp:member:`i2c_master_bus_config_t::intr_priority` Set the priority of the interrupt. If set to ``0`` , then the driver will use a interrupt with low or medium priority (priority level may be one of 1,2 or 3), otherwise use the priority indicated by :cpp:member:`i2c_master_bus_config_t::intr_priority` Please use the number form (1,2,3) , not the bitmask form ((1<<1),(1<<2),(1<<3)).
|
|
|
+- :cpp:member:`i2c_master_bus_config_t::trans_queue_depth` Depth of internal transfer queue. Only valid in asynchronous transaction.
|
|
|
+- :cpp:member:`i2c_master_bus_config_t::enable_internal_pullup` Enable internal pullups. Note: This is not strong enough to pullup buses under high-speed frequency. A suitable external pullup is recommended.
|
|
|
|
|
|
-.. only:: SOC_I2C_SUPPORT_SLAVE
|
|
|
|
|
|
- - (Slave only) Configure the following
|
|
|
+If the configurations in :cpp:type:`i2c_master_bus_config_t` is specified, users can call :cpp:func:`i2c_new_master_bus` to allocate and initialize an I2C master bus. This function will return an I2C bus handle if it runs correctly. Specifically, when there are no more I2C port available, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error.
|
|
|
|
|
|
- * Whether to enable **10 bit address mode**
|
|
|
- * Define **slave address**
|
|
|
+I2C master device requires the configuration that specified by :cpp:type:`i2c_device_config_t`:
|
|
|
|
|
|
-After that, initialize the configuration for a given I2C port. For this, call the function :cpp:func:`i2c_param_config` and pass to it the port number and the structure :cpp:type:`i2c_config_t`.
|
|
|
+- :cpp:member:`i2c_device_config_t::dev_addr_length` configure the address bit length of the slave device. User can choose from enumerator :cpp:enumerator:`I2C_ADDR_BIT_LEN_7` or :cpp:enumerator:`I2C_ADDR_BIT_LEN_10` (if supported).
|
|
|
+- :cpp:member:`i2c_device_config_t::device_address` I2C device raw address. Please parse the device address to this member directly. For example, the device address is 0x28, then parse 0x28 to :cpp:member:`i2c_device_config_t::device_address`, don't carry a write/read bit.
|
|
|
+- :cpp:member:`i2c_device_config_t::scl_speed_hz` set the scl line frequency of this device.
|
|
|
|
|
|
-Configuration example (master):
|
|
|
+Once the :cpp:type:`i2c_device_config_t` structure is populated with mandatory parameters, users can call :cpp:func:`i2c_master_bus_add_device` to allocate an I2C device instance and mounted to the master bus then. This function will return an I2C device handle if it runs correctly. Specifically, when the I2C bus is not initialized properly, calling this function will result in a :c:macro:`ESP_ERR_INVALID_ARG` error.
|
|
|
|
|
|
-.. code-block:: c
|
|
|
+.. code:: c
|
|
|
|
|
|
- int i2c_master_port = 0;
|
|
|
- i2c_config_t conf = {
|
|
|
- .mode = I2C_MODE_MASTER,
|
|
|
- .sda_io_num = I2C_MASTER_SDA_IO, // select SDA GPIO specific to your project
|
|
|
- .sda_pullup_en = GPIO_PULLUP_ENABLE,
|
|
|
- .scl_io_num = I2C_MASTER_SCL_IO, // select SCL GPIO specific to your project
|
|
|
- .scl_pullup_en = GPIO_PULLUP_ENABLE,
|
|
|
- .master.clk_speed = I2C_MASTER_FREQ_HZ, // select frequency specific to your project
|
|
|
- .clk_flags = 0, // optional; you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here
|
|
|
+ #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,
|
|
|
};
|
|
|
|
|
|
-.. only:: SOC_I2C_SUPPORT_SLAVE
|
|
|
+ i2c_master_bus_handle_t bus_handle;
|
|
|
+ ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
|
|
|
|
|
- Configuration example (slave):
|
|
|
-
|
|
|
- .. code-block:: c
|
|
|
-
|
|
|
- int i2c_slave_port = I2C_SLAVE_NUM;
|
|
|
- i2c_config_t conf_slave = {
|
|
|
- .sda_io_num = I2C_SLAVE_SDA_IO, // select SDA GPIO specific to your project
|
|
|
- .sda_pullup_en = GPIO_PULLUP_ENABLE,
|
|
|
- .scl_io_num = I2C_SLAVE_SCL_IO, // select SCL GPIO specific to your project
|
|
|
- .scl_pullup_en = GPIO_PULLUP_ENABLE,
|
|
|
- .mode = I2C_MODE_SLAVE,
|
|
|
- .slave.addr_10bit_en = 0,
|
|
|
- .slave.slave_addr = ESP_SLAVE_ADDR, // slave address of your project
|
|
|
- .slave.maximum_speed = I2C_SLAVE_MAX_SPEED // expected maximum clock speed
|
|
|
- .clk_flags = 0, // optional; you can use I2C_SCLK_SRC_FLAG_* flags to choose I2C source clock here
|
|
|
- };
|
|
|
+ i2c_device_config_t dev_cfg = {
|
|
|
+ .dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
|
|
+ .device_address = 0x58,
|
|
|
+ .scl_speed_hz = 100000,
|
|
|
+ };
|
|
|
|
|
|
-At this stage, :cpp:func:`i2c_param_config` also sets a few other I2C configuration parameters to default values that are defined by the I2C specification. For more details on the values and how to modify them, see :ref:`i2c-api-customized-configuration`.
|
|
|
+ i2c_master_dev_handle_t dev_handle;
|
|
|
+ ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
|
|
|
|
|
-Source Clock Configuration
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
+Uninstall I2C master bus and device
|
|
|
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-**Clock sources allocator** is added for supporting different clock sources. The clock allocator will choose one clock source that meets all the requirements of frequency and capability (as requested in :cpp:member:`i2c_config_t::clk_flags`).
|
|
|
+If a previously installed I2C bus or device is no longer needed, it's recommended to recycle the resource by calling :cpp:func:`i2c_master_bus_rm_device` or :cpp:func:`i2c_del_master_bus`, so that to release the underlying hardware.
|
|
|
|
|
|
-When :cpp:member:`i2c_config_t::clk_flags` is 0, the clock allocator will select only according to the desired frequency. If no special capabilities are needed, such as APB, you can configure the clock allocator to select the source clock only according to the desired frequency. For this, set :cpp:member:`i2c_config_t::clk_flags` to 0. For clock characteristics, see the table below.
|
|
|
+Install I2C slave device
|
|
|
+~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-.. note::
|
|
|
+I2C slave requires the configuration that specified by :cpp:type:`i2c_slave_config_t`:
|
|
|
|
|
|
- A clock is not a valid option, if it does not meet the requested capabilities, i.e., any bit of requested capabilities (clk_flags) is 0 in the clock's capabilities.
|
|
|
-
|
|
|
-.. only:: esp32
|
|
|
-
|
|
|
- .. list-table:: Characteristics of {IDF_TARGET_NAME} clock sources
|
|
|
- :widths: 5 5 50 20
|
|
|
- :header-rows: 1
|
|
|
-
|
|
|
- * - Clock name
|
|
|
- - Clock frequency
|
|
|
- - MAX freq for SCL
|
|
|
- - Clock capabilities
|
|
|
- * - APB clock
|
|
|
- - 80 MHz
|
|
|
- - 4 MHz
|
|
|
- - /
|
|
|
-
|
|
|
-.. only:: esp32s2
|
|
|
-
|
|
|
- .. list-table:: Characteristics of {IDF_TARGET_NAME} clock sources
|
|
|
- :widths: 5 5 50 100
|
|
|
- :header-rows: 1
|
|
|
-
|
|
|
- * - Clock name
|
|
|
- - Clock frequency
|
|
|
- - MAX freq for SCL
|
|
|
- - Clock capabilities
|
|
|
- * - APB clock
|
|
|
- - 80 MHz
|
|
|
- - 4 MHz
|
|
|
- - /
|
|
|
- * - REF_TICK
|
|
|
- - 1 MHz
|
|
|
- - 50 KHz
|
|
|
- - :c:macro:`I2C_SCLK_SRC_FLAG_AWARE_DFS`, :c:macro:`I2C_SCLK_SRC_FLAG_LIGHT_SLEEP`
|
|
|
-
|
|
|
- Explanations for :cpp:member:`i2c_config_t::clk_flags` are as follows:
|
|
|
- 1. :c:macro:`I2C_SCLK_SRC_FLAG_AWARE_DFS`: Clock's baud rate will not change while APB clock is changing.
|
|
|
- 2. :c:macro:`I2C_SCLK_SRC_FLAG_LIGHT_SLEEP`: It supports Light-sleep mode, which APB clock cannot do.
|
|
|
-
|
|
|
-.. only:: esp32s3
|
|
|
-
|
|
|
- .. list-table:: Characteristics of {IDF_TARGET_NAME} clock sources
|
|
|
- :widths: 5 5 50 20
|
|
|
- :header-rows: 1
|
|
|
-
|
|
|
- * - Clock name
|
|
|
- - Clock frequency
|
|
|
- - MAX freq for SCL
|
|
|
- - Clock capabilities
|
|
|
- * - XTAL clock
|
|
|
- - 40 MHz
|
|
|
- - 2 MHz
|
|
|
- - /
|
|
|
- * - RTC clock
|
|
|
- - 20 MHz
|
|
|
- - 1 MHz
|
|
|
- - :c:macro:`I2C_SCLK_SRC_FLAG_AWARE_DFS`, :c:macro:`I2C_SCLK_SRC_FLAG_LIGHT_SLEEP`
|
|
|
-
|
|
|
-.. only:: esp32c3
|
|
|
-
|
|
|
- .. list-table:: Characteristics of {IDF_TARGET_NAME} clock sources
|
|
|
- :widths: 5 5 50 100
|
|
|
- :header-rows: 1
|
|
|
-
|
|
|
- * - Clock name
|
|
|
- - Clock frequency
|
|
|
- - MAX freq for SCL
|
|
|
- - Clock capabilities
|
|
|
- * - XTAL clock
|
|
|
- - 40 MHz
|
|
|
- - 2 MHz
|
|
|
- - /
|
|
|
- * - RTC clock
|
|
|
- - 20 MHz
|
|
|
- - 1 MHz
|
|
|
- - :c:macro:`I2C_SCLK_SRC_FLAG_AWARE_DFS`, :c:macro:`I2C_SCLK_SRC_FLAG_LIGHT_SLEEP`
|
|
|
-
|
|
|
-Explanations for :cpp:member:`i2c_config_t::clk_flags` are as follows:
|
|
|
-
|
|
|
-1. :c:macro:`I2C_SCLK_SRC_FLAG_AWARE_DFS`: Clock's baud rate will not change while APB clock is changing.
|
|
|
-2. :c:macro:`I2C_SCLK_SRC_FLAG_LIGHT_SLEEP`: It supports Light-sleep mode, which APB clock cannot do.
|
|
|
-3. Some flags may not be supported on {IDF_TARGET_NAME}, reading technical reference manual before using it.
|
|
|
+.. list::
|
|
|
|
|
|
-.. note::
|
|
|
+ - :cpp:member:`i2c_slave_config_t::i2c_port` sets the I2C port used by the controller.
|
|
|
+ - :cpp:member:`i2c_slave_config_t::sda_io_num` sets the GPIO number for serial data bus (SDA).
|
|
|
+ - :cpp:member:`i2c_slave_config_t::scl_io_num` sets the GPIO number for serial clock bus (SCL).
|
|
|
+ - :cpp:member:`i2c_slave_config_t::clk_source` selects the source clock for I2C bus. The available clocks are listed in :cpp:type:`i2c_clock_source_t`. For the effect on power consumption of different clock source, please refer to `Power Management <#power-management>`__ section.
|
|
|
+ - :cpp:member:`i2c_slave_config_t::send_buf_depth` sets the sending buffer length.
|
|
|
+ - :cpp:member:`i2c_slave_config_t::slave_addr` sets the slave address
|
|
|
+ - :cpp:member:`i2c_master_bus_config_t::intr_priority` Set the priority of the interrupt. If set to ``0`` , then the driver will use a interrupt with low or medium priority (priority level may be one of 1,2 or 3), otherwise use the priority indicated by :cpp:member:`i2c_master_bus_config_t::intr_priority` Please use the number form (1,2,3) , not the bitmask form ((1<<1),(1<<2),(1<<3)). Please pay attention that once the interrupt priority is set, it cannot be changed until :cpp:func:`i2c_del_master_bus` is called.
|
|
|
+ - :cpp:member:`i2c_slave_config_t::addr_bit_len` sets true if you need the slave to have a 10-bit address.
|
|
|
+ :SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE: - :cpp:member:`i2c_slave_config_t::stretch_en` Set true if you want the slave controller stretch works, please refer to [`TRM <{IDF_TARGET_TRM_EN_URL}#i2c>`__] to learn how I2C stretch works.
|
|
|
+ :SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE: - :cpp:member:`i2c_slave_config_t::broadcast_en` Set true to enable the slave broadcase. When the slave receives the general call address 0x00 from the master and the R/W bit followed is 0, it responds to the master regardless of its own address.
|
|
|
+ :SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS: - :cpp:member:`i2c_slave_config_t::access_ram_en` Set true to enable the non-fifo mode. Thus the I2C data fifo can be used as RAM, and double addressing will be synchronised opened.
|
|
|
+ :SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH: - :cpp:member:`i2c_slave_config_t::slave_unmatch_en` Set true to enable the slave unmatch interrupt. If master send command address cannot match the slave address, and unmatch interrupt will be triggered.
|
|
|
|
|
|
- The clock frequency of SCL in master mode should not be lager than max frequency for SCL mentioned in the table above.
|
|
|
+Once the :cpp:type:`i2c_slave_config_t` structure is populated with mandatory parameters, users can call :cpp:func:`i2c_new_slave_device` to allocate and initialize an I2C master bus. This function will return an I2C bus handle if it runs correctly. Specifically, when there are no more I2C port available, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error.
|
|
|
|
|
|
-.. note::
|
|
|
+.. code:: c
|
|
|
|
|
|
- The clock frequency of SCL is influenced by the pull-up resistors and wire capacitance (or might slave capacitance) together. Therefore, users need to choose correct pull-up resistors by themselves to make the frequency accurate. It is recommended by I2C protocol that the pull-up resistors commonly range from 1KOhms to 10KOhms, but different frequencies need different resistors.
|
|
|
+ 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,
|
|
|
+ };
|
|
|
|
|
|
- Generally speaking, the higher frequency is selected, the smaller resistor should be used (but not less than 1KOhms). This is because high resistor declines the current, which will lengthen the rising time and reduce the frequency. Usually, range 2KOhms to 5KOhms is what we recommend, but users also might need to make some adjustment depends on their reality.
|
|
|
+ i2c_slave_dev_handle_t slave_handle;
|
|
|
+ ESP_ERROR_CHECK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
|
|
|
|
|
-.. _i2c-api-install-driver:
|
|
|
+Uninstall I2C slave device
|
|
|
+~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-Install Driver
|
|
|
-^^^^^^^^^^^^^^
|
|
|
+If a previously installed I2C bus is no longer needed, it's recommended to recycle the resource by calling :cpp:func:`i2c_del_slave_device`, so that to release the underlying hardware.
|
|
|
|
|
|
-After the I2C driver is configured, install it by calling the function :cpp:func:`i2c_driver_install` with the following parameters:
|
|
|
|
|
|
-- Port number, one of the two port numbers from :cpp:type:`i2c_port_t`
|
|
|
-- {IDF_TARGET_I2C_ROLE}, selected from :cpp:type:`i2c_mode_t`
|
|
|
+I2C Master Controller
|
|
|
+^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
-.. only:: SOC_I2C_SUPPORT_SLAVE
|
|
|
+After installing the i2c master driver by :cpp:func:`i2c_new_master_bus`, {IDF_TARGET_NAME} is ready to communicate with other I2C devices. I2C APIs allow the standard transactions. Like the wave as follows:
|
|
|
+
|
|
|
+.. wavedrom:: /../_static/diagrams/i2c/i2c_trans_wave.json
|
|
|
|
|
|
- - (Slave only) Size of buffers to allocate for sending and receiving data. As I2C is a master-centric bus, data can only go from the slave to the master at the master's request. Therefore, the slave usually has a send buffer where the slave application writes data. The data remains in the send buffer to be read by the master at the master's own discretion.
|
|
|
+I2C Master Write
|
|
|
+~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-- Flags for allocating the interrupt (see ESP_INTR_FLAG_* values in :component_file:`esp_hw_support/include/esp_intr_alloc.h`)
|
|
|
+After installing I2C master bus successfully, you can simply call :cpp:func:`i2c_master_transmit` to write data to the slave device. The principle of this function can be explained by following chart.
|
|
|
|
|
|
-.. _i2c-api-master-mode:
|
|
|
+In order to organize the process, the driver uses a command link, that should be populated with a sequence of commands and then passed to I2C controller for execution.
|
|
|
|
|
|
-Communication as Master
|
|
|
-^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
+.. figure:: ../../../_static/diagrams/i2c/i2c_master_write_slave.png
|
|
|
+ :align: center
|
|
|
+ :alt: I2C master write to slave
|
|
|
+
|
|
|
+ I2C master write to slave
|
|
|
|
|
|
-After installing the I2C driver, {IDF_TARGET_NAME} is ready to communicate with other I2C devices.
|
|
|
+Simple example for writing data to slave:
|
|
|
|
|
|
-{IDF_TARGET_NAME}'s I2C controller operating as master is responsible for establishing communication with I2C slave devices and sending commands to trigger a slave to action, for example, to take a measurement and send the readings back to the master.
|
|
|
+.. code:: c
|
|
|
|
|
|
-For better process organization, the driver provides a container, called a "command link", that should be populated with a sequence of commands and then passed to the I2C controller for execution.
|
|
|
+ #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,
|
|
|
+ };
|
|
|
|
|
|
-Master Write
|
|
|
-""""""""""""
|
|
|
+ i2c_master_dev_handle_t dev_handle;
|
|
|
+ ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
|
|
|
|
|
-The example below shows how to build a command link for an I2C master to send *n* bytes to a slave.
|
|
|
+ ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1));
|
|
|
|
|
|
-.. blockdiag:: ../../../_static/diagrams/i2c-command-link-master-write-blockdiag.diag
|
|
|
- :scale: 100
|
|
|
- :caption: I2C command link - master write example
|
|
|
+I2C Master Read
|
|
|
+~~~~~~~~~~~~~~~
|
|
|
+
|
|
|
+After installing I2C master bus successfully, you can simply call :cpp:func:`i2c_master_receive` to read data from the slave device. The principle of this function can be explained by following chart.
|
|
|
+
|
|
|
+.. figure:: ../../../_static/diagrams/i2c/i2c_master_read_slave.png
|
|
|
:align: center
|
|
|
+ :alt: I2C master read from slave
|
|
|
|
|
|
+ I2C master read from slave
|
|
|
|
|
|
-The following describes how a command link for a "master write" is set up and what comes inside:
|
|
|
+Simple example for reading data from slave:
|
|
|
|
|
|
-1. Create a command link with :cpp:func:`i2c_cmd_link_create`.
|
|
|
+.. code:: c
|
|
|
|
|
|
- Then, populate it with the series of data to be sent to the slave:
|
|
|
+ #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;
|
|
|
|
|
|
- a) **Start bit** - :cpp:func:`i2c_master_start`
|
|
|
- b) **Slave address** - :cpp:func:`i2c_master_write_byte`. The single byte address is provided as an argument of this function call.
|
|
|
- c) **Data** - One or more bytes as an argument of :cpp:func:`i2c_master_write`
|
|
|
- d) **Stop bit** - :cpp:func:`i2c_master_stop`
|
|
|
+ ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
|
|
|
|
|
- Both functions :cpp:func:`i2c_master_write_byte` and :cpp:func:`i2c_master_write` have an additional argument specifying whether the master should ensure that it has received the ACK bit.
|
|
|
+ i2c_device_config_t dev_cfg = {
|
|
|
+ .dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
|
|
+ .device_address = 0x58,
|
|
|
+ .scl_speed_hz = 100000,
|
|
|
+ };
|
|
|
|
|
|
-2. Trigger the execution of the command link by I2C controller by calling :cpp:func:`i2c_master_cmd_begin`. Once the execution is triggered, the command link cannot be modified.
|
|
|
-3. After the commands are transmitted, release the resources used by the command link by calling :cpp:func:`i2c_cmd_link_delete`.
|
|
|
+ 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);
|
|
|
|
|
|
-Master Read
|
|
|
-"""""""""""
|
|
|
+I2C Master Write and Read
|
|
|
+~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-The example below shows how to build a command link for an I2C master to read *n* bytes from a slave.
|
|
|
+Some I2C device needs write configurations before reading data from it, therefore, an interface called :cpp:func:`i2c_master_transmit_receive` can help. The principle of this function can be explained by following chart.
|
|
|
|
|
|
-.. blockdiag:: ../../../_static/diagrams/i2c-command-link-master-read-blockdiag.diag
|
|
|
- :scale: 100
|
|
|
- :caption: I2C command link - master read example
|
|
|
+.. figure:: ../../../_static/diagrams/i2c/i2c_master_write_read_slave.png
|
|
|
:align: center
|
|
|
+ :alt: I2C master write to slave and read from slave
|
|
|
|
|
|
+ I2C master write to slave and read from slave
|
|
|
|
|
|
-Compared to writing data, the command link is populated in Step 4 not with ``i2c_master_write...`` functions but with :cpp:func:`i2c_master_read_byte` and/or :cpp:func:`i2c_master_read`. Also, the last read in Step 5 is configured so that the master does not provide the ACK bit.
|
|
|
+Simple example for writing and reading from slave:
|
|
|
|
|
|
+.. code:: c
|
|
|
|
|
|
-Indicating Write or Read
|
|
|
-""""""""""""""""""""""""
|
|
|
+ i2c_device_config_t dev_cfg = {
|
|
|
+ .dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
|
|
+ .device_address = 0x58,
|
|
|
+ .scl_speed_hz = 100000,
|
|
|
+ };
|
|
|
|
|
|
-After sending a slave address (see Step 3 on both diagrams above), the master either writes or reads from the slave.
|
|
|
+ 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));
|
|
|
|
|
|
-The information on what the master actually does is hidden in the least significant bit of the slave's address.
|
|
|
+I2C Master Probe
|
|
|
+~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-For this reason, the command link sent by the master to write data to the slave contains the address ``(ESP_SLAVE_ADDR << 1) | I2C_MASTER_WRITE`` and looks as follows:
|
|
|
+I2C driver can use :cpp:func:`i2c_master_probe` to detect whether the specific device has been connected on I2C bus. If this function return ``ESP_OK``, that means the device has been detected.
|
|
|
|
|
|
-.. code-block:: c
|
|
|
+.. figure:: ../../../_static/diagrams/i2c/i2c_master_probe.png
|
|
|
+ :align: center
|
|
|
+ :alt: I2C master probe
|
|
|
+
|
|
|
+ I2C master probe
|
|
|
|
|
|
- i2c_master_write_byte(cmd, (ESP_SLAVE_ADDR << 1) | I2C_MASTER_WRITE, ACK_EN);
|
|
|
+Simple example for probing an I2C device:
|
|
|
|
|
|
-Likewise, the command link to read from the slave looks as follows:
|
|
|
+.. code:: c
|
|
|
|
|
|
-.. code-block:: c
|
|
|
+ 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;
|
|
|
|
|
|
- i2c_master_write_byte(cmd, (ESP_SLAVE_ADDR << 1) | I2C_MASTER_READ, ACK_EN);
|
|
|
+ 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));
|
|
|
|
|
|
|
|
|
-.. only:: SOC_I2C_SUPPORT_SLAVE
|
|
|
+I2C Slave Controller
|
|
|
+^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
- .. _i2c-api-slave-mode:
|
|
|
+After installing the i2c slave driver by :cpp:func:`i2c_new_slave_device`, {IDF_TARGET_NAME} is ready to communicate with other I2C master as a slave.
|
|
|
|
|
|
- Communication as Slave
|
|
|
- ^^^^^^^^^^^^^^^^^^^^^^
|
|
|
+I2C Slave Write
|
|
|
+~~~~~~~~~~~~~~~
|
|
|
|
|
|
- After installing the I2C driver, {IDF_TARGET_NAME} is ready to communicate with other I2C devices.
|
|
|
+The send buffer of the I2C slave is used as a FIFO to store the data to be sent. The data will queue up until the master requests them. You can call :cpp:func:`i2c_slave_transmit` to transfer data.
|
|
|
|
|
|
- The API provides the following functions for slaves
|
|
|
+Simple example for writing data to FIFO:
|
|
|
|
|
|
- - :cpp:func:`i2c_slave_read_buffer`
|
|
|
+.. code:: c
|
|
|
|
|
|
- Whenever the master writes data to the slave, the slave automatically stores it in the receive buffer. This allows the slave application to call the function :cpp:func:`i2c_slave_read_buffer` at its own discretion. This function also has a parameter to specify block time if no data is in the receive buffer. This allows the slave application to wait with a specified timeout for data to arrive to the buffer.
|
|
|
+ uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH);
|
|
|
|
|
|
- - :cpp:func:`i2c_slave_write_buffer`
|
|
|
+ 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 Slave Read
|
|
|
+~~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Whenever the master writes data to the slave, the slave will automatically store data in the receive buffer. This allows the slave application to call the function :cpp:func:`i2c_slave_receive` as its own discretion. As :cpp:func:`i2c_slave_receive` is designed as a non-blocking interface. So the user needs to register callback :cpp:func:`i2c_slave_register_event_callbacks` to know when the receive has finished.
|
|
|
+
|
|
|
+.. code:: c
|
|
|
+
|
|
|
+ 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,
|
|
|
+ };
|
|
|
|
|
|
- The send buffer is used to store all the data that the slave wants to send to the master in FIFO order. The data stays there until the master requests for it. The function :cpp:func:`i2c_slave_write_buffer` has a parameter to specify block time if the send buffer is full. This allows the slave application to wait with a specified timeout for the adequate amount of space to become available in the send buffer.
|
|
|
+ i2c_slave_dev_handle_t slave_handle;
|
|
|
+ ESP_ERROR_CHECK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
|
|
|
|
|
- A code example showing how to use these functions can be found in :example:`peripherals/i2c`.
|
|
|
+ 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.
|
|
|
+
|
|
|
+.. only:: SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS
|
|
|
+
|
|
|
+ Put Data In I2C Slave RAM
|
|
|
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
+
|
|
|
+ I2C slave fifo mentioned above can be used as RAM, which means user can access the RAM directly via address fields. For example, writing data to the 3rd ram block with following graph. Before using this, please note that :cpp:member:`i2c_slave_config_t::access_ram_en` needs to be set to true.
|
|
|
|
|
|
- .. _i2c-api-interrupt-handling:
|
|
|
+ .. figure:: ../../../_static/diagrams/i2c/i2c_slave_write_slave_ram.png
|
|
|
+ :align: center
|
|
|
+ :alt: Put data in I2C slave RAM
|
|
|
+
|
|
|
+ Put data in I2C slave RAM
|
|
|
+
|
|
|
+ .. code:: c
|
|
|
+
|
|
|
+ uint8_t data_rd[DATA_LENGTH_RAM] = {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,
|
|
|
+ .flags.access_ram_en = true,
|
|
|
+ };
|
|
|
|
|
|
-.. only:: not SOC_I2C_SUPPORT_SLAVE
|
|
|
+ // Master write to slave.
|
|
|
|
|
|
- .. _i2c-api-interrupt-handling:
|
|
|
+ i2c_slave_dev_handle_t slave_handle;
|
|
|
+ ESP_ERROR_CHECK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
|
|
+ ESP_ERROR_CHECK(i2c_slave_read_ram(slave_handle, 0x5, data_rd, DATA_LENGTH_RAM));
|
|
|
+ ESP_ERROR_CHECK(i2c_del_slave_device(slave_handle));
|
|
|
|
|
|
-Interrupt Handling
|
|
|
-^^^^^^^^^^^^^^^^^^
|
|
|
+ Get Data From I2C Slave RAM
|
|
|
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-During driver installation, an interrupt handler is installed by default.
|
|
|
+ Data can be stored in the RAM with a specific offset by the slave controller, and the master can read this data directly via the RAM address. For example, if the data is stored in 3rd ram block, master can read this data by following graph. Before using this, please note that :cpp:member:`i2c_slave_config_t::access_ram_en` needs to be set to true.
|
|
|
|
|
|
-.. _i2c-api-customized-configuration:
|
|
|
+ .. figure:: ../../../_static/diagrams/i2c/i2c_slave_read_slave_ram.png
|
|
|
+ :align: center
|
|
|
+ :alt: Get data from I2C slave RAM
|
|
|
|
|
|
-Customized Configuration
|
|
|
+ Get data from I2C slave RAM
|
|
|
+
|
|
|
+ .. code:: c
|
|
|
+
|
|
|
+ uint8_t data_wr[DATA_LENGTH_RAM] = {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,
|
|
|
+ .flags.access_ram_en = true,
|
|
|
+ };
|
|
|
+
|
|
|
+ i2c_slave_dev_handle_t slave_handle;
|
|
|
+ ESP_ERROR_CHECK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
|
|
+ ESP_ERROR_CHECK(i2c_slave_write_ram(slave_handle, 0x2, data_wr, DATA_LENGTH_RAM));
|
|
|
+ ESP_ERROR_CHECK(i2c_del_slave_device(slave_handle));
|
|
|
+
|
|
|
+Register Event Callbacks
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
-As mentioned at the end of Section :ref:`i2c-api-configure-driver`, when the function :cpp:func:`i2c_param_config` initializes the driver configuration for an I2C port, it also sets several I2C communication parameters to default values defined in the I2C specification. Some other related parameters are pre-configured in registers of the I2C controller.
|
|
|
+I2C master callbacks
|
|
|
+~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-All these parameters can be changed to user-defined values by calling dedicated functions given in the table below. Please note that the timing values are defined in APB clock cycles.
|
|
|
+When an I2C master bus triggers an interrupt, a specific event will be generated and notify the CPU. If you have some functions that need to be called when those events occurred, you can hook your functions to the ISR (Interrupt Service Routine) by calling :cpp:func:`i2c_master_register_event_callbacks`. Since the registered callback functions are called in the interrupt context, user should ensure the callback function doesn't attempt to block (e.g. by making sure that only FreeRTOS APIs with ``ISR`` suffix are called from within the function). The callback functions are required to return a boolean value, to tell the ISR whether a high priority task is woke up by it.
|
|
|
|
|
|
-.. list-table:: Other Configurable I2C Communication Parameters
|
|
|
- :widths: 65 35
|
|
|
- :header-rows: 1
|
|
|
+I2C master event callbacks are listed in the :cpp:type:`i2c_master_event_callbacks_t`.
|
|
|
|
|
|
- * - Parameters to Change
|
|
|
- - Function
|
|
|
- * - High time and low time for SCL pulses
|
|
|
- - :cpp:func:`i2c_set_period`
|
|
|
- * - SCL and SDA signal timing used during generation of **start** signals
|
|
|
- - :cpp:func:`i2c_set_start_timing`
|
|
|
- * - SCL and SDA signal timing used during generation of **stop** signals
|
|
|
- - :cpp:func:`i2c_set_stop_timing`
|
|
|
- * - Timing relationship between SCL and SDA signals when slave samples, as well as when master toggles
|
|
|
- - :cpp:func:`i2c_set_data_timing`
|
|
|
- * - I2C timeout
|
|
|
- - :cpp:func:`i2c_set_timeout`
|
|
|
- * - Choice between transmitting / receiving the LSB or MSB first, choose one of the modes defined in :cpp:type:`i2c_trans_mode_t`
|
|
|
- - :cpp:func:`i2c_set_data_mode`
|
|
|
+Although I2C is a synchronous communication protocol, we also support asynchronous behavior by registering above callback. In this way, I2C APIs will be non-blocking interface. But note that on the same bus, only one device can adopt asynchronous operation.
|
|
|
|
|
|
+.. important::
|
|
|
|
|
|
-Each of the above functions has a *_get_* counterpart to check the currently set value. For example, to check the I2C timeout value, call :cpp:func:`i2c_get_timeout`.
|
|
|
+ I2C master asynchronous transaction is still an experimental feature. (The issue is when asynchronous transaction is very large, it will cause memory problem.)
|
|
|
|
|
|
-To check the default parameter values which are set during the driver configuration process, please refer to the file :component_file:`driver/i2c/i2c.c` and look for defines with the suffix ``_DEFAULT``.
|
|
|
+- :cpp:member:`i2c_master_event_callbacks_t::on_recv_done` sets a callback function for master "transaction-done" event. The function prototype is declared in :cpp:type:`i2c_master_callback_t`.
|
|
|
|
|
|
-You can also select different pins for SDA and SCL signals and alter the configuration of pull-ups with the function :cpp:func:`i2c_set_pin`. If you want to modify already entered values, use the function :cpp:func:`i2c_param_config`.
|
|
|
+I2C slave callbacks
|
|
|
+~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-.. note::
|
|
|
+When an I2C slave bus triggers an interrupt, a specific event will be generated and notify the CPU. If you have some function that needs to be called when those events occurred, you can hook your function to the ISR (Interrupt Service Routine) by calling :cpp:func:`i2c_slave_register_event_callbacks`. Since the registered callback functions are called in the interrupt context, user should ensure the callback function doesn't attempt to block (e.g. by making sure that only FreeRTOS APIs with ``ISR`` suffix are called from within the function). The callback function has a boolean return value, to tell the caller whether a high priority task is woke up by it.
|
|
|
|
|
|
- {IDF_TARGET_NAME}'s internal pull-ups are in the range of tens of kOhm, which is, in most cases, insufficient for use as I2C pull-ups. Users are advised to use external pull-ups with values described in the I2C specification. For help with calculating the resistor values see `TI Application Note <https://www.ti.com/lit/an/slva689/slva689.pdf>`_
|
|
|
+I2C slave event callbacks are listed in the :cpp:type:`i2c_slave_event_callbacks_t`.
|
|
|
|
|
|
+.. list::
|
|
|
|
|
|
-.. _i2c-api-error-handling:
|
|
|
+ - :cpp:member:`i2c_slave_event_callbacks_t::on_recv_done` sets a callback function for "receive-done" event. The function prototype is declared in :cpp:type:`i2c_slave_received_callback_t`.
|
|
|
+ :SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE: - :cpp:member:`i2c_slave_event_callbacks_t::on_stretch_occur` sets a callback function for "stretch" cause. The function prototype is declared in :cpp:type:`i2c_slave_stretch_callback_t`.
|
|
|
|
|
|
-Error Handling
|
|
|
-^^^^^^^^^^^^^^
|
|
|
+Power Management
|
|
|
+^^^^^^^^^^^^^^^^
|
|
|
|
|
|
-The majority of I2C driver functions either return ``ESP_OK`` on successful completion or a specific error code on failure. It is a good practice to always check the returned values and implement error handling. The driver also prints out log messages that contain error details, e.g., when checking the validity of entered configuration. For details please refer to the file :component_file:`driver/i2c/i2c.c` and look for defines with the suffix ``_ERR_STR``.
|
|
|
+.. only:: SOC_I2C_SUPPORT_APB
|
|
|
|
|
|
-Use dedicated interrupts to capture communication failures. For instance, if a slave stretches the clock for too long while preparing the data to send back to master, the interrupt ``I2C_TIME_OUT_INT`` will be triggered. For detailed information, see :ref:`i2c-api-interrupt-handling`.
|
|
|
+ When the power management is enabled (i.e. :ref:`CONFIG_PM_ENABLE` is on), the system will adjust or stop the source clock of I2C fifo before going into light sleep, thus potentially changing the I2C signals and leading to transmitting or receiving invalid data.
|
|
|
|
|
|
-In case of a communication failure, you can reset the internal hardware buffers by calling the functions :cpp:func:`i2c_reset_tx_fifo` and :cpp:func:`i2c_reset_rx_fifo` for the send and receive buffers respectively.
|
|
|
+ However, the driver can prevent the system from changing APB frequency by acquiring a power management lock of type :cpp:enumerator:`ESP_PM_APB_FREQ_MAX`. Whenever user creates an I2C bus that has selected :cpp:enumerator:`I2C_CLK_SRC_APB` as the clock source, the driver will guarantee that the power management lock is acquired when I2C operations begin and release the lock automatically when I2C operations finish.
|
|
|
|
|
|
+.. only:: SOC_I2C_SUPPORT_REF_TICK
|
|
|
|
|
|
-.. _i2c-api-delete-driver:
|
|
|
+ If the controller clock source is selected to :cpp:enumerator:`I2C_CLK_SRC_REF_TICK`, then the driver won't install power management lock for it, which is more suitable for a low power application as long as the source clock can still provide sufficient resolution.
|
|
|
|
|
|
-Delete Driver
|
|
|
-^^^^^^^^^^^^^
|
|
|
+.. only:: SOC_I2C_SUPPORT_XTAL
|
|
|
|
|
|
-When the I2C communication is established with the function :cpp:func:`i2c_driver_install` and is not required for some substantial amount of time, the driver may be deinitialized to release allocated resources by calling :cpp:func:`i2c_driver_delete`.
|
|
|
+ If the controller clock source is selected to :cpp:enumerator:`I2C_CLK_SRC_XTAL`, then the driver won't install power management lock for it, which is more suitable for a low power application as long as the source clock can still provide sufficient resolution.
|
|
|
|
|
|
-Before calling :cpp:func:`i2c_driver_delete` to remove i2c driver, please make sure that all threads have stopped using the driver in any way, because this function does not guarantee thread safety.
|
|
|
+IRAM Safe
|
|
|
+^^^^^^^^^
|
|
|
|
|
|
-Application Example
|
|
|
--------------------
|
|
|
+By default, the I2C interrupt will be deferred when the Cache is disabled for reasons like writing/erasing Flash. Thus the event callback functions will not get executed in time, which is not expected in a real-time application.
|
|
|
+
|
|
|
+There's a Kconfig option :ref:`CONFIG_I2C_ISR_IRAM_SAFE` that will:
|
|
|
|
|
|
-I2C examples: :example:`peripherals/i2c`.
|
|
|
+1. Enable the interrupt being serviced even when cache is disabled
|
|
|
+2. Place all functions that used by the ISR into IRAM
|
|
|
+3. Place driver object into DRAM (in case it's mapped to PSRAM by accident)
|
|
|
|
|
|
+This will allow the interrupt to run while the cache is disabled but will come at the cost of increased IRAM consumption.
|
|
|
+
|
|
|
+Thread Safety
|
|
|
+^^^^^^^^^^^^^
|
|
|
+
|
|
|
+The factory function :cpp:func:`i2c_new_master_bus` and :cpp:func:`i2c_new_slave_device` are guaranteed to be thread safe by the driver, which means, user can call them from different RTOS tasks without protection by extra locks. Other public I2C APIs are not thread safe. which means the user should avoid calling them from multiple tasks, if user strongly needs to call them in multiple tasks, please add extra lock.
|
|
|
+
|
|
|
+Kconfig Options
|
|
|
+^^^^^^^^^^^^^^^
|
|
|
+
|
|
|
+- :ref:`CONFIG_I2C_ISR_IRAM_SAFE` controls whether the default ISR handler can work when cache is disabled, see also `IRAM Safe <#iram-safe>`__ for more information.
|
|
|
+- :ref:`CONFIG_I2C_ENABLE_DEBUG_LOG` is used to enable the debug log at the cost of increased firmware binary size.
|
|
|
|
|
|
API Reference
|
|
|
-------------
|
|
|
|
|
|
-.. include-build-file:: inc/i2c.inc
|
|
|
-.. include-build-file:: inc/i2c_types.inc
|
|
|
+.. include-build-file:: inc/i2c_master.inc
|
|
|
+
|
|
|
+.. only:: SOC_I2C_SUPPORT_SLAVE
|
|
|
+
|
|
|
+ .. include-build-file:: inc/i2c_slave.inc
|
|
|
+
|
|
|
+.. include-build-file:: inc/components/driver/i2c/include/driver/i2c_types.inc
|
|
|
+.. include-build-file:: inc/components/hal/include/hal/i2c_types.inc
|