summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Fennema <fennema@google.com>2017-12-21 21:41:44 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-12-21 21:41:44 +0000
commit9d8f09b9e27e23157c9ad0dd6a28052073bd0a4f (patch)
treeaa9f47edfb06cd76cf0015fe42f3319d7a18c6c6
parent5b6af28e86478b2afdb9040bcb80852bf23c4d82 (diff)
parentd6104b39af592750d6fb8554765663c83e2fe00c (diff)
downloadcontexthub-9d8f09b9e27e23157c9ad0dd6a28052073bd0a4f.tar.gz
nanohub: i2c: detect and clock through stuck low sda am: 44b122a273 am: aad7f8db68
am: d6104b39af Change-Id: I8f98984ece95247ade6bfa37e2ca67f5c791f15e
-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);