From 01cc1687b3d13cbba973c002d60e33254bc53f12 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Mon, 28 Aug 2023 12:05:03 +0300 Subject: [PATCH] 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. --- arch/risc-v/src/mpfs/mpfs_i2c.c | 42 ++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index 0f760820c0..3a6f46486e 100644 --- a/arch/risc-v/src/mpfs/mpfs_i2c.c +++ b/arch/risc-v/src/mpfs/mpfs_i2c.c @@ -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 ****************************************************************************/