summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Fennema <fennema@google.com>2017-11-29 10:46:08 -0800
committerBen Fennema <fennema@google.com>2017-12-20 14:17:29 -0800
commit44b122a273da6aff4ec56c292898f8204811dd4d (patch)
tree435b840fcf7750eb189af390cbc7812ea56eee17
parent35642255034ed82fe39c2324e7851a19af87681d (diff)
downloadcontexthub-o-mr1-iot-preview-7.tar.gz
If the chip is reset in the middle of an i2c read, the slave will still be waiting for additional pulses of sdc. This prevents all chips on the stuck i2c bus from being detected until a power cycle. Detect that sda is stuck low and attempt to clock through the issue. Bug: 65966547 Test: run accel at a high rate over i2c and reset the stm32. Confirm all chips on i2c are detected after reset. Change-Id: I3a7ec24556a693b5506ba65f4eefa6e9f36e5818 Signed-off-by: Ben Fennema <fennema@google.com>
-rw-r--r--firmware/os/core/timer.c8
-rw-r--r--firmware/os/inc/timer.h1
-rw-r--r--firmware/os/platform/stm32/i2c.c46
3 files changed, 55 insertions, 0 deletions
diff --git a/firmware/os/core/timer.c b/firmware/os/core/timer.c
index ace80723..f9c33523 100644
--- a/firmware/os/core/timer.c
+++ b/firmware/os/core/timer.c
@@ -62,6 +62,14 @@ uint64_t timGetTime(void)
return platGetTicks();
}
+void timDelay(uint32_t length)
+{
+ uint64_t curTime = timGetTime();
+
+ while (curTime + length > timGetTime())
+ ;
+}
+
static struct Timer *timFindTimerById(uint32_t timId) /* no locks taken. be careful what you do with this */
{
uint32_t i;
diff --git a/firmware/os/inc/timer.h b/firmware/os/inc/timer.h
index abc5e19f..30e359a2 100644
--- a/firmware/os/inc/timer.h
+++ b/firmware/os/inc/timer.h
@@ -38,6 +38,7 @@ typedef void (*TimTimerCbkF)(uint32_t timerId, void* data);
uint64_t timGetTime(void); /* Time since some stable reference point in nanoseconds */
+void timDelay(uint32_t length);
uint32_t timTimerSet(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TimTimerCbkF cbk, void* data, bool oneShot); /* return timer id or 0 if failed */
uint32_t timTimerSetAsApp(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, uint32_t tid, void* data, bool oneShot); /* return timer id or 0 if failed */
diff --git a/firmware/os/platform/stm32/i2c.c b/firmware/os/platform/stm32/i2c.c
index 189e8f9d..7ba7b7ce 100644
--- a/firmware/os/platform/stm32/i2c.c
+++ b/firmware/os/platform/stm32/i2c.c
@@ -26,6 +26,7 @@
#include <atomicBitset.h>
#include <atomic.h>
#include <platform.h>
+#include <timer.h>
#include <plat/cmsis.h>
#include <plat/dma.h>
@@ -775,6 +776,49 @@ static inline struct Gpio* stmI2cGpioInit(const struct StmI2cBoardCfg *board, co
return gpio;
}
+static int i2cMasterReset(uint32_t busId, uint32_t speed)
+{
+ struct Gpio *sda, *scl;
+ int cnt = 0;
+ uint32_t delay;
+
+ if (busId >= ARRAY_SIZE(mStmI2cDevs))
+ return -EINVAL;
+
+ const struct StmI2cBoardCfg *board = boardStmI2cCfg(busId);
+ if (!board)
+ return -EINVAL;
+
+ sda = gpioRequest(board->gpioSda.gpioNum);
+ gpioConfigOutput(sda, board->gpioSpeed, GPIO_PULL_NONE, GPIO_OUT_OPEN_DRAIN, 1);
+ if (gpioGet(sda) == 0) {
+ // 50% duty cycle for the clock
+ delay = 500000000UL/speed;
+
+ scl = gpioRequest(board->gpioScl.gpioNum);
+ gpioConfigOutput(scl, board->gpioSpeed, GPIO_PULL_NONE, GPIO_OUT_OPEN_DRAIN, 1);
+ do {
+ // generate clock pulse
+ gpioSet(scl, 1);
+ timDelay(delay);
+ gpioSet(scl, 0);
+ timDelay(delay);
+ cnt ++;
+ } while (gpioGet(sda) == 0 && cnt < 9);
+
+ // generate STOP condition
+ gpioSet(sda, 0);
+ gpioSet(scl, 1);
+ timDelay(delay);
+ gpioSet(sda, 1);
+ timDelay(delay);
+ gpioRelease(scl);
+ }
+ gpioRelease(sda);
+
+ return cnt;
+}
+
int i2cMasterRequest(uint32_t busId, uint32_t speed)
{
if (busId >= ARRAY_SIZE(mStmI2cDevs))
@@ -797,6 +841,8 @@ int i2cMasterRequest(uint32_t busId, uint32_t speed)
pdev->last = 1;
atomicBitsetInit(mXfersValid, I2C_MAX_QUEUE_DEPTH);
+ i2cMasterReset(busId, speed);
+
pdev->scl = stmI2cGpioInit(board, &board->gpioScl);
pdev->sda = stmI2cGpioInit(board, &board->gpioSda);