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 <[email protected]>
diff --git a/firmware/src/drivers/vsync/vsync.c b/firmware/src/drivers/vsync/vsync.c
index c6d55aa..75716ae 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 @@
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 30e91db..2543ac2 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 @@
.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 @@
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(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 @@
return -EINVAL;
chainIsr(&exti->base, isr);
+ if (!mMaxLatency || (isr->maxLatencyNs && isr->maxLatencyNs < mMaxLatency))
+ extiUpdateMaxLatency(isr->maxLatencyNs);
+
return 0;
}
@@ -152,16 +201,19 @@
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 5cbe5a7..f4fc6c6 100644
--- a/firmware/src/platform/stm32f4xx/platform.c
+++ b/firmware/src/platform/stm32f4xx/platform.c
@@ -373,6 +373,16 @@
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 @@
.jitterPpm = 0,
.driftPpm = 50,
.maxWakeupTime = 407000ull,
+ .devsAvail = (1 << Stm32sleepDevExti),
.prepare = sleepClockRtcPrepare,
.wake = sleepClockRtcWake,
.userData = (void*)stm32f411SleepModeStopLPLV,
@@ -532,6 +543,7 @@
.jitterPpm = 0,
.driftPpm = 50,
.maxWakeupTime = 130000ull,
+ .devsAvail = (1 << Stm32sleepDevExti),
.prepare = sleepClockRtcPrepare,
.wake = sleepClockRtcWake,
.userData = (void*)stm32f411SleepModeStopLPFD,
@@ -545,6 +557,7 @@
.jitterPpm = 0,
.driftPpm = 50,
.maxWakeupTime = 111000ull,
+ .devsAvail = (1 << Stm32sleepDevExti),
.prepare = sleepClockRtcPrepare,
.wake = sleepClockRtcWake,
.userData = (void*)stm32f411SleepModeStopMRFPD,
@@ -558,6 +571,7 @@
.jitterPpm = 0,
.driftPpm = 50,
.maxWakeupTime = 14500ull,
+ .devsAvail = (1 << Stm32sleepDevExti),
.prepare = sleepClockRtcPrepare,
.wake = sleepClockRtcWake,
.userData = (void*)stm32f411SleepModeStopMR,
@@ -571,7 +585,7 @@
.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 @@
.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 @@
if (predecrement > length)
continue;
- //skip options with too much drift
+ //skip options with too much drift
if (sleepClock->driftPpm > mMaxDriftPpm)
continue;