diff options
author | Patryk Duda <pdk@semihalf.com> | 2021-12-21 16:02:39 +0100 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2022-01-21 10:48:59 +0000 |
commit | 46b0dbe56c9450af7debf307ab6691e77e5c62be (patch) | |
tree | 2c8167271cb3f1646d823974ca8f2e3cf086b878 /core | |
parent | 39fbc1252a9312355a0b656830cef03c27da1c4a (diff) | |
download | chrome-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.c | 9 |
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; |