mpfs/mpfs_i2c.c: Replace 1 second timeout with Time-on-Air based timeout

Calculate how long an I2C transation will take in microseconds, and use
this as the timeout for mpfs_i2c_sem_waitdone.

The reason for doing this is not to keep an i2c bus reserved for the full
1 second timeout, if e.g. a sensor is not on the bus / is faulty and
non-responsive. Reading the other sensors will be blocked for a relatively
long time (1 second) in this case. This fixes such behavior.
This commit is contained in:
Ville Juven 2023-08-28 12:05:03 +03:00 committed by Xiang Xiao
parent 47faeeb360
commit 01cc1687b3
1 changed files with 41 additions and 1 deletions

View File

@ -68,6 +68,11 @@
#define MPFS_I2C_DATA (priv->hw_base + MPFS_I2C_DATA_OFFSET)
#define MPFS_I2C_ADDR (priv->hw_base + MPFS_I2C_SLAVE0ADR_OFFSET)
/* Gives TTOA in microseconds, ~4.8% bias, +1 rounds up */
#define I2C_TTOA_US(n, f) ((((n) << 20) / (f)) + 1)
#define I2C_TTOA_MARGIN 20
/****************************************************************************
* Private Types
****************************************************************************/
@ -143,6 +148,7 @@ struct mpfs_i2c_priv_s
uint32_t frequency; /* Current I2C frequency */
uint8_t msgid; /* Current message ID */
uint8_t msgc; /* Message count */
ssize_t bytes; /* Processed data bytes */
uint8_t ser_address; /* Own i2c address */
@ -267,6 +273,7 @@ static struct mpfs_i2c_priv_s
static int mpfs_i2c_setfrequency(struct mpfs_i2c_priv_s *priv,
uint32_t frequency);
static uint32_t mpfs_i2c_timeout(int msgc, struct i2c_msg_s *msgv);
/****************************************************************************
* Private Functions
@ -399,7 +406,8 @@ static void mpfs_i2c_deinit(struct mpfs_i2c_priv_s *priv)
static int mpfs_i2c_sem_waitdone(struct mpfs_i2c_priv_s *priv)
{
return nxsem_tickwait_uninterruptible(&priv->sem_isr, SEC2TICK(1));
uint32_t timeout = mpfs_i2c_timeout(priv->msgc, priv->msgv);
return nxsem_tickwait_uninterruptible(&priv->sem_isr, USEC2TICK(timeout));
}
/****************************************************************************
@ -667,6 +675,7 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev,
}
priv->msgv = msgs;
priv->msgc = count;
for (int i = 0; i < count; i++)
{
@ -884,6 +893,37 @@ static int mpfs_i2c_setfrequency(struct mpfs_i2c_priv_s *priv,
return OK;
}
/****************************************************************************
* Name: mpfs_i2c_timeout
*
* Description:
* Calculate the time a full I2C transaction (message vector) will take
* to transmit, used for bus timeout.
*
* Input Parameters:
* msgc - Message count in message vector
* msgv - Message vector containing the messages to send
*
* Returned Value:
* I2C transaction timeout in microseconds (with some margin)
*
****************************************************************************/
static uint32_t mpfs_i2c_timeout(int msgc, struct i2c_msg_s *msgv)
{
uint32_t usec = 0;
int i;
for (i = 0; i < msgc; i++)
{
/* start + stop + address is 12 bits, each byte is 9 bits */
usec += I2C_TTOA_US(12 + msgv[i].length * 9, msgv[i].frequency);
}
return usec + I2C_TTOA_MARGIN;
}
/****************************************************************************
* Public Functions
****************************************************************************/