xtensa/esp32: Adds I2C polled support.
This commit is contained in:
parent
bafac8b560
commit
7300bc8f1c
@ -35,6 +35,7 @@
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
@ -71,6 +72,12 @@
|
||||
((_ack_val) << 10) + \
|
||||
(_bytes))
|
||||
|
||||
/* Helper */
|
||||
|
||||
#ifdef CONFIG_I2C_POLLED
|
||||
#define TIMESPEC_TO_US(sec, nano) ((sec * USEC_PER_SEC) + (nano / NSEC_PER_USEC))
|
||||
#endif
|
||||
|
||||
/* Default option */
|
||||
|
||||
#define I2C_FIFO_SIZE (255)
|
||||
@ -107,7 +114,9 @@ enum esp32_i2cstate_e
|
||||
I2CSTATE_IDLE = 0,
|
||||
I2CSTATE_PROC,
|
||||
I2CSTATE_STOP,
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
I2CSTATE_FINISH
|
||||
#endif
|
||||
};
|
||||
|
||||
/* I2C hardware command */
|
||||
@ -160,9 +169,11 @@ struct esp32_i2c_config_s
|
||||
uint8_t scl_pin; /* GPIO configuration for SCL as SCL */
|
||||
uint8_t sda_pin; /* GPIO configuration for SDA as SDA */
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
uint8_t cpu; /* CPU ID */
|
||||
uint8_t periph; /* peripher ID */
|
||||
uint8_t periph; /* Peripheral ID */
|
||||
uint8_t irq; /* Interrupt ID */
|
||||
#endif
|
||||
|
||||
uint32_t clk_bit; /* Clock enable bit */
|
||||
uint32_t rst_bit; /* I2C reset bit */
|
||||
@ -183,9 +194,12 @@ struct esp32_i2c_priv_s
|
||||
/* Port configuration */
|
||||
|
||||
const struct esp32_i2c_config_s *config;
|
||||
int refs; /* Referernce count */
|
||||
int refs; /* Reference count */
|
||||
sem_t sem_excl; /* Mutual exclusion semaphore */
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
sem_t sem_isr; /* Interrupt wait semaphore */
|
||||
#endif
|
||||
|
||||
/* I2C work state (see enum esp32_i2cstate_e) */
|
||||
|
||||
@ -196,11 +210,13 @@ struct esp32_i2c_priv_s
|
||||
uint8_t msgid; /* Current message ID */
|
||||
ssize_t bytes; /* Processed data bytes */
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
int cpuint; /* CPU interrupt assigned to this I2C */
|
||||
#endif
|
||||
|
||||
uint32_t error; /* I2C transform error */
|
||||
|
||||
bool ready_read; /* If I2C has can read date */
|
||||
bool ready_read; /* If I2C has read data */
|
||||
|
||||
uint32_t clk_freq; /* Current I2C Clock frequency */
|
||||
|
||||
@ -227,6 +243,11 @@ static void esp32_i2c_deinit(FAR struct esp32_i2c_priv_s *priv);
|
||||
static int esp32_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
FAR struct i2c_msg_s *msgs,
|
||||
int count);
|
||||
static inline void esp32_i2c_process(struct esp32_i2c_priv_s *priv,
|
||||
uint32_t status);
|
||||
#ifdef CONFIG_I2C_POLLED
|
||||
static int esp32_i2c_polling_waitdone(FAR struct esp32_i2c_priv_s *priv);
|
||||
#endif
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
static int esp32_i2c_reset(FAR struct i2c_master_s *dev);
|
||||
#endif
|
||||
@ -265,9 +286,11 @@ static const struct esp32_i2c_config_s esp32_i2c0_config =
|
||||
.clk_freq = I2C_CLK_FREQ_DEF,
|
||||
.scl_pin = CONFIG_ESP32_I2C0_SCLPIN,
|
||||
.sda_pin = CONFIG_ESP32_I2C0_SDAPIN,
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
.cpu = 0,
|
||||
.periph = ESP32_PERIPH_I2C_EXT0,
|
||||
.irq = ESP32_IRQ_I2C_EXT0,
|
||||
#endif
|
||||
.clk_bit = DPORT_I2C_EXT0_CLK_EN,
|
||||
.rst_bit = DPORT_I2C_EXT0_RST,
|
||||
.scl_insig = I2CEXT0_SCL_IN_IDX,
|
||||
@ -296,9 +319,11 @@ static const struct esp32_i2c_config_s esp32_i2c1_config =
|
||||
.clk_freq = I2C_CLK_FREQ_DEF,
|
||||
.scl_pin = CONFIG_ESP32_I2C1_SCLPIN,
|
||||
.sda_pin = CONFIG_ESP32_I2C1_SDAPIN,
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
.cpu = 0,
|
||||
.periph = ESP32_PERIPH_I2C_EXT1,
|
||||
.irq = ESP32_IRQ_I2C_EXT1,
|
||||
#endif
|
||||
.clk_bit = DPORT_I2C_EXT1_CLK_EN,
|
||||
.rst_bit = DPORT_I2C_EXT1_RST,
|
||||
.scl_insig = I2CEXT1_SCL_IN_IDX,
|
||||
@ -415,16 +440,29 @@ static void esp32_i2c_sendstart(FAR struct esp32_i2c_priv_s *priv)
|
||||
{
|
||||
struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
|
||||
|
||||
/* Load a start cmd, write and end in controller. */
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_COMD0_OFFSET,
|
||||
I2C_BASE_CMD(I2C_CMD_RESTART, 0));
|
||||
esp32_i2c_set_reg(priv, I2C_COMD1_OFFSET,
|
||||
I2C_SEND_CMD(I2C_CMD_WRITE, 1, 1));
|
||||
esp32_i2c_set_reg(priv, I2C_COMD2_OFFSET,
|
||||
I2C_BASE_CMD(I2C_CMD_END, 0));
|
||||
|
||||
/* Load the slave address and the flags to the FIFO. */
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_DATA_OFFSET, (msg->addr << 1) |
|
||||
(msg->flags & I2C_M_READ));
|
||||
|
||||
/* Enable interrupts to detect the execution of an end cmd and
|
||||
* multiple errors.
|
||||
*/
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_INT_ENA_OFFSET, I2C_END_DETECT_INT_ENA |
|
||||
I2C_INT_ERR_EN_BITS);
|
||||
|
||||
/* Start sending the slave address and hold line. */
|
||||
|
||||
esp32_i2c_set_reg_bits(priv, I2C_CTR_OFFSET, I2C_TRANS_START_M);
|
||||
}
|
||||
|
||||
@ -444,11 +482,15 @@ static void esp32_i2c_senddata(FAR struct esp32_i2c_priv_s *priv)
|
||||
|
||||
n = n < I2C_FIFO_SIZE ? n : I2C_FIFO_SIZE;
|
||||
|
||||
/* Load a write operation */
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_COMD0_OFFSET,
|
||||
I2C_SEND_CMD(I2C_CMD_WRITE, 1, n));
|
||||
esp32_i2c_set_reg(priv, I2C_COMD1_OFFSET,
|
||||
I2C_BASE_CMD(I2C_CMD_END, 0));
|
||||
|
||||
/* Transfer the data from the msg buffer to the TX FIFO */
|
||||
|
||||
for (i = 0; i < n; i ++)
|
||||
{
|
||||
esp32_i2c_set_reg(priv, I2C_DATA_OFFSET,
|
||||
@ -457,6 +499,10 @@ static void esp32_i2c_senddata(FAR struct esp32_i2c_priv_s *priv)
|
||||
|
||||
priv->bytes += n;
|
||||
|
||||
/* Enable interrupts to detect the execution of an end cmd and
|
||||
* multiple errors.
|
||||
*/
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_INT_ENA_OFFSET, I2C_END_DETECT_INT_ENA |
|
||||
I2C_INT_ERR_EN_BITS);
|
||||
esp32_i2c_set_reg_bits(priv, I2C_CTR_OFFSET, I2C_TRANS_START_M);
|
||||
@ -466,7 +512,7 @@ static void esp32_i2c_senddata(FAR struct esp32_i2c_priv_s *priv)
|
||||
* Name: esp32_i2c_recvdata
|
||||
*
|
||||
* Description:
|
||||
* Receive I2C data
|
||||
* Transfer the received data from the RX FIFO to the message buffer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
@ -490,8 +536,9 @@ static void esp32_i2c_recvdata(struct esp32_i2c_priv_s *priv)
|
||||
* Name: esp32_i2c_startrecv
|
||||
*
|
||||
* Description:
|
||||
* Configure I2C to prepare receiving data and it will create an interrupt
|
||||
* to receive real data
|
||||
* Configure I2C to prepare receiving data and it will enable an interrupt
|
||||
* to detect the end of the receiving operation and to load the content
|
||||
* into the RX buffer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
@ -512,11 +559,17 @@ static void esp32_i2c_startrecv(struct esp32_i2c_priv_s *priv)
|
||||
ack_value = 1;
|
||||
}
|
||||
|
||||
/* Load read and end cmds */
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_COMD0_OFFSET,
|
||||
I2C_RECV_CMD(I2C_CMD_READ, ack_value, n));
|
||||
esp32_i2c_set_reg(priv, I2C_COMD1_OFFSET,
|
||||
I2C_BASE_CMD(I2C_CMD_END, 0));
|
||||
|
||||
/* Enable interrupts to detect the execution of an end cmd and
|
||||
* multiple errors.
|
||||
*/
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_INT_ENA_OFFSET, I2C_END_DETECT_INT_ENA |
|
||||
I2C_INT_ERR_EN_BITS);
|
||||
esp32_i2c_set_reg_bits(priv, I2C_CTR_OFFSET, I2C_TRANS_START_M);
|
||||
@ -532,6 +585,10 @@ static void esp32_i2c_startrecv(struct esp32_i2c_priv_s *priv)
|
||||
|
||||
static void esp32_i2c_sendstop(struct esp32_i2c_priv_s *priv)
|
||||
{
|
||||
/* Load a stop cmd and enable the interrupts that indicate end of a stop
|
||||
* cmd or error.
|
||||
*/
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_COMD0_OFFSET, I2C_BASE_CMD(I2C_CMD_STOP, 0));
|
||||
esp32_i2c_set_reg(priv, I2C_INT_ENA_OFFSET, I2C_TRANS_COMPLETE_INT_ENA |
|
||||
I2C_INT_ERR_EN_BITS);
|
||||
@ -656,24 +713,146 @@ static void esp32_i2c_reset_fsmc(FAR struct esp32_i2c_priv_s *priv)
|
||||
* Name: esp32_i2c_sem_waitdone
|
||||
*
|
||||
* Description:
|
||||
* Wait for a transfer to complete
|
||||
* Wait for a transfer to complete using an interruptible semaphore which
|
||||
* in unlocked from within the ISR context. This function is only used in
|
||||
* interrupt driven mode.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - Pointer to the internal driver state structure.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
static int esp32_i2c_sem_waitdone(FAR struct esp32_i2c_priv_s *priv)
|
||||
{
|
||||
int ret;
|
||||
struct timespec abstime;
|
||||
|
||||
/* Get the current absolute time and adds a offset as timeout */
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &abstime);
|
||||
|
||||
abstime.tv_sec += 10;
|
||||
abstime.tv_nsec += 0;
|
||||
|
||||
/* Wait on ISR semaphore */
|
||||
|
||||
ret = nxsem_timedwait_uninterruptible(&priv->sem_isr, &abstime);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_i2c_polling_waitdone
|
||||
*
|
||||
* Description:
|
||||
* Wait for a transfer to complete by polling status interrupt registers,
|
||||
* which indicates the status of the I2C operations. This function is only
|
||||
* used in polling driven mode.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - Pointer to the internal driver state structure.
|
||||
*
|
||||
* Returned Values:
|
||||
* Zero (OK) is returned on successfull transfer. -ETIMEDOUT is returned
|
||||
* in case a transfer didn't finish within the timeout interval. And ERROR
|
||||
* is returned in case of any I2C error during the transfer has happened.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifdef CONFIG_I2C_POLLED
|
||||
static int esp32_i2c_polling_waitdone(FAR struct esp32_i2c_priv_s *priv)
|
||||
{
|
||||
int ret;
|
||||
struct timespec current_time;
|
||||
struct timespec timeout;
|
||||
uint64_t current_us;
|
||||
uint64_t timeout_us;
|
||||
uint32_t status = 0;
|
||||
|
||||
/* Get the current absolute time and add an offset as timeout.
|
||||
* Preferable to use monotonic, so in case the time changes,
|
||||
* the time reference is kept, i.e., current time can't jump
|
||||
* forward and backwards.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_MONOTONIC, ¤t_time);
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, ¤t_time);
|
||||
#endif
|
||||
|
||||
timeout.tv_sec = current_time.tv_sec + 10;
|
||||
timeout.tv_nsec = current_time.tv_nsec + 0;
|
||||
|
||||
current_us = TIMESPEC_TO_US(current_time.tv_sec, current_time.tv_nsec);
|
||||
timeout_us = TIMESPEC_TO_US(timeout.tv_sec, timeout.tv_nsec);
|
||||
|
||||
/* Loop while a transfer is in progress
|
||||
* and an error didn't occur within the timeout
|
||||
*/
|
||||
|
||||
while ((current_us < timeout_us) && (priv->error == 0))
|
||||
{
|
||||
/* Check if any interrupt triggered, clear them
|
||||
* process the operation.
|
||||
*/
|
||||
|
||||
status = esp32_i2c_get_reg(priv, I2C_INT_STATUS_OFFSET);
|
||||
if (status != 0)
|
||||
{
|
||||
/* Check if the stop operation ended. Don't use
|
||||
* I2CSTATE_FINISH, because it is set before the stop
|
||||
* signal really ends. This works for interrupts because
|
||||
* the i2c_state is checked in the next interrupt when
|
||||
* stop signal has concluded. This is not the case of
|
||||
* polling.
|
||||
*/
|
||||
|
||||
if (status & I2C_TRANS_COMPLETE_INT_ST_M)
|
||||
{
|
||||
esp32_i2c_set_reg(priv, I2C_INT_CLR_OFFSET, status);
|
||||
break;
|
||||
}
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_INT_CLR_OFFSET, status);
|
||||
esp32_i2c_process(priv, status);
|
||||
}
|
||||
|
||||
/* Update current time */
|
||||
|
||||
#ifdef CONFIG_CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_MONOTONIC, ¤t_time);
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, ¤t_time);
|
||||
#endif
|
||||
current_us = TIMESPEC_TO_US(current_time.tv_sec, current_time.tv_nsec);
|
||||
}
|
||||
|
||||
/* Return a negated value in case of timeout, and in the other scenarios
|
||||
* return a positive value.
|
||||
* The transfer function will check the status of priv to check the other
|
||||
* scenarios.
|
||||
*/
|
||||
|
||||
if (current_us >= timeout_us)
|
||||
{
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
else if (priv->error)
|
||||
{
|
||||
ret = ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
/* Disable all interrupts */
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_INT_ENA_OFFSET, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_i2c_sem_wait
|
||||
@ -712,7 +891,9 @@ static void esp32_i2c_sem_post(struct esp32_i2c_priv_s *priv)
|
||||
static void esp32_i2c_sem_destroy(FAR struct esp32_i2c_priv_s *priv)
|
||||
{
|
||||
nxsem_destroy(&priv->sem_excl);
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
nxsem_destroy(&priv->sem_isr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -731,8 +912,10 @@ static inline void esp32_i2c_sem_init(FAR struct esp32_i2c_priv_s *priv)
|
||||
* priority inheritance enabled.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
nxsem_init(&priv->sem_isr, 0, 0);
|
||||
nxsem_set_protocol(&priv->sem_isr, SEM_PRIO_NONE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -763,16 +946,26 @@ static int esp32_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If previous state is different than idle,
|
||||
* reset the fsmc to the idle state.
|
||||
*/
|
||||
|
||||
if (priv->i2cstate != I2CSTATE_IDLE)
|
||||
{
|
||||
esp32_i2c_reset_fsmc(priv);
|
||||
priv->i2cstate = I2CSTATE_IDLE;
|
||||
}
|
||||
|
||||
/* Transfer the messages to the internal struct
|
||||
* and loop count times to make all transfers.
|
||||
*/
|
||||
|
||||
priv->msgv = msgs;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
/* Clear TX and RX FIFOs. */
|
||||
|
||||
esp32_i2c_reset_fifo(priv);
|
||||
|
||||
priv->bytes = 0;
|
||||
@ -781,6 +974,8 @@ static int esp32_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
priv->error = 0;
|
||||
priv->i2cstate = I2CSTATE_PROC;
|
||||
|
||||
/* Set the SCLK frequency for the current msg. */
|
||||
|
||||
esp32_i2c_init_clock(priv, msgs[i].frequency);
|
||||
|
||||
/* Reset I2C trace logic */
|
||||
@ -790,10 +985,15 @@ static int esp32_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_SENDADDR, msgs[i].addr,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
|
||||
/* Send the start cmd */
|
||||
|
||||
esp32_i2c_sendstart(priv);
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
if (esp32_i2c_sem_waitdone(priv) < 0)
|
||||
{
|
||||
/* Timed out - transfer was not completed within the timeout */
|
||||
|
||||
ret = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
@ -801,15 +1001,41 @@ static int esp32_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
{
|
||||
if (priv->error)
|
||||
{
|
||||
/* An error occurred */
|
||||
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Successful transfer, update the I2C state to idle */
|
||||
|
||||
priv->i2cstate = I2CSTATE_IDLE;
|
||||
ret = OK;
|
||||
}
|
||||
}
|
||||
#else
|
||||
ret = esp32_i2c_polling_waitdone(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (ret == -ETIMEDOUT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Successful transfer, update the I2C state to idle */
|
||||
|
||||
priv->i2cstate = I2CSTATE_IDLE;
|
||||
ret = OK;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Dump the trace result */
|
||||
@ -1048,28 +1274,71 @@ static void esp32_i2c_tracedump(struct esp32_i2c_priv_s *priv)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
static int esp32_i2c_irq(int cpuint, void *context, FAR void *arg)
|
||||
{
|
||||
struct esp32_i2c_priv_s *priv = (struct esp32_i2c_priv_s *)arg;
|
||||
struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
|
||||
uint32_t status = esp32_i2c_get_reg(priv, I2C_INT_STATUS_OFFSET);
|
||||
|
||||
/* Get the interrupt status and clear the interrupts that
|
||||
* triggered.
|
||||
*/
|
||||
|
||||
uint32_t status = esp32_i2c_get_reg(priv, I2C_INT_STATUS_OFFSET);
|
||||
esp32_i2c_set_reg(priv, I2C_INT_CLR_OFFSET, status);
|
||||
esp32_i2c_process(priv, status);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_i2c_process
|
||||
*
|
||||
* Description:
|
||||
* This routine manages the transfer. It's called after some specific
|
||||
* commands from the I2C controller are executed or in case of errors.
|
||||
* It's responsible for writing/reading operations and transferring data
|
||||
* from/to FIFO.
|
||||
* It's called in the interrupt and polled driven mode.
|
||||
*
|
||||
* Parameters:
|
||||
* priv - Pointer to the internal driver state structure.
|
||||
* status - The current interrupt status register.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void esp32_i2c_process(struct esp32_i2c_priv_s *priv,
|
||||
uint32_t status)
|
||||
{
|
||||
struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
|
||||
|
||||
/* Check for any errors */
|
||||
|
||||
if (I2C_INT_ERR_EN_BITS & status)
|
||||
{
|
||||
/* Save the errors, register the error event, disable interrupts
|
||||
* and release the semaphore to conclude the transfer.
|
||||
*/
|
||||
|
||||
priv->error = status & I2C_INT_ERR_EN_BITS;
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_ERROR, priv->error,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
esp32_i2c_set_reg(priv, I2C_INT_ENA_OFFSET, 0);
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
nxsem_post(&priv->sem_isr);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
else /* If no error */
|
||||
{
|
||||
/* If a transfer has just initialized */
|
||||
|
||||
if (priv->i2cstate == I2CSTATE_PROC)
|
||||
{
|
||||
/* Check the flags to perform a read or write operation */
|
||||
|
||||
if (msg->flags & I2C_M_READ)
|
||||
{
|
||||
/* RX FIFO has available data */
|
||||
|
||||
if (priv->ready_read)
|
||||
{
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->bytes,
|
||||
@ -1079,15 +1348,20 @@ static int esp32_i2c_irq(int cpuint, void *context, FAR void *arg)
|
||||
priv->ready_read = 0;
|
||||
}
|
||||
|
||||
/* Received all data. Finish the transaction
|
||||
* and update the state I2C state.
|
||||
*/
|
||||
|
||||
if (priv->bytes == msg->length)
|
||||
{
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
esp32_i2c_sendstop(priv);
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
priv->i2cstate = I2CSTATE_FINISH;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
else /* Start a receive operation */
|
||||
{
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_RCVMODEEN, 0,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
@ -1096,12 +1370,16 @@ static int esp32_i2c_irq(int cpuint, void *context, FAR void *arg)
|
||||
priv->ready_read = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
else /* Write operation */
|
||||
{
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->bytes,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
esp32_i2c_senddata(priv);
|
||||
|
||||
/* Finally sent the entire message. Update the I2C state to
|
||||
* send a stop signal in the next interrupt.
|
||||
*/
|
||||
|
||||
if (priv->bytes == msg->length)
|
||||
{
|
||||
priv->i2cstate = I2CSTATE_STOP;
|
||||
@ -1110,19 +1388,27 @@ static int esp32_i2c_irq(int cpuint, void *context, FAR void *arg)
|
||||
}
|
||||
else if (priv->i2cstate == I2CSTATE_STOP)
|
||||
{
|
||||
/* Transmitted all data. Finish the transaction sending a stop
|
||||
* and update the state I2C state.
|
||||
*/
|
||||
|
||||
esp32_i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
|
||||
esp32_i2c_get_reg(priv, I2C_SR_OFFSET));
|
||||
esp32_i2c_sendstop(priv);
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
priv->i2cstate = I2CSTATE_FINISH;
|
||||
#endif
|
||||
}
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
else if (priv->i2cstate == I2CSTATE_FINISH)
|
||||
{
|
||||
/* Disable all interrupts and release the semaphore */
|
||||
|
||||
esp32_i2c_set_reg(priv, I2C_INT_ENA_OFFSET, 0);
|
||||
nxsem_post(&priv->sem_isr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1139,10 +1425,12 @@ static int esp32_i2c_irq(int cpuint, void *context, FAR void *arg)
|
||||
|
||||
FAR struct i2c_master_s *esp32_i2cbus_initialize(int port)
|
||||
{
|
||||
int ret;
|
||||
irqstate_t flags;
|
||||
struct esp32_i2c_priv_s *priv;
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
const struct esp32_i2c_config_s *config;
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
switch (port)
|
||||
{
|
||||
@ -1160,8 +1448,6 @@ FAR struct i2c_master_s *esp32_i2cbus_initialize(int port)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config = priv->config;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
if ((volatile int)priv->refs++ != 0)
|
||||
@ -1171,6 +1457,8 @@ FAR struct i2c_master_s *esp32_i2cbus_initialize(int port)
|
||||
return (struct i2c_master_s *)priv;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
config = priv->config;
|
||||
priv->cpuint = esp32_alloc_levelint(1);
|
||||
if (priv->cpuint < 0)
|
||||
{
|
||||
@ -1196,6 +1484,7 @@ FAR struct i2c_master_s *esp32_i2cbus_initialize(int port)
|
||||
}
|
||||
|
||||
up_enable_irq(priv->cpuint);
|
||||
#endif
|
||||
|
||||
esp32_i2c_sem_init(priv);
|
||||
|
||||
@ -1236,11 +1525,13 @@ int esp32_i2cbus_uninitialize(FAR struct i2c_master_s *dev)
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
up_disable_irq(priv->cpuint);
|
||||
esp32_detach_peripheral(priv->config->cpu,
|
||||
priv->config->periph,
|
||||
priv->cpuint);
|
||||
esp32_free_cpuint(priv->cpuint);
|
||||
#endif
|
||||
|
||||
esp32_i2c_deinit(priv);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user