diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/inc/isr.h | 17 | ||||
-rw-r--r-- | firmware/inc/platform.h | 1 | ||||
-rw-r--r-- | firmware/inc/platform/stm32f4xx/exti.h | 2 | ||||
-rw-r--r-- | firmware/inc/platform/stm32f4xx/plat.h | 1 | ||||
-rw-r--r-- | firmware/src/drivers/vsync/vsync.c | 4 | ||||
-rw-r--r-- | firmware/src/platform/stm32f4xx/exti.c | 64 | ||||
-rw-r--r-- | firmware/src/platform/stm32f4xx/platform.c | 20 |
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; |