summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorBen Fennema <fennema@google.com>2016-09-14 15:51:06 -0700
committerBen Fennema <fennema@google.com>2016-09-19 17:06:43 -0700
commit8efc9b9f929178c90164da3593328ab8d673aeb4 (patch)
tree83c6ae8e5299be0556a37a5781d8c8d34e60a9c7 /firmware
parent83d52c51111467d3ea1f9a80027bc192077c1475 (diff)
downloadcontexthub-8efc9b9f929178c90164da3593328ab8d673aeb4.tar.gz
exti: add support for specifying a max latency requirement for interrupts
A non-zero maxLatency specified for an enabled interrupt will prevent the system from going into sleep modes that take longer than the specified latency to wake up. Set vsync maxLatencyNs to MAX_VSYNC_INT_LATENCY to prevent the cpu from going into any stop modes while vsync is enabled. Bug: 29886751 Change-Id: I4b578b7598d8e4d6989b4ea0dafeb9c8900f8553 Signed-off-by: Ben Fennema <fennema@google.com>
Diffstat (limited to 'firmware')
-rw-r--r--firmware/inc/isr.h17
-rw-r--r--firmware/inc/platform.h1
-rw-r--r--firmware/inc/platform/stm32f4xx/exti.h2
-rw-r--r--firmware/inc/platform/stm32f4xx/plat.h1
-rw-r--r--firmware/src/drivers/vsync/vsync.c4
-rw-r--r--firmware/src/platform/stm32f4xx/exti.c64
-rw-r--r--firmware/src/platform/stm32f4xx/platform.c20
7 files changed, 99 insertions, 10 deletions
diff --git a/firmware/inc/isr.h b/firmware/inc/isr.h
index 2ce9d2ca..73a8f033 100644
--- a/firmware/inc/isr.h
+++ b/firmware/inc/isr.h
@@ -34,6 +34,9 @@ struct ChainedInterrupt {
struct ChainedIsr {
link_t node;
+
+ uint32_t maxLatencyNs;
+
bool (*func)(struct ChainedIsr *);
uint16_t tid;
};
@@ -88,4 +91,18 @@ static inline int unchainIsrAll(struct ChainedInterrupt *interrupt, uint32_t tid
return count;
}
+static inline uint32_t maxLatencyIsr(struct ChainedInterrupt *interrupt)
+{
+ struct link_t *cur, *tmp;
+ uint32_t latency = 0;
+
+ list_iterate(&interrupt->isrs, cur, tmp) {
+ struct ChainedIsr *curIsr = container_of(cur, struct ChainedIsr, node);
+ if (!latency || (curIsr->maxLatencyNs && curIsr->maxLatencyNs < latency))
+ latency = curIsr->maxLatencyNs;
+ }
+
+ return latency;
+}
+
#endif /* __ISR_H */
diff --git a/firmware/inc/platform.h b/firmware/inc/platform.h
index c589b5b1..aa706cad 100644
--- a/firmware/inc/platform.h
+++ b/firmware/inc/platform.h
@@ -68,6 +68,7 @@ bool platSleepClockRequest(uint64_t wakeupTime, uint32_t maxJitterPpm, uint32_t
/* 0 for any "max" value means "do not care" */
bool platRequestDevInSleepMode(uint32_t sleepDevID, uint32_t maxWakeupTime); //request that this device remain powered/clocked in sleep mode (device lists are platform specific)
+bool platAdjustDevInSleepMode(uint32_t sleepDevID, uint32_t maxWakeupTime); //adjust maxWakeupTime for this device
bool platReleaseDevInSleepMode(uint32_t sleepDevID); //unrequest that this device remain powered/clocked in sleep mode (device lists are platform specific)
diff --git a/firmware/inc/platform/stm32f4xx/exti.h b/firmware/inc/platform/stm32f4xx/exti.h
index 84fcd396..59d9db69 100644
--- a/firmware/inc/platform/stm32f4xx/exti.h
+++ b/firmware/inc/platform/stm32f4xx/exti.h
@@ -68,6 +68,8 @@ int extiChainIsr(IRQn_Type n, struct ChainedIsr *isr);
int extiUnchainIsr(IRQn_Type n, struct ChainedIsr *isr);
int extiUnchainAll(uint32_t tid);
+int extiSetMaxLatency(struct ChainedIsr *isr, uint32_t maxLatencyNs);
+
static inline void extiEnableIntGpio(const struct Gpio *__restrict gpioHandle, enum ExtiTrigger trigger)
{
if (gpioHandle) {
diff --git a/firmware/inc/platform/stm32f4xx/plat.h b/firmware/inc/platform/stm32f4xx/plat.h
index 253d9fac..c07ae564 100644
--- a/firmware/inc/platform/stm32f4xx/plat.h
+++ b/firmware/inc/platform/stm32f4xx/plat.h
@@ -35,6 +35,7 @@ enum PlatSleepDevID
Stm32sleepDevSpi2, /* we use this to prevent stop mode during spi2 xfers */
Stm32sleepDevSpi3, /* we use this to prevent stop mode during spi3 xfers */
Stm32sleepDevI2c1, /* we use this to prevent stop mode during i2c1 xfers */
+ Stm32sleepDevExti, /* we use this for max external interrupt latency */
Stm32sleepDevNum, //must be last always, and must be <= PLAT_MAX_SLEEP_DEVS
};
diff --git a/firmware/src/drivers/vsync/vsync.c b/firmware/src/drivers/vsync/vsync.c
index c6d55aab..75716ae0 100644
--- a/firmware/src/drivers/vsync/vsync.c
+++ b/firmware/src/drivers/vsync/vsync.c
@@ -38,7 +38,8 @@
// This defines how many vsync events we could handle being backed up in the
// queue. Use this to size our slab
-#define MAX_VSYNC_EVENTS 4
+#define MAX_VSYNC_EVENTS 4
+#define MAX_VSYNC_INT_LATENCY 1000 /* in ns */
#ifndef VSYNC_PIN
#error "VSYNC_PIN is not defined; please define in variant.h"
@@ -198,6 +199,7 @@ static bool startTask(uint32_t taskId)
mTask.sensorHandle = sensorRegister(&mSensorInfo, &mSensorOps, NULL, true);
mTask.pin = gpioRequest(VSYNC_PIN);
mTask.isr.func = vsyncIsr;
+ mTask.isr.maxLatencyNs = MAX_VSYNC_INT_LATENCY;
mTask.evtSlab = slabAllocatorNew(sizeof(struct SingleAxisDataEvent) + sizeof(struct SingleAxisDataPoint), 4, MAX_VSYNC_EVENTS);
if (!mTask.evtSlab) {
diff --git a/firmware/src/platform/stm32f4xx/exti.c b/firmware/src/platform/stm32f4xx/exti.c
index 30e91db5..2543ac29 100644
--- a/firmware/src/platform/stm32f4xx/exti.c
+++ b/firmware/src/platform/stm32f4xx/exti.c
@@ -16,6 +16,7 @@
#include <errno.h>
#include <isr.h>
+#include <platform.h>
#include <plat/inc/cmsis.h>
#include <plat/inc/exti.h>
@@ -94,7 +95,9 @@ static void extiInterruptDisable(struct ChainedInterrupt *irq)
.irq = i, \
}
-static struct ExtiInterrupt gInterrupts[] = {
+uint32_t mMaxLatency = 0;
+
+static struct ExtiInterrupt mInterrupts[] = {
DECLARE_SHARED_EXTI(EXTI0_IRQn),
DECLARE_SHARED_EXTI(EXTI1_IRQn),
DECLARE_SHARED_EXTI(EXTI2_IRQn),
@@ -104,14 +107,39 @@ static struct ExtiInterrupt gInterrupts[] = {
DECLARE_SHARED_EXTI(EXTI15_10_IRQn),
};
+static void extiUpdateMaxLatency(uint32_t maxLatencyNs)
+{
+ if (!maxLatencyNs && mMaxLatency)
+ platReleaseDevInSleepMode(Stm32sleepDevExti);
+ else if (maxLatencyNs && !mMaxLatency)
+ platRequestDevInSleepMode(Stm32sleepDevExti, maxLatencyNs);
+ else if (maxLatencyNs && mMaxLatency)
+ platAdjustDevInSleepMode(Stm32sleepDevExti, maxLatencyNs);
+ mMaxLatency = maxLatencyNs;
+}
+
+static void extiCalcMaxLatency()
+{
+ int i;
+ uint32_t maxLatency, newMaxLatency = 0;
+ struct ExtiInterrupt *exti = mInterrupts;
+
+ for (i = 0; i < ARRAY_SIZE(mInterrupts); ++i, ++exti) {
+ maxLatency = maxLatencyIsr(&exti->base);
+ if (!newMaxLatency || (maxLatency && maxLatency < newMaxLatency))
+ newMaxLatency = maxLatency;
+ }
+ extiUpdateMaxLatency(newMaxLatency);
+}
+
static inline struct ExtiInterrupt *extiForIrq(IRQn_Type n)
{
if (n >= EXTI0_IRQn && n <= EXTI4_IRQn)
- return &gInterrupts[n - EXTI0_IRQn];
+ return &mInterrupts[n - EXTI0_IRQn];
if (n == EXTI9_5_IRQn)
- return &gInterrupts[ARRAY_SIZE(gInterrupts) - 2];
+ return &mInterrupts[ARRAY_SIZE(mInterrupts) - 2];
if (n == EXTI15_10_IRQn)
- return &gInterrupts[ARRAY_SIZE(gInterrupts) - 1];
+ return &mInterrupts[ARRAY_SIZE(mInterrupts) - 1];
return NULL;
}
@@ -135,6 +163,24 @@ DEFINE_SHARED_EXTI_ISR(4)
DEFINE_SHARED_EXTI_ISR(9_5)
DEFINE_SHARED_EXTI_ISR(15_10)
+int extiSetMaxLatency(struct ChainedIsr *isr, uint32_t maxLatencyNs)
+{
+ uint32_t latency;
+
+ if (!isr)
+ return -EINVAL;
+
+ if (maxLatencyNs != isr->maxLatencyNs) {
+ latency = isr->maxLatencyNs;
+ isr->maxLatencyNs = maxLatencyNs;
+ if (!mMaxLatency || latency == mMaxLatency || (maxLatencyNs && maxLatencyNs < mMaxLatency)) {
+ extiCalcMaxLatency();
+ }
+ }
+
+ return 0;
+}
+
int extiChainIsr(IRQn_Type n, struct ChainedIsr *isr)
{
struct ExtiInterrupt *exti = extiForIrq(n);
@@ -142,6 +188,9 @@ int extiChainIsr(IRQn_Type n, struct ChainedIsr *isr)
return -EINVAL;
chainIsr(&exti->base, isr);
+ if (!mMaxLatency || (isr->maxLatencyNs && isr->maxLatencyNs < mMaxLatency))
+ extiUpdateMaxLatency(isr->maxLatencyNs);
+
return 0;
}
@@ -152,16 +201,19 @@ int extiUnchainIsr(IRQn_Type n, struct ChainedIsr *isr)
return -EINVAL;
unchainIsr(&exti->base, isr);
+ if (isr->maxLatencyNs && isr->maxLatencyNs == mMaxLatency)
+ extiCalcMaxLatency();
return 0;
}
int extiUnchainAll(uint32_t tid)
{
int i, count = 0;
- struct ExtiInterrupt *exti = gInterrupts;
+ struct ExtiInterrupt *exti = mInterrupts;
- for (i = 0; i < ARRAY_SIZE(gInterrupts); ++i, ++exti)
+ for (i = 0; i < ARRAY_SIZE(mInterrupts); ++i, ++exti)
count += unchainIsrAll(&exti->base, tid);
+ extiCalcMaxLatency();
return count;
}
diff --git a/firmware/src/platform/stm32f4xx/platform.c b/firmware/src/platform/stm32f4xx/platform.c
index 5cbe5a72..f4fc6c61 100644
--- a/firmware/src/platform/stm32f4xx/platform.c
+++ b/firmware/src/platform/stm32f4xx/platform.c
@@ -373,6 +373,16 @@ bool platRequestDevInSleepMode(uint32_t sleepDevID, uint32_t maxWakeupTime)
return true;
}
+bool platAdjustDevInSleepMode(uint32_t sleepDevID, uint32_t maxWakeupTime)
+{
+ if (sleepDevID >= PLAT_MAX_SLEEP_DEVS || sleepDevID >= Stm32sleepDevNum)
+ return false;
+
+ mDevsMaxWakeTime[sleepDevID] = maxWakeupTime;
+
+ return true;
+}
+
bool platReleaseDevInSleepMode(uint32_t sleepDevID)
{
if (sleepDevID >= PLAT_MAX_SLEEP_DEVS || sleepDevID >= Stm32sleepDevNum)
@@ -519,6 +529,7 @@ struct PlatSleepAndClockInfo {
.jitterPpm = 0,
.driftPpm = 50,
.maxWakeupTime = 407000ull,
+ .devsAvail = (1 << Stm32sleepDevExti),
.prepare = sleepClockRtcPrepare,
.wake = sleepClockRtcWake,
.userData = (void*)stm32f411SleepModeStopLPLV,
@@ -532,6 +543,7 @@ struct PlatSleepAndClockInfo {
.jitterPpm = 0,
.driftPpm = 50,
.maxWakeupTime = 130000ull,
+ .devsAvail = (1 << Stm32sleepDevExti),
.prepare = sleepClockRtcPrepare,
.wake = sleepClockRtcWake,
.userData = (void*)stm32f411SleepModeStopLPFD,
@@ -545,6 +557,7 @@ struct PlatSleepAndClockInfo {
.jitterPpm = 0,
.driftPpm = 50,
.maxWakeupTime = 111000ull,
+ .devsAvail = (1 << Stm32sleepDevExti),
.prepare = sleepClockRtcPrepare,
.wake = sleepClockRtcWake,
.userData = (void*)stm32f411SleepModeStopMRFPD,
@@ -558,6 +571,7 @@ struct PlatSleepAndClockInfo {
.jitterPpm = 0,
.driftPpm = 50,
.maxWakeupTime = 14500ull,
+ .devsAvail = (1 << Stm32sleepDevExti),
.prepare = sleepClockRtcPrepare,
.wake = sleepClockRtcWake,
.userData = (void*)stm32f411SleepModeStopMR,
@@ -571,7 +585,7 @@ struct PlatSleepAndClockInfo {
.jitterPpm = 0,
.driftPpm = 30,
.maxWakeupTime = 12ull,
- .devsAvail = (1 << Stm32sleepDevTim2) | (1 << Stm32sleepDevTim4) | (1 << Stm32sleepDevTim5) | (1 << Stm32sleepDevTim9) | (1 << Stm32sleepWakeup) | (1 << Stm32sleepDevSpi2) | (1 << Stm32sleepDevSpi3) | (1 << Stm32sleepDevI2c1),
+ .devsAvail = (1 << Stm32sleepDevTim2) | (1 << Stm32sleepDevTim4) | (1 << Stm32sleepDevTim5) | (1 << Stm32sleepDevTim9) | (1 << Stm32sleepWakeup) | (1 << Stm32sleepDevSpi2) | (1 << Stm32sleepDevSpi3) | (1 << Stm32sleepDevI2c1) | (1 << Stm32sleepDevExti),
.prepare = sleepClockTmrPrepare,
.wake = sleepClockTmrWake,
},
@@ -583,7 +597,7 @@ struct PlatSleepAndClockInfo {
.jitterPpm = 0,
.driftPpm = 0,
.maxWakeupTime = 0,
- .devsAvail = (1 << Stm32sleepDevTim2) | (1 << Stm32sleepDevTim4) | (1 << Stm32sleepDevTim5) | (1 << Stm32sleepDevTim9) | (1 << Stm32sleepWakeup) | (1 << Stm32sleepDevSpi2) | (1 << Stm32sleepDevSpi3) | (1 << Stm32sleepDevI2c1),
+ .devsAvail = (1 << Stm32sleepDevTim2) | (1 << Stm32sleepDevTim4) | (1 << Stm32sleepDevTim5) | (1 << Stm32sleepDevTim9) | (1 << Stm32sleepWakeup) | (1 << Stm32sleepDevSpi2) | (1 << Stm32sleepDevSpi3) | (1 << Stm32sleepDevI2c1) | (1 << Stm32sleepDevExti),
.prepare = sleepClockJustWfiPrepare,
},
@@ -620,7 +634,7 @@ void platSleep(void)
if (predecrement > length)
continue;
- //skip options with too much drift
+ //skip options with too much drift
if (sleepClock->driftPpm > mMaxDriftPpm)
continue;