diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2016-05-23 15:23:38 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-06-02 14:06:52 -0700 |
commit | 4f600b32bbcdd1f870f8389b8666101d3a8513ed (patch) | |
tree | d60ca034718fd19e0a13411825b1eaef25901072 | |
parent | f6a53e9917b474e95afb42e2522fb88c61998c9a (diff) | |
download | chrome-ec-4f600b32bbcdd1f870f8389b8666101d3a8513ed.tar.gz |
stm32: i2c: Busy loop for a while waiting for interrupt
I2C is not necessarily _that_ slow, especially when using 1Mhz clock
speed, and, looking at traces from userspace, there are large gaps
(150us) between bytes (while the bytes themselves only take ~10us).
At 400kHz and higher bus speed, busy-loop for the duration of 2 bytes,
before sleeping (and yielding to other tasks) for 100us between each
attempt.
BRANCH=None
BUG=chrome-os-partner:50381
TEST=i2cget, look at Logic 16 traces: no gaps between address and bytes
Change-Id: If47f0f8e55be37002361800d35f71c945863d42d
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/346670
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | chip/stm32/i2c-stm32f0.c | 28 |
1 files changed, 23 insertions, 5 deletions
diff --git a/chip/stm32/i2c-stm32f0.c b/chip/stm32/i2c-stm32f0.c index 4bc371a3dc..8710d73be5 100644 --- a/chip/stm32/i2c-stm32f0.c +++ b/chip/stm32/i2c-stm32f0.c @@ -10,6 +10,7 @@ #include "gpio.h" #include "hooks.h" #include "host_command.h" +#include "hwtimer.h" #include "i2c.h" #include "registers.h" #include "system.h" @@ -44,6 +45,7 @@ /* I2C port state data */ struct i2c_port_data { uint32_t timeout_us; /* Transaction timeout, or 0 to use default */ + enum i2c_freq freq; /* Port clock speed */ }; static struct i2c_port_data pdata[I2C_PORT_COUNT]; @@ -52,6 +54,13 @@ void i2c_set_timeout(int port, uint32_t timeout) pdata[port].timeout_us = timeout ? timeout : I2C_TX_TIMEOUT_MASTER; } +/* timingr register values for supported input clks / i2c clk rates */ +static const uint32_t busyloop_us[I2C_FREQ_COUNT] = { + [I2C_FREQ_1000KHZ] = 16, /* Enough for 2 bytes */ + [I2C_FREQ_400KHZ] = 40, /* Enough for 2 bytes */ + [I2C_FREQ_100KHZ] = 0, /* No busy looping at 100kHz (bus is slow) */ +}; + /** * Wait for ISR register to contain the specified mask. * @@ -60,9 +69,10 @@ void i2c_set_timeout(int port, uint32_t timeout) */ static int wait_isr(int port, int mask) { - uint64_t timeout = get_time().val + pdata[port].timeout_us; + uint32_t start = __hw_clock_source_read(); + uint32_t delta = 0; - while (get_time().val < timeout) { + do { int isr = STM32_I2C_ISR(port); /* Check for errors */ @@ -74,9 +84,15 @@ static int wait_isr(int port, int mask) if ((isr & mask) == mask) return EC_SUCCESS; - /* I2C is slow, so let other things run while we wait */ - usleep(100); - } + delta = __hw_clock_source_read() - start; + + /** + * Depending on the bus speed, busy loop for a while before + * sleeping and letting other things run. + */ + if (delta >= busyloop_us[pdata[port].freq]) + usleep(100); + } while (delta < pdata[port].timeout_us); return EC_ERROR_TIMEOUT; } @@ -116,6 +132,8 @@ static void i2c_set_freq_port(const struct i2c_port_t *p, STM32_I2C_TIMINGR(port) = regs[freq]; /* Enable port */ STM32_I2C_CR1(port) = STM32_I2C_CR1_PE; + + pdata[port].freq = freq; } /** |