| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102 |
- /*
- * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include <string.h>
- #include <sys/param.h>
- #include <sys/lock.h>
- #include "sdkconfig.h"
- #include "esp_types.h"
- #include "esp_attr.h"
- #include "esp_check.h"
- #if CONFIG_I2C_ENABLE_DEBUG_LOG
- // The local log level must be defined before including esp_log.h
- // Set the maximum log level for this source file
- #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
- #endif
- #include "esp_log.h"
- #include "esp_intr_alloc.h"
- #include "freertos/FreeRTOS.h"
- #include "freertos/semphr.h"
- #include "soc/i2c_periph.h"
- #include "esp_private/periph_ctrl.h"
- #include "esp_private/esp_clk.h"
- #include "esp_rom_gpio.h"
- #include "driver/i2c_master.h"
- #include "i2c_private.h"
- #include "driver/gpio.h"
- #include "clk_ctrl_os.h"
- #include "hal/i2c_types.h"
- #include "hal/i2c_hal.h"
- #include "hal/gpio_hal.h"
- #include "esp_memory_utils.h"
- #include "freertos/idf_additions.h"
- static const char *TAG = "i2c.master";
- static _lock_t s_i2c_bus_acquire;
- #define DIM(array) (sizeof(array)/sizeof(*array))
- #define I2C_ADDRESS_TRANS_WRITE(device_address) (((device_address) << 1) | 0)
- #define I2C_ADDRESS_TRANS_READ(device_address) (((device_address) << 1) | 1)
- static esp_err_t s_i2c_master_clear_bus(i2c_bus_handle_t handle)
- {
- #if !SOC_I2C_SUPPORT_HW_FSM_RST
- const int scl_half_period = 5; // use standard 100kHz data rate
- int i = 0;
- gpio_set_direction(handle->scl_num, GPIO_MODE_OUTPUT_OD);
- gpio_set_direction(handle->sda_num, GPIO_MODE_INPUT_OUTPUT_OD);
- // If a SLAVE device was in a read operation when the bus was interrupted, the SLAVE device is controlling SDA.
- // The only bit during the 9 clock cycles of a READ byte the MASTER(ESP32) is guaranteed control over is during the ACK bit
- // period. If the slave is sending a stream of ZERO bytes, it will only release SDA during the ACK bit period.
- // So, this reset code needs to synchronous the bit stream with, Either, the ACK bit, Or a 1 bit to correctly generate
- // a STOP condition.
- gpio_set_level(handle->scl_num, 0);
- gpio_set_level(handle->sda_num, 1);
- esp_rom_delay_us(scl_half_period);
- while (!gpio_get_level(handle->sda_num) && (i++ < 9)) {
- gpio_set_level(handle->scl_num, 1);
- esp_rom_delay_us(scl_half_period);
- gpio_set_level(handle->scl_num, 0);
- esp_rom_delay_us(scl_half_period);
- }
- gpio_set_level(handle->sda_num, 0); // setup for STOP
- gpio_set_level(handle->scl_num, 1);
- esp_rom_delay_us(scl_half_period);
- gpio_set_level(handle->sda_num, 1); // STOP, SDA low -> high while SCL is HIGH
- i2c_common_set_pins(handle);
- #else
- i2c_hal_context_t *hal = &handle->hal;
- i2c_ll_master_clr_bus(hal->dev, I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT);
- #endif
- return ESP_OK;
- }
- /**
- * @brief Reset I2C hardware fsm.
- * 1. Store filter and timing stuff(they are I2C hardware configure stuff)
- * so, the configuration is same after reset.
- *
- * @param[in] i2c_master I2C master handle
- */
- static esp_err_t s_i2c_hw_fsm_reset(i2c_master_bus_handle_t i2c_master)
- {
- i2c_hal_context_t *hal = &i2c_master->base->hal;
- i2c_hal_timing_config_t timing_config;
- uint8_t filter_cfg;
- i2c_hal_get_timing_config(hal, &timing_config);
- i2c_ll_master_get_filter(hal->dev, &filter_cfg);
- //to reset the I2C hw module, we need re-enable the hw
- s_i2c_master_clear_bus(i2c_master->base);
- periph_module_disable(i2c_periph_signal[i2c_master->base->port_num].module);
- periph_module_enable(i2c_periph_signal[i2c_master->base->port_num].module);
- i2c_hal_master_init(hal);
- i2c_ll_disable_intr_mask(hal->dev, I2C_LL_INTR_MASK);
- i2c_ll_clear_intr_mask(hal->dev, I2C_LL_INTR_MASK);
- i2c_hal_set_timing_config(hal, &timing_config);
- i2c_ll_master_set_filter(hal->dev, filter_cfg);
- return ESP_OK;
- }
- //////////////////////////////////////I2C operation functions////////////////////////////////////////////
- /**
- * @brief This function is used to send I2C write command, which is divided in two parts.
- * -1. If write buffer is smaller than hardware fifo, it can be sent out in one single time,
- * so the hardware command(step) is simply like start(1)->write(2)->end(3)
- * -2. If write buffer is larger than hardware fifo, it cannot be sent out in one time, so it needs
- * to be separated in to different transactions by interrupt. In this time, the hardware command(step)
- * simply looks like start(1)->write_part(2)--interrupt--...--write(1)->end(2).
- *
- * @param[in] i2c_master I2C master handle
- * @param[in] i2c_operation Pointer to I2C trans operation structure.
- * @param[in] fifo_fill will be populated with the number of bytes written to the harware FIFO by this function
- * @param[in] address_fill I2C device address with read or write information.
- */
- static bool s_i2c_write_command(i2c_master_bus_handle_t i2c_master, i2c_operation_t *i2c_operation, uint8_t *fifo_fill, uint8_t *address_fill, BaseType_t *do_yield)
- {
- i2c_master->async_break = false;
- const size_t remaining_bytes = i2c_operation->total_bytes - i2c_operation->bytes_used;
- const i2c_ll_hw_cmd_t hw_end_cmd = {
- .op_code = I2C_LL_CMD_END
- };
- uint8_t *write_pr = NULL;
- i2c_hal_context_t *hal = &i2c_master->base->hal;
- i2c_bus_handle_t handle = i2c_master->base;
- i2c_ll_hw_cmd_t hw_cmd = i2c_operation->hw_cmd;
- uint8_t data_fill = 0;
- // data_fill refers to the length to fill the data
- data_fill = MIN(remaining_bytes, SOC_I2C_FIFO_LEN - *address_fill);
- write_pr = i2c_operation->data + i2c_operation->bytes_used;
- i2c_operation->bytes_used += data_fill;
- hw_cmd.byte_num = data_fill + *address_fill;
- *address_fill = 0;
- atomic_store(&i2c_master->status, I2C_STATUS_WRITE);
- portENTER_CRITICAL_SAFE(&handle->spinlock);
- i2c_ll_write_txfifo(hal->dev, write_pr, data_fill);
- i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
- portEXIT_CRITICAL_SAFE(&handle->spinlock);
- i2c_master->w_r_size = data_fill;
- #if SOC_I2C_STOP_INDEPENDENT
- i2c_ll_master_write_cmd_reg(hal->dev, hw_end_cmd, i2c_master->cmd_idx + 1);
- i2c_master->cmd_idx = 0;
- if (i2c_master->i2c_trans.ops[i2c_master->trans_idx].total_bytes == i2c_master->i2c_trans.ops[i2c_master->trans_idx].bytes_used) {
- i2c_master->i2c_trans.cmd_count--;
- i2c_master->trans_idx++;
- }
- portENTER_CRITICAL_SAFE(&handle->spinlock);
- if (i2c_master->asnyc_trans == false) {
- i2c_hal_master_trans_start(hal);
- } else {
- i2c_master->async_break = true;
- }
- portEXIT_CRITICAL_SAFE(&handle->spinlock);
- #else
- // If data cannot be sent in one time, send data out. Otherwise, continue configuring command.
- if ((remaining_bytes - data_fill) != 0) {
- portENTER_CRITICAL_SAFE(&handle->spinlock);
- i2c_ll_master_write_cmd_reg(hal->dev, hw_end_cmd, i2c_master->cmd_idx + 1);
- portEXIT_CRITICAL_SAFE(&handle->spinlock);
- i2c_master->cmd_idx = 0;
- if (i2c_master->asnyc_trans == false) {
- i2c_hal_master_trans_start(hal);
- } else {
- i2c_master->async_break = true;
- }
- } else {
- i2c_master->cmd_idx++;
- i2c_master->trans_idx++;
- i2c_master->i2c_trans.cmd_count--;
- if (i2c_master->asnyc_trans == false) {
- if (xPortInIsrContext()) {
- xSemaphoreGiveFromISR(i2c_master->cmd_semphr, do_yield);
- } else {
- xSemaphoreGive(i2c_master->cmd_semphr);
- }
- }
- }
- #endif
- *fifo_fill = data_fill;
- return i2c_master->async_break;
- }
- /**
- * @brief This function is used to send I2C read command, which is divided in three parts.
- * -1. If read buffer is smaller than hardware fifo, it can be sent out in one single time,
- * so the hardware command(step) is simply like start(1)->read_ack(2)->read_nack(3)->end(4)
- * -2. If read buffer is larger than hardware fifo, it cannot be sent out in one time, so it needs
- * to be separated in to different transactions by interrupt. In this time, the hardware command(step)
- * simply looks like start(1)->read_part(2)--interrupt--...--read(1)->end(2).
- * -3. If only one byte is waiting to be read. only send nack command. like start(1)->read_nack(2)->end(3)
- *
- * @param[in] i2c_master I2C master handle
- * @param[in] i2c_operation Pointer to I2C trans operation structure.
- * @param[out] fifo_fill Pointer to read buffer length
- */
- static bool s_i2c_read_command(i2c_master_bus_handle_t i2c_master, i2c_operation_t *i2c_operation, uint8_t *fifo_fill, BaseType_t *do_yield)
- {
- i2c_master->async_break = false;
- const size_t remaining_bytes = i2c_operation->total_bytes - i2c_operation->bytes_used;
- const i2c_ll_hw_cmd_t hw_end_cmd = {
- .op_code = I2C_LL_CMD_END
- };
- i2c_hal_context_t *hal = &i2c_master->base->hal;
- i2c_bus_handle_t handle = i2c_master->base;
- i2c_ll_hw_cmd_t hw_cmd = i2c_operation->hw_cmd;
- *fifo_fill = MIN(remaining_bytes, SOC_I2C_FIFO_LEN - i2c_master->read_len_static);
- i2c_master->rx_cnt = *fifo_fill;
- hw_cmd.byte_num = *fifo_fill;
- i2c_master->contains_read = true;
- #if !SOC_I2C_STOP_INDEPENDENT
- if (remaining_bytes < SOC_I2C_FIFO_LEN - 1) {
- if (i2c_operation->hw_cmd.ack_val == ACK_VAL) {
- if (remaining_bytes != 0) {
- i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
- i2c_master->read_len_static = i2c_master->rx_cnt;
- i2c_master->cmd_idx++;
- }
- i2c_master->read_buf_pos = i2c_master->trans_idx;
- } else {
- i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
- i2c_master->cmd_idx++;
- }
- i2c_master->trans_idx++;
- i2c_master->i2c_trans.cmd_count--;
- if (i2c_master->asnyc_trans == false) {
- if (xPortInIsrContext()) {
- xSemaphoreGiveFromISR(i2c_master->cmd_semphr, do_yield);
- } else {
- xSemaphoreGive(i2c_master->cmd_semphr);
- }
- }
- } else {
- atomic_store(&i2c_master->status, I2C_STATUS_READ);
- portENTER_CRITICAL_SAFE(&handle->spinlock);
- i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
- i2c_ll_master_write_cmd_reg(hal->dev, hw_end_cmd, i2c_master->cmd_idx + 1);
- if (i2c_master->asnyc_trans == false) {
- i2c_hal_master_trans_start(hal);
- } else {
- i2c_master->async_break = true;
- }
- portEXIT_CRITICAL_SAFE(&handle->spinlock);
- }
- #else
- portENTER_CRITICAL_SAFE(&handle->spinlock);
- i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
- i2c_ll_master_write_cmd_reg(hal->dev, hw_end_cmd, i2c_master->cmd_idx + 1);
- portEXIT_CRITICAL_SAFE(&handle->spinlock);
- i2c_master->status = I2C_STATUS_READ;
- portENTER_CRITICAL_SAFE(&handle->spinlock);
- if (i2c_master->asnyc_trans == false) {
- i2c_hal_master_trans_start(hal);
- } else {
- i2c_master->async_break = true;
- }
- portEXIT_CRITICAL_SAFE(&handle->spinlock);
- #endif
- return i2c_master->async_break;
- }
- /**
- * @brief This function is used to send I2C start or stop command, which is divided in two parts.
- * If start command is accepted, a write address command must be followed. So prepared one address
- * data here. Send with write or read command.
- *
- * @param[in] i2c_master I2C master handle
- * @param[in] i2c_operation Pointer to I2C trans operation structure.
- * @param[in] address_fill I2C device address with read or write information.
- */
- static void s_i2c_start_end_command(i2c_master_bus_handle_t i2c_master, i2c_operation_t *i2c_operation, uint8_t *address_fill, BaseType_t *do_yield)
- {
- i2c_hal_context_t *hal = &i2c_master->base->hal;
- i2c_ll_hw_cmd_t hw_cmd = i2c_operation->hw_cmd;
- #if SOC_I2C_SUPPORT_10BIT_ADDR
- uint8_t cmd_address = (i2c_master->addr_10bits_bus == I2C_ADDR_BIT_LEN_7) ? i2c_master->i2c_trans.device_address : ((i2c_master->i2c_trans.device_address >> 8) | 0x78);
- uint8_t addr_byte = (i2c_master->addr_10bits_bus == I2C_ADDR_BIT_LEN_7) ? 1 : 2;
- #else
- uint8_t cmd_address = i2c_master->i2c_trans.device_address;
- uint8_t addr_byte = 1;
- #endif
- uint8_t addr_write[addr_byte];
- uint8_t addr_read[addr_byte];
- addr_write[0] = I2C_ADDRESS_TRANS_WRITE(cmd_address);
- addr_read[0] = I2C_ADDRESS_TRANS_READ(cmd_address);
- #if SOC_I2C_SUPPORT_10BIT_ADDR
- if (i2c_master->addr_10bits_bus == I2C_ADDR_BIT_LEN_10) {
- addr_write[1] = i2c_master->i2c_trans.device_address & 0xff;
- addr_read[1] = i2c_master->i2c_trans.device_address & 0xff;
- }
- #endif
- portENTER_CRITICAL_SAFE(&i2c_master->base->spinlock);
- i2c_ll_master_write_cmd_reg(hal->dev, hw_cmd, i2c_master->cmd_idx);
- i2c_master->cmd_idx++;
- portEXIT_CRITICAL_SAFE(&i2c_master->base->spinlock);
- if (i2c_operation->hw_cmd.op_code == I2C_LL_CMD_RESTART) {
- if (i2c_master->i2c_trans.ops[i2c_master->trans_idx + 1].hw_cmd.op_code != I2C_LL_CMD_WRITE) {
- #if SOC_I2C_SUPPORT_10BIT_ADDR
- if (i2c_master->addr_10bits_bus == I2C_ADDR_BIT_LEN_10) {
- i2c_ll_hw_cmd_t hw_write_cmd = {
- .ack_en = false,
- .op_code = I2C_LL_CMD_WRITE,
- .byte_num = 2,
- };
- portENTER_CRITICAL_SAFE(&i2c_master->base->spinlock);
- i2c_ll_write_txfifo(hal->dev, addr_write, sizeof(addr_write));
- i2c_ll_master_write_cmd_reg(hal->dev, hw_write_cmd, i2c_master->cmd_idx);
- i2c_master->cmd_idx++;
- portEXIT_CRITICAL_SAFE(&i2c_master->base->spinlock);
- const i2c_ll_hw_cmd_t hw_start_cmd = {
- .op_code = I2C_LL_CMD_RESTART,
- };
- portENTER_CRITICAL_SAFE(&i2c_master->base->spinlock);
- i2c_ll_master_write_cmd_reg(hal->dev, hw_start_cmd, i2c_master->cmd_idx);
- i2c_master->cmd_idx++;
- portEXIT_CRITICAL_SAFE(&i2c_master->base->spinlock);
- }
- #endif
- i2c_ll_hw_cmd_t hw_write_cmd = {
- .ack_en = false,
- .op_code = I2C_LL_CMD_WRITE,
- .byte_num = 1,
- };
- portENTER_CRITICAL_SAFE(&i2c_master->base->spinlock);
- i2c_ll_write_txfifo(hal->dev, addr_read, sizeof(addr_read));
- i2c_ll_master_write_cmd_reg(hal->dev, hw_write_cmd, i2c_master->cmd_idx);
- i2c_master->cmd_idx++;
- portEXIT_CRITICAL_SAFE(&i2c_master->base->spinlock);
- } else {
- /* The next transaction is a WRITE, we can merge the device address byte
- * with the next write command. No need to write the `cmd_reg` as the next
- * command will do it for us, we only need to add the device address byte
- * in the TX FIFO. */
- portENTER_CRITICAL_SAFE(&i2c_master->base->spinlock);
- i2c_ll_write_txfifo(hal->dev, addr_write, sizeof(addr_write));
- *address_fill += sizeof(addr_write);
- portEXIT_CRITICAL_SAFE(&i2c_master->base->spinlock);
- }
- if (i2c_master->asnyc_trans == false) {
- if (xPortInIsrContext()) {
- xSemaphoreGiveFromISR(i2c_master->cmd_semphr, do_yield);
- } else {
- xSemaphoreGive(i2c_master->cmd_semphr);
- }
- }
- } else {
- atomic_store(&i2c_master->status, I2C_STATUS_STOP);
- }
- portENTER_CRITICAL_SAFE(&i2c_master->base->spinlock);
- i2c_master->trans_idx++;
- i2c_master->i2c_trans.cmd_count--;
- portEXIT_CRITICAL_SAFE(&i2c_master->base->spinlock);
- }
- static void s_i2c_send_commands(i2c_master_bus_handle_t i2c_master, TickType_t ticks_to_wait)
- {
- i2c_hal_context_t *hal = &i2c_master->base->hal;
- uint8_t fifo_fill = 0;
- uint8_t address_fill = 0;
- while (i2c_master->i2c_trans.cmd_count) {
- if (xSemaphoreTake(i2c_master->cmd_semphr, ticks_to_wait) != pdTRUE) {
- // Software timeout, clear the command link and finish this transaction.
- i2c_master->cmd_idx = 0;
- i2c_master->trans_idx = 0;
- return;
- }
- if (i2c_master->status == I2C_STATUS_TIMEOUT) {
- s_i2c_hw_fsm_reset(i2c_master);
- i2c_master->cmd_idx = 0;
- i2c_master->trans_idx = 0;
- xSemaphoreGive(i2c_master->cmd_semphr);
- return;
- }
- if (i2c_master->status == I2C_STATUS_ACK_ERROR) {
- const i2c_ll_hw_cmd_t hw_stop_cmd = {
- .op_code = I2C_LL_CMD_STOP,
- };
- i2c_ll_master_write_cmd_reg(hal->dev, hw_stop_cmd, 0);
- i2c_hal_master_trans_start(hal);
- return;
- }
- i2c_operation_t *i2c_operation = &i2c_master->i2c_trans.ops[i2c_master->trans_idx];
- if (i2c_operation->hw_cmd.op_code == I2C_LL_CMD_WRITE) {
- s_i2c_write_command(i2c_master, i2c_operation, &fifo_fill, &address_fill, NULL);
- } else if (i2c_operation->hw_cmd.op_code == I2C_LL_CMD_READ) {
- s_i2c_read_command(i2c_master, i2c_operation, &fifo_fill, NULL);
- } else {
- s_i2c_start_end_command(i2c_master, i2c_operation, &address_fill, NULL);
- }
- }
- i2c_hal_master_trans_start(hal);
- // For blocking implementation, we must wait `done` interrupt to update the status.
- while (i2c_master->trans_done == false) {};
- atomic_store(&i2c_master->status, I2C_STATUS_DONE);
- xSemaphoreGive(i2c_master->cmd_semphr);
- }
- static void s_i2c_send_command_async(i2c_master_bus_handle_t i2c_master, BaseType_t *do_yield)
- {
- i2c_hal_context_t *hal = &i2c_master->base->hal;
- uint8_t address_fill = 0;
- bool needs_start = false;
- if (i2c_master->i2c_trans.cmd_count == 0) {
- // No extra commands.
- i2c_master->trans_finish = true;
- i2c_master->in_progress = false;
- if (i2c_master->queue_trans) {
- i2c_master->new_queue = true;
- xQueueSendFromISR(i2c_master->trans_queues[I2C_TRANS_QUEUE_COMPLETE], &i2c_master->i2c_trans, do_yield);
- }
- i2c_master->sent_all = true;
- return;
- }
- while(i2c_ll_is_bus_busy(hal->dev)){}
- while (i2c_master->i2c_trans.cmd_count && !needs_start) {
- i2c_master->in_progress = true;
- i2c_master->sent_all = false;
- i2c_operation_t *i2c_operation = &i2c_master->i2c_trans.ops[i2c_master->trans_idx];
- uint8_t fifo_fill = 0;
- if (i2c_operation->hw_cmd.op_code == I2C_LL_CMD_WRITE) {
- needs_start = s_i2c_write_command(i2c_master, i2c_operation, &fifo_fill, &address_fill, do_yield);
- } else if (i2c_operation->hw_cmd.op_code == I2C_LL_CMD_READ) {
- needs_start = s_i2c_read_command(i2c_master, i2c_operation, &fifo_fill, do_yield);
- } else {
- s_i2c_start_end_command(i2c_master, i2c_operation, &address_fill, do_yield);
- }
- }
- i2c_hal_master_trans_start(hal);
- }
- static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xfer_timeout_ms)
- {
- i2c_master_bus_handle_t i2c_master = i2c_dev->master_bus;
- i2c_hal_context_t *hal = &i2c_master->base->hal;
- TickType_t ticks_to_wait = (xfer_timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(xfer_timeout_ms);
- // Sometimes when the FSM get stuck, the ACK_ERR interrupt will occur endlessly until we reset the FSM and clear bus.
- esp_err_t ret = ESP_OK;
- if (i2c_master->status == I2C_STATUS_TIMEOUT || i2c_ll_is_bus_busy(hal->dev)) {
- s_i2c_hw_fsm_reset(i2c_master);
- }
- if (i2c_master->base->pm_lock) {
- ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(i2c_master->base->pm_lock), TAG, "acquire pm_lock failed");
- }
- portENTER_CRITICAL(&i2c_master->base->spinlock);
- atomic_init(&i2c_master->trans_idx, 0);
- atomic_store(&i2c_master->status, I2C_STATUS_IDLE);
- i2c_master->cmd_idx = 0;
- i2c_master->rx_cnt = 0;
- i2c_master->read_len_static = 0;
- i2c_hal_set_bus_timing(hal, i2c_dev->scl_speed_hz, i2c_master->base->clk_src, i2c_master->base->clk_src_freq_hz);
- i2c_ll_master_set_fractional_divider(hal->dev, 0, 0);
- i2c_ll_update(hal->dev);
- i2c_ll_txfifo_rst(hal->dev);
- i2c_ll_rxfifo_rst(hal->dev);
- i2c_ll_enable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR);
- portEXIT_CRITICAL(&i2c_master->base->spinlock);
- if (i2c_master->asnyc_trans == true) {
- s_i2c_send_command_async(i2c_master, NULL);
- } else {
- s_i2c_send_commands(i2c_master, ticks_to_wait);
- // Wait event bits
- if (i2c_master->status != I2C_STATUS_DONE) {
- ret = ESP_ERR_INVALID_STATE;
- }
- }
- if (i2c_master->base->pm_lock) {
- ESP_RETURN_ON_ERROR(esp_pm_lock_release(i2c_master->base->pm_lock), TAG, "release pm_lock failed");
- }
- return ret;
- }
- ///////////////////////////////I2C DRIVERS//////////////////////////////////////////////////////////////
- IRAM_ATTR static void i2c_isr_receive_handler(i2c_master_bus_t *i2c_master)
- {
- i2c_hal_context_t *hal = &i2c_master->base->hal;
- while(i2c_ll_is_bus_busy(hal->dev)){}
- if (i2c_master->status == I2C_STATUS_READ) {
- i2c_operation_t *i2c_operation = &i2c_master->i2c_trans.ops[i2c_master->trans_idx];
- portENTER_CRITICAL_ISR(&i2c_master->base->spinlock);
- i2c_ll_read_rxfifo(hal->dev, i2c_operation->data + i2c_operation->bytes_used, i2c_master->rx_cnt);
- /* rx_cnt bytes have just been read, increment the number of bytes used from the buffer */
- i2c_master->w_r_size = i2c_master->rx_cnt;
- i2c_operation->bytes_used += i2c_master->rx_cnt;
- i2c_master->cmd_idx = 0;
- /* Test if there are still some remaining bytes to send. */
- if (i2c_operation->bytes_used == i2c_operation->total_bytes) {
- i2c_master->i2c_trans.cmd_count--;
- i2c_master->read_buf_pos = i2c_master->trans_idx;
- i2c_master->trans_idx++;
- i2c_operation->bytes_used = 0;
- }
- portEXIT_CRITICAL_ISR(&i2c_master->base->spinlock);
- }
- #if !SOC_I2C_STOP_INDEPENDENT
- else {
- i2c_operation_t *i2c_operation = &i2c_master->i2c_trans.ops[i2c_master->read_buf_pos];
- portENTER_CRITICAL_ISR(&i2c_master->base->spinlock);
- i2c_ll_read_rxfifo(hal->dev, i2c_operation->data + i2c_operation->bytes_used, i2c_master->read_len_static);
- i2c_ll_read_rxfifo(hal->dev, i2c_master->i2c_trans.ops[i2c_master->read_buf_pos + 1].data, 1);
- i2c_master->w_r_size = i2c_master->read_len_static + 1;
- i2c_master->contains_read = false;
- portEXIT_CRITICAL_ISR(&i2c_master->base->spinlock);
- }
- #endif
- }
- static void IRAM_ATTR i2c_master_isr_handler_default(void *arg)
- {
- i2c_master_bus_handle_t i2c_master = (i2c_master_bus_t*) arg;
- i2c_hal_context_t *hal = &i2c_master->base->hal;
- portBASE_TYPE HPTaskAwoken = pdFALSE;
- uint32_t int_mask;
- BaseType_t ret = pdTRUE;
- i2c_master->trans_done = false;
- i2c_ll_get_intr_mask(hal->dev, &int_mask);
- i2c_ll_clear_intr_mask(hal->dev, int_mask);
- if (int_mask == 0) {
- return;
- }
- if (int_mask == I2C_LL_INTR_NACK) {
- atomic_store(&i2c_master->status, I2C_STATUS_ACK_ERROR);
- i2c_master->event = I2C_EVENT_NACK;
- } else if (int_mask == I2C_LL_INTR_TIMEOUT || int_mask == I2C_LL_INTR_ARBITRATION) {
- atomic_store(&i2c_master->status, I2C_STATUS_TIMEOUT);
- } else if (int_mask == I2C_LL_INTR_MST_COMPLETE) {
- i2c_master->trans_done = true;
- i2c_master->event = I2C_EVENT_DONE;
- }
- if (i2c_master->contains_read == true) {
- i2c_isr_receive_handler(i2c_master);
- }
- if (i2c_master->asnyc_trans) {
- i2c_master_dev_handle_t i2c_dev = NULL;
- i2c_master_device_list_t *device_item;
- xSemaphoreTakeFromISR(i2c_master->bus_lock_mux, &HPTaskAwoken);
- SLIST_FOREACH(device_item, &i2c_master->device_list, next) {
- if (device_item->device->device_address == i2c_master->i2c_trans.device_address) {
- i2c_dev = device_item->device;
- break;
- }
- }
- xSemaphoreGiveFromISR(i2c_master->bus_lock_mux, &HPTaskAwoken);
- if (i2c_dev == NULL) {
- return;
- }
- i2c_master_event_data_t evt = {
- .event = i2c_master->event,
- };
- s_i2c_send_command_async(i2c_master, &HPTaskAwoken);
- if (i2c_master->trans_done) {
- if (i2c_dev->on_trans_done) {
- i2c_dev->on_trans_done(i2c_dev, &evt, i2c_dev->user_ctx);
- }
- if (i2c_master->new_queue && i2c_master->num_trans_inqueue > 0 && i2c_master->in_progress == false) {
- i2c_transaction_t t = {};
- i2c_master->num_trans_inqueue--;
- i2c_master->new_queue = false;
- t.cmd_count = 0;
- t.device_address = 0;
- t.ops = NULL;
- ret = xQueueReceiveFromISR(i2c_master->trans_queues[I2C_TRANS_QUEUE_PROGRESS], &t, &HPTaskAwoken);
- if (ret == pdTRUE) {
- i2c_master->queue_trans = true;
- atomic_init(&i2c_master->trans_idx, 0);
- atomic_store(&i2c_master->status, I2C_STATUS_IDLE);
- i2c_master->cmd_idx = 0;
- i2c_master->rx_cnt = 0;
- i2c_master->read_len_static = 0;
- i2c_ll_txfifo_rst(hal->dev);
- i2c_ll_rxfifo_rst(hal->dev);
- i2c_ll_enable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR);
- i2c_master->i2c_trans = t;
- memcpy(i2c_master->i2c_ops, t.ops, t.cmd_count * sizeof(i2c_operation_t));
- s_i2c_send_command_async(i2c_master, &HPTaskAwoken);
- }
- }
- }
- } else {
- xSemaphoreGiveFromISR(i2c_master->cmd_semphr, &HPTaskAwoken);
- }
- if (HPTaskAwoken == pdTRUE) {
- portYIELD_FROM_ISR();
- }
- }
- static esp_err_t i2c_param_master_config(i2c_bus_handle_t handle, const i2c_master_bus_config_t *i2c_conf)
- {
- i2c_hal_context_t *hal = &handle->hal;
- ESP_RETURN_ON_ERROR(i2c_common_set_pins(handle), TAG, "i2c master set pin failed");
- ESP_RETURN_ON_ERROR(i2c_select_periph_clock(handle, i2c_conf->clk_source), TAG, "i2c select clock failed");
- handle->clk_src = i2c_conf->clk_source;
- portENTER_CRITICAL(&handle->spinlock);
- i2c_hal_master_init(hal);
- i2c_ll_update(hal->dev);
- portEXIT_CRITICAL(&handle->spinlock);
- return ESP_OK;
- }
- static esp_err_t i2c_master_bus_destroy(i2c_master_bus_handle_t bus_handle)
- {
- ESP_RETURN_ON_FALSE(bus_handle, ESP_ERR_INVALID_ARG, TAG, "no memory for i2c master bus");
- i2c_master_bus_handle_t i2c_master = bus_handle;
- if(i2c_release_bus_handle(i2c_master->base) == 0) {
- if (i2c_master) {
- if (i2c_master->base->intr_handle) {
- ESP_RETURN_ON_ERROR(esp_intr_free(i2c_master->base->intr_handle), TAG, "delete interrupt service failed");
- }
- if (i2c_master->base->pm_lock) {
- ESP_RETURN_ON_ERROR(esp_pm_lock_delete(i2c_master->base->pm_lock), TAG, "delete pm_lock failed");
- }
- if (i2c_master->bus_lock_mux) {
- vSemaphoreDeleteWithCaps(i2c_master->bus_lock_mux);
- i2c_master->bus_lock_mux = NULL;
- }
- if (i2c_master->cmd_semphr) {
- vSemaphoreDeleteWithCaps(i2c_master->cmd_semphr);
- i2c_master->cmd_semphr = NULL;
- }
- if (i2c_master->queues_storage) {
- free(i2c_master->queues_storage);
- }
- if (i2c_master->i2c_anyc_ops) {
- for (int i = 0; i < i2c_master->index; i++) {
- if (i2c_master->i2c_anyc_ops[i]) {
- free(i2c_master->i2c_anyc_ops[i]);
- }
- }
- free(i2c_master->i2c_anyc_ops);
- }
- if (i2c_master->anyc_write_buffer) {
- for (int i = 0; i < i2c_master->index; i++) {
- if (i2c_master->anyc_write_buffer[i]) {
- free(i2c_master->anyc_write_buffer[i]);
- }
- }
- free(i2c_master->anyc_write_buffer);
- }
- for (int i = 0; i < I2C_TRANS_QUEUE_MAX; i++) {
- if (i2c_master->trans_queues[i]) {
- vQueueDelete(i2c_master->trans_queues[i]);
- }
- }
- bus_handle = NULL;
- }
- free(i2c_master);
- } else {
- free(i2c_master);
- }
- return ESP_OK;
- }
- static esp_err_t s_i2c_asynchronous_transaction(i2c_master_dev_handle_t i2c_dev, i2c_operation_t *i2c_ops, size_t ops_dim, int timeout_ms)
- {
- if (i2c_dev->master_bus->sent_all == true && i2c_dev->master_bus->num_trans_inqueue == 0) {
- memcpy(i2c_dev->master_bus->i2c_ops, i2c_ops, sizeof(i2c_operation_t) * ops_dim);
- i2c_dev->master_bus->addr_10bits_bus = i2c_dev->addr_10bits;
- i2c_dev->master_bus->i2c_trans = (i2c_transaction_t) {
- .device_address = i2c_dev->device_address,
- .ops = i2c_dev->master_bus->i2c_ops,
- .cmd_count = ops_dim,
- };
- i2c_dev->master_bus->sent_all = false;
- i2c_dev->master_bus->trans_finish = false;
- i2c_dev->master_bus->queue_trans = false;
- ESP_RETURN_ON_ERROR(s_i2c_transaction_start(i2c_dev, timeout_ms), TAG, "I2C transaction failed");
- } else {
- i2c_dev->master_bus->i2c_anyc_ops[i2c_dev->master_bus->index]=(i2c_operation_t(*))heap_caps_calloc(1, sizeof(i2c_operation_t) * 6, I2C_MEM_ALLOC_CAPS);
- memcpy(i2c_dev->master_bus->i2c_anyc_ops[i2c_dev->master_bus->index], i2c_ops, sizeof(i2c_operation_t) * ops_dim);
- i2c_transaction_t i2c_queue_pre;
- if (i2c_dev->master_bus->num_trans_inflight < i2c_dev->master_bus->queue_size) {
- ESP_RETURN_ON_FALSE(xQueueReceive(i2c_dev->master_bus->trans_queues[I2C_TRANS_QUEUE_READY], &i2c_queue_pre, portMAX_DELAY) == pdTRUE, ESP_FAIL, TAG, "no transaction in the ready queue");
- } else {
- ESP_RETURN_ON_FALSE(xQueueReceive(i2c_dev->master_bus->trans_queues[I2C_TRANS_QUEUE_COMPLETE], &i2c_queue_pre, portMAX_DELAY) == pdTRUE, ESP_FAIL, TAG, "recycle transaction from done queue failed");
- i2c_dev->master_bus->num_trans_inflight--;
- }
- i2c_queue_pre = (i2c_transaction_t) {
- .device_address = i2c_dev->device_address,
- .ops = i2c_dev->master_bus->i2c_anyc_ops[i2c_dev->master_bus->index],
- .cmd_count = ops_dim,
- };
- i2c_dev->master_bus->index++;
- if (xQueueSend(i2c_dev->master_bus->trans_queues[I2C_TRANS_QUEUE_PROGRESS], &i2c_queue_pre, portMAX_DELAY) == pdTRUE) {
- i2c_dev->master_bus->num_trans_inflight++;
- i2c_dev->master_bus->num_trans_inqueue++;
- if (i2c_dev->master_bus->sent_all == true) {
- // Oh no, you cannot get the queue from ISR, so you get queue here.
- xQueueReceive(i2c_dev->master_bus->trans_queues[I2C_TRANS_QUEUE_PROGRESS], &i2c_queue_pre, portMAX_DELAY);
- i2c_dev->master_bus->num_trans_inflight--;
- i2c_dev->master_bus->num_trans_inqueue--;
- i2c_dev->master_bus->sent_all = false;
- i2c_dev->master_bus->trans_finish = false;
- i2c_dev->master_bus->queue_trans = false;
- ESP_RETURN_ON_ERROR(s_i2c_transaction_start(i2c_dev, timeout_ms), TAG, "I2C transaction failed");
- }
- } else {
- ESP_RETURN_ON_FALSE(xQueueSend(i2c_dev->master_bus->trans_queues[I2C_TRANS_QUEUE_READY], &i2c_queue_pre, 0) == pdTRUE, ESP_ERR_INVALID_STATE, TAG, "ready queue full");
- }
- }
- return ESP_OK;
- }
- static esp_err_t s_i2c_synchronous_transaction(i2c_master_dev_handle_t i2c_dev, i2c_operation_t *i2c_ops, size_t ops_dim, int timeout_ms)
- {
- i2c_dev->master_bus->trans_done = false;
- TickType_t ticks_to_wait = (timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
- if (xSemaphoreTake(i2c_dev->master_bus->bus_lock_mux, ticks_to_wait) != pdTRUE) {
- return ESP_ERR_TIMEOUT;
- }
- memcpy(i2c_dev->master_bus->i2c_ops, i2c_ops, sizeof(i2c_operation_t) * ops_dim);
- i2c_dev->master_bus->addr_10bits_bus = i2c_dev->addr_10bits;
- i2c_dev->master_bus->i2c_trans = (i2c_transaction_t) {
- .device_address = i2c_dev->device_address,
- .ops = i2c_dev->master_bus->i2c_ops,
- .cmd_count = ops_dim,
- };
- i2c_dev->master_bus->sent_all = false;
- i2c_dev->master_bus->trans_finish = false;
- i2c_dev->master_bus->queue_trans = false;
- ESP_RETURN_ON_ERROR(s_i2c_transaction_start(i2c_dev, timeout_ms), TAG, "I2C transaction failed");
- xSemaphoreGive(i2c_dev->master_bus->bus_lock_mux);
- return ESP_OK;
- }
- esp_err_t i2c_new_master_bus(const i2c_master_bus_config_t *bus_config, i2c_master_bus_handle_t *ret_bus_handle)
- {
- #if CONFIG_I2C_ENABLE_DEBUG_LOG
- esp_log_level_set(TAG, ESP_LOG_DEBUG);
- #endif
- esp_err_t ret = ESP_OK;
- i2c_master_bus_t *i2c_master = NULL;
- i2c_port_num_t i2c_port_num = bus_config->i2c_port;
- ESP_RETURN_ON_FALSE(bus_config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
- ESP_RETURN_ON_FALSE((bus_config->i2c_port < SOC_I2C_NUM || bus_config->i2c_port == -1), ESP_ERR_INVALID_ARG, TAG, "invalid i2c port number");
- ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(bus_config->sda_io_num) && GPIO_IS_VALID_GPIO(bus_config->scl_io_num), ESP_ERR_INVALID_ARG, TAG, "invalid SDA/SCL pin number");
- bool bus_occupied = false;
- bool bus_found = false;
- i2c_master = heap_caps_calloc(1, sizeof(i2c_master_bus_t) + 20 * sizeof(i2c_transaction_t), I2C_MEM_ALLOC_CAPS);
- ESP_RETURN_ON_FALSE(i2c_master, ESP_ERR_NO_MEM, TAG, "no memory for i2c master bus");
- _lock_acquire(&s_i2c_bus_acquire);
- if (i2c_port_num == -1) {
- for (int i = 0; i < SOC_I2C_NUM; i++) {
- bus_occupied = i2c_bus_occupied(i);
- if (bus_occupied == false) {
- ret = i2c_acquire_bus_handle(i, &i2c_master->base, I2C_BUS_MODE_MASTER);
- if (ret != ESP_OK) {
- ESP_LOGE(TAG, "acquire bus failed");
- _lock_release(&s_i2c_bus_acquire);
- goto err;
- }
- bus_found = true;
- i2c_port_num = i;
- break;
- }
- }
- ESP_GOTO_ON_FALSE((bus_found == true), ESP_ERR_NOT_FOUND, err, TAG, "acquire bus failed, no free bus");
- } else {
- ret = i2c_acquire_bus_handle(i2c_port_num, &i2c_master->base, I2C_BUS_MODE_MASTER);
- if (ret != ESP_OK) {
- ESP_LOGE(TAG, "acquire bus failed");
- _lock_release(&s_i2c_bus_acquire);
- goto err;
- }
- }
- _lock_release(&s_i2c_bus_acquire);
- i2c_hal_context_t *hal = &i2c_master->base->hal;
- i2c_master->base->scl_num = bus_config->scl_io_num;
- i2c_master->base->sda_num = bus_config->sda_io_num;
- i2c_master->base->pull_up_enable = bus_config->flags.enable_internal_pullup;
- ESP_GOTO_ON_ERROR(i2c_param_master_config(i2c_master->base, bus_config), err, TAG, "i2c configure parameter failed");
- i2c_master->bus_lock_mux = xSemaphoreCreateBinaryWithCaps(I2C_MEM_ALLOC_CAPS);
- ESP_GOTO_ON_FALSE(i2c_master->bus_lock_mux, ESP_ERR_NO_MEM, err, TAG, "No memory for binary semaphore");
- xSemaphoreGive(i2c_master->bus_lock_mux);
- i2c_master->cmd_semphr = xSemaphoreCreateBinaryWithCaps(I2C_MEM_ALLOC_CAPS);
- ESP_GOTO_ON_FALSE(i2c_master->cmd_semphr, ESP_ERR_NO_MEM, err, TAG, "no memory for i2c semaphore struct");
- portENTER_CRITICAL(&i2c_master->base->spinlock);
- i2c_ll_clear_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR);
- portEXIT_CRITICAL(&i2c_master->base->spinlock);
- if (bus_config->intr_priority) {
- ESP_RETURN_ON_FALSE(1 << (bus_config->intr_priority) & I2C_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, TAG, "invalid interrupt priority:%d", bus_config->intr_priority);
- }
- xSemaphoreTake(i2c_master->bus_lock_mux, portMAX_DELAY);
- SLIST_INIT(&i2c_master->device_list);
- xSemaphoreGive(i2c_master->bus_lock_mux);
- // Initialize the queue
- if (bus_config->trans_queue_depth) {
- i2c_master->asnyc_trans = true;
- i2c_master->sent_all = true;
- i2c_master->trans_finish = true;
- i2c_master->new_queue = true;
- i2c_master->queue_size = bus_config->trans_queue_depth;
- i2c_master->queues_storage = (uint8_t*)heap_caps_calloc(bus_config->trans_queue_depth * I2C_TRANS_QUEUE_MAX, sizeof(i2c_transaction_t), I2C_MEM_ALLOC_CAPS);
- ESP_RETURN_ON_FALSE(i2c_master->queues_storage, ESP_ERR_NO_MEM, TAG, "no mem for queue storage");
- i2c_transaction_t **pp_trans_desc = (i2c_transaction_t **)i2c_master->queues_storage;
- for (int i = 0; i < I2C_TRANS_QUEUE_MAX; i++) {
- i2c_master->trans_queues[i] = xQueueCreate(bus_config->trans_queue_depth, sizeof(i2c_transaction_t));
- pp_trans_desc += bus_config->trans_queue_depth;
- // sanity check
- assert(i2c_master->trans_queues[i]);
- }
- i2c_transaction_t trans_pre = {};
- for (int i = 0; i < bus_config->trans_queue_depth ; i++) {
- trans_pre = i2c_master->i2c_trans_pool[i];
- ESP_RETURN_ON_FALSE(xQueueSend(i2c_master->trans_queues[I2C_TRANS_QUEUE_READY], &trans_pre, 0) == pdTRUE,
- ESP_ERR_INVALID_STATE, TAG, "ready queue full");
- }
- i2c_master->i2c_anyc_ops = (i2c_operation_t(**))heap_caps_calloc(bus_config->trans_queue_depth, sizeof(i2c_operation_t*), I2C_MEM_ALLOC_CAPS);
- i2c_master->anyc_write_buffer = (uint8_t**)heap_caps_calloc(bus_config->trans_queue_depth, sizeof(uint8_t*), I2C_MEM_ALLOC_CAPS);
- }
- int isr_flags = I2C_INTR_ALLOC_FLAG;
- if (bus_config->intr_priority) {
- isr_flags |= 1 << (bus_config->intr_priority);
- }
- ret = esp_intr_alloc_intrstatus(i2c_periph_signal[i2c_port_num].irq, isr_flags, (uint32_t)i2c_ll_get_interrupt_status_reg(hal->dev), I2C_LL_MASTER_EVENT_INTR, i2c_master_isr_handler_default, i2c_master, &i2c_master->base->intr_handle);
- ESP_GOTO_ON_ERROR(ret, err, TAG, "install i2c master interrupt failed");
- atomic_init(&i2c_master->status, I2C_STATUS_IDLE);
- i2c_ll_enable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR);
- i2c_ll_master_set_filter(hal->dev, bus_config->glitch_ignore_cnt);
- xSemaphoreGive(i2c_master->cmd_semphr);
- *ret_bus_handle = i2c_master;
- return ESP_OK;
- err:
- if (i2c_master) {
- i2c_master_bus_destroy(i2c_master);
- }
- return ret;
- }
- 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)
- {
- esp_err_t ret = ESP_OK;
- ESP_RETURN_ON_FALSE((bus_handle != NULL), ESP_ERR_INVALID_ARG, TAG, "this bus is not initialized, please call `i2c_new_master_bus`");
- if(bus_handle->base->bus_mode != I2C_BUS_MODE_MASTER) {
- ESP_LOGE(TAG, "This is not master bus!");
- return ESP_ERR_INVALID_ARG;
- }
- i2c_master_bus_t *i2c_master = bus_handle;
- i2c_master_dev_t *i2c_dev = heap_caps_calloc(1, sizeof(i2c_master_dev_t), I2C_MEM_ALLOC_CAPS);
- ESP_GOTO_ON_FALSE(i2c_dev, ESP_ERR_NO_MEM, err, TAG, "no memory for i2c master device");
- i2c_dev->device_address = dev_config->device_address;
- i2c_dev->scl_speed_hz = dev_config->scl_speed_hz;
- i2c_dev->addr_10bits = dev_config->dev_addr_length;
- i2c_dev->master_bus = i2c_master;
- i2c_master_device_list_t *device_item = (i2c_master_device_list_t *)calloc(1, sizeof(i2c_master_device_list_t));
- ESP_RETURN_ON_FALSE((device_item != NULL), ESP_ERR_NO_MEM, TAG, "no memory for i2c device item`");
- device_item->device = i2c_dev;
- xSemaphoreTake(bus_handle->bus_lock_mux, portMAX_DELAY);
- SLIST_INSERT_HEAD(&bus_handle->device_list, device_item, next);
- xSemaphoreGive(bus_handle->bus_lock_mux);
- *ret_handle = i2c_dev;
- return ret;
- err:
- if (i2c_dev) {
- i2c_master_bus_rm_device(i2c_dev);
- }
- return ret;
- }
- esp_err_t i2c_master_bus_rm_device(i2c_master_dev_handle_t handle)
- {
- ESP_RETURN_ON_FALSE((handle != NULL), ESP_ERR_INVALID_ARG, TAG, "this device is not initialized");
- ESP_RETURN_ON_FALSE((((int)atomic_load(&handle->master_bus->status) > (int)I2C_STATUS_START)), ESP_ERR_INVALID_STATE, TAG, "Wrong I2C status, cannot delete device");
- i2c_master_bus_handle_t i2c_master = handle->master_bus;
- i2c_master_device_list_t *device_item;
- xSemaphoreTake(handle->master_bus->bus_lock_mux, portMAX_DELAY);
- SLIST_FOREACH(device_item, &i2c_master->device_list, next) {
- if (handle == device_item->device) {
- SLIST_REMOVE(&i2c_master->device_list, device_item, i2c_master_device_list, next);
- free(device_item);
- break;
- }
- }
- xSemaphoreGive(handle->master_bus->bus_lock_mux);
- if (handle) {
- free(handle);
- handle = NULL;
- }
- return ESP_OK;
- }
- esp_err_t i2c_del_master_bus(i2c_master_bus_handle_t bus_handle)
- {
- ESP_LOGD(TAG, "del i2c bus(%d)", bus_handle->base->port_num);
- ESP_RETURN_ON_ERROR(i2c_master_bus_destroy(bus_handle), TAG, "destroy i2c bus failed");
- return ESP_OK;
- }
- esp_err_t i2c_master_bus_reset(i2c_master_bus_handle_t handle)
- {
- ESP_RETURN_ON_FALSE((handle != NULL), ESP_ERR_INVALID_ARG, TAG, "This bus is not initialized");
- // Reset I2C master bus
- ESP_RETURN_ON_ERROR(s_i2c_hw_fsm_reset(handle), TAG, "I2C master bus reset failed");
- // Reset I2C status state
- atomic_store(&handle->status, I2C_STATUS_IDLE);
- return ESP_OK;
- }
- 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)
- {
- ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
- ESP_RETURN_ON_FALSE((write_buffer != NULL) && (write_size > 0), ESP_ERR_INVALID_ARG, TAG, "i2c transmit buffer or size invalid");
- if (i2c_dev->master_bus->asnyc_trans == false) {
- i2c_operation_t i2c_ops[] = {
- {.hw_cmd = I2C_TRANS_START_COMMAND},
- {.hw_cmd = I2C_TRANS_WRITE_COMMAND(false), .data = (uint8_t *)write_buffer, .total_bytes = write_size},
- {.hw_cmd = I2C_TRANS_STOP_COMMAND},
- };
- ESP_RETURN_ON_ERROR(s_i2c_synchronous_transaction(i2c_dev, i2c_ops, DIM(i2c_ops), xfer_timeout_ms), TAG, "I2C transaction failed");
- } else {
- i2c_dev->master_bus->anyc_write_buffer[i2c_dev->master_bus->index] = (uint8_t*)heap_caps_calloc(1, sizeof(uint8_t)*write_size, I2C_MEM_ALLOC_CAPS);
- memcpy(i2c_dev->master_bus->anyc_write_buffer[i2c_dev->master_bus->index], write_buffer, write_size);
- i2c_operation_t i2c_ops[] = {
- {.hw_cmd = I2C_TRANS_START_COMMAND},
- {.hw_cmd = I2C_TRANS_WRITE_COMMAND(false), .data = (uint8_t *)i2c_dev->master_bus->anyc_write_buffer[i2c_dev->master_bus->index], .total_bytes = write_size},
- {.hw_cmd = I2C_TRANS_STOP_COMMAND},
- };
- ESP_RETURN_ON_ERROR(s_i2c_asynchronous_transaction(i2c_dev, i2c_ops, DIM(i2c_ops), xfer_timeout_ms), TAG, "I2C transaction failed");
- }
- return ESP_OK;
- }
- 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)
- {
- ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
- ESP_RETURN_ON_FALSE((write_buffer != NULL) && (write_size > 0), ESP_ERR_INVALID_ARG, TAG, "i2c transmit buffer or size invalid");
- ESP_RETURN_ON_FALSE((read_buffer != NULL) && (read_size > 0), ESP_ERR_INVALID_ARG, TAG, "i2c receive buffer or size invalid");
- if (i2c_dev->master_bus->asnyc_trans == false) {
- i2c_operation_t i2c_ops[] = {
- {.hw_cmd = I2C_TRANS_START_COMMAND},
- {.hw_cmd = I2C_TRANS_WRITE_COMMAND(false), .data = (uint8_t *)write_buffer, .total_bytes = write_size},
- {.hw_cmd = I2C_TRANS_START_COMMAND},
- {.hw_cmd = I2C_TRANS_READ_COMMAND(ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
- {.hw_cmd = I2C_TRANS_READ_COMMAND(NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
- {.hw_cmd = I2C_TRANS_STOP_COMMAND},
- };
- ESP_RETURN_ON_ERROR(s_i2c_synchronous_transaction(i2c_dev, i2c_ops, DIM(i2c_ops), xfer_timeout_ms), TAG, "I2C transaction failed");
- } else {
- i2c_dev->master_bus->anyc_write_buffer[i2c_dev->master_bus->index] = (uint8_t*)heap_caps_calloc(1, sizeof(uint8_t)*write_size, I2C_MEM_ALLOC_CAPS);
- memcpy(i2c_dev->master_bus->anyc_write_buffer[i2c_dev->master_bus->index], write_buffer, write_size);
- i2c_operation_t i2c_ops[] = {
- {.hw_cmd = I2C_TRANS_START_COMMAND},
- {.hw_cmd = I2C_TRANS_WRITE_COMMAND(false), .data = (uint8_t *)i2c_dev->master_bus->anyc_write_buffer[i2c_dev->master_bus->index], .total_bytes = write_size},
- {.hw_cmd = I2C_TRANS_START_COMMAND},
- {.hw_cmd = I2C_TRANS_READ_COMMAND(ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
- {.hw_cmd = I2C_TRANS_READ_COMMAND(NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
- {.hw_cmd = I2C_TRANS_STOP_COMMAND},
- };
- ESP_RETURN_ON_ERROR(s_i2c_asynchronous_transaction(i2c_dev, i2c_ops, DIM(i2c_ops), xfer_timeout_ms), TAG, "I2C transaction failed");
- }
- return ESP_OK;
- }
- 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)
- {
- ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
- ESP_RETURN_ON_FALSE((read_buffer != NULL) && (read_size > 0), ESP_ERR_INVALID_ARG, TAG, "i2c receive buffer or size invalid");
- i2c_operation_t i2c_ops[] = {
- {.hw_cmd = I2C_TRANS_START_COMMAND},
- {.hw_cmd = I2C_TRANS_READ_COMMAND(ACK_VAL), .data = read_buffer, .total_bytes = read_size - 1},
- {.hw_cmd = I2C_TRANS_READ_COMMAND(NACK_VAL), .data = (read_buffer + read_size - 1), .total_bytes = 1},
- {.hw_cmd = I2C_TRANS_STOP_COMMAND},
- };
- if (i2c_dev->master_bus->asnyc_trans == false) {
- ESP_RETURN_ON_ERROR(s_i2c_synchronous_transaction(i2c_dev, i2c_ops, DIM(i2c_ops), xfer_timeout_ms), TAG, "I2C transaction failed");
- } else {
- ESP_RETURN_ON_ERROR(s_i2c_asynchronous_transaction(i2c_dev, i2c_ops, DIM(i2c_ops), xfer_timeout_ms), TAG, "I2C transaction failed");
- }
- return ESP_OK;
- }
- esp_err_t i2c_master_probe(i2c_master_bus_handle_t i2c_master, uint16_t address, int xfer_timeout_ms)
- {
- ESP_RETURN_ON_FALSE(i2c_master != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
- i2c_operation_t i2c_ops[] = {
- {.hw_cmd = I2C_TRANS_START_COMMAND},
- {.hw_cmd = I2C_TRANS_STOP_COMMAND},
- };
- TickType_t ticks_to_wait = (xfer_timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(xfer_timeout_ms);
- i2c_master->i2c_trans = (i2c_transaction_t) {
- .device_address = address,
- .ops = i2c_ops,
- .cmd_count = DIM(i2c_ops),
- };
- s_i2c_send_commands(i2c_master, ticks_to_wait);
- if (i2c_master->status == I2C_STATUS_ACK_ERROR) {
- return ESP_ERR_NOT_FOUND;
- }
- return ESP_OK;
- }
- 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)
- {
- ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
- if (i2c_dev->master_bus->asnyc_trans == false) {
- ESP_LOGE(TAG, "I2C transaction queue is not initialized, so you can't use callback here, please resister the bus again with trans_queue_depth != 0");
- return ESP_ERR_INVALID_STATE;
- }
- #if CONFIG_I2C_ISR_IRAM_SAFE
- if (cbs->on_trans_done) {
- ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_done), ESP_ERR_INVALID_ARG, TAG, "i2c trans done callback not in IRAM");
- }
- if (user_data) {
- ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
- }
- #endif // CONFIG_I2C_ISR_IRAM_SAFE
- i2c_dev->on_trans_done = cbs->on_trans_done;
- i2c_dev->user_ctx = user_data;
- return ESP_OK;
- }
- esp_err_t i2c_master_wait_all_done(i2c_master_bus_handle_t i2c_master, int timeout_ms)
- {
- ESP_RETURN_ON_FALSE(i2c_master, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
- TickType_t wait_ticks = timeout_ms < 0 ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
- i2c_transaction_t t;
- size_t cnt = i2c_master->num_trans_inflight;
- for (size_t i = 0; i < cnt; i++) {
- ESP_RETURN_ON_FALSE(xQueueReceive(i2c_master->trans_queues[I2C_TRANS_QUEUE_COMPLETE], &t, wait_ticks) == pdTRUE,
- ESP_ERR_TIMEOUT, TAG, "flush timeout");
- ESP_RETURN_ON_FALSE(xQueueSend(i2c_master->trans_queues[I2C_TRANS_QUEUE_READY], &t, 0) == pdTRUE,
- ESP_ERR_INVALID_STATE, TAG, "ready queue full");
- i2c_master->num_trans_inflight--;
- }
- return ESP_OK;
- }
|