summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
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;