summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorPatryk Duda <pdk@semihalf.com>2021-12-21 16:02:39 +0100
committerCommit Bot <commit-bot@chromium.org>2022-01-21 10:48:59 +0000
commit46b0dbe56c9450af7debf307ab6691e77e5c62be (patch)
tree2c8167271cb3f1646d823974ca8f2e3cf086b878 /core
parent39fbc1252a9312355a0b656830cef03c27da1c4a (diff)
downloadchrome-ec-46b0dbe56c9450af7debf307ab6691e77e5c62be.tar.gz
clock-stm32f4: Handle timer overflow in IDLE task
STM32F4 microcontroller has 32 bit timer which is used by EC to measure system uptime (in microseconds) and wake tasks if necessary. In EC timestamp is defined as two 32 bit values, which combined together give full 64 bit value. Lower 32 bits are read directly from timer. Higher 32 bits are kept in clksrc_high variable. The variable is updated in process_timers() function which is called in interrupt context (it's not an interrupt handler, but it's called by the driver). The function also sets event timestamp which is supposed to generate interrupt if timer register matches event timestamp. When EC switches to IDLE task, interrupts are disabled in order to prevent task preemption in uncontrolled manner. It is possible that after interrupts are disabled timer overflow could occur and clksrc_high variable remains old. Other problem is that event timestamp which is read using __hw_clock_event_get() and points to timestamp in previous "epoch". Its value is about 2^32 - HOOK_TICK_INTERVAL (500 ms). After overflow, t0.le.lo is very low and t0.le.hi remains unincremented. As a result next_delay variable (which tells for how long RTC alarm is set) is very high (even above 1 hour). Another important fact is that t0 timestamp is wrong and it is used to calculate value which will be loaded into the timer after wake. This can potentially lead to very long wait before running tasks. This fix checks if timestamp overflow occurs between disabling interrupt and getting "t0" value. If it happens, interrupts are enabled (to handle timer overflow) and IDLE enter procedure is repeated. BUG=b:200828093 BRANCH=none TEST=make -j buildall TEST=Run EC on bloonchipper and enable deep sleep. Check if device crashes. TEST=Measure dragonclaw v0.2 power consumption in deep sleep using following commands: dut-control fpmcu_slp_s0:on dut-control -t 60 pp3300_dx_mcu_mv pp3300_dx_fp_mv \ pp1800_dx_fp_mv pp3300_dx_mcu_mw pp3300_dx_fp_mw \ pp1800_dx_fp_mw Make sure that power consumption doesn't increase. Signed-off-by: Patryk Duda <pdk@semihalf.com> Change-Id: I8c3bb51a0ef9d94ef384b8fca5a175945ba67604 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3347659 Reviewed-by: Bobby Casey <bobbycasey@google.com> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'core')
-rw-r--r--core/cortex-m/task.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/core/cortex-m/task.c b/core/cortex-m/task.c
index 934de2b70c..417a54f557 100644
--- a/core/cortex-m/task.c
+++ b/core/cortex-m/task.c
@@ -543,6 +543,15 @@ void task_clear_pending_irq(int irq)
CPU_NVIC_UNPEND(irq / 32) = 1 << (irq % 32);
}
+/*
+ * Reading interrupt clear-pending register gives us information if interrupt
+ * is pending.
+ */
+bool task_is_irq_pending(int irq)
+{
+ return CPU_NVIC_UNPEND(irq / 32) & (1 << (irq % 32));
+}
+
void task_trigger_irq(int irq)
{
CPU_NVIC_SWTRIG = irq;