The STM32 periph_timer driver reads the timer's status flags, then
clears them all. It is possible that a timer interrupt could occur
between reading the flag and clearing it. This would lead to a lost
interrupt.
The timer's status flags can be cleared by software, but can only be set
by the hardware. This patch takes advantage of this by only clearing the
flags it knows are set. The rest of the flags are set, which doesn't
actually change their state.
The implmentation of `timer_set_absolute()` has The following problems.
First, it attempts to restore the auto reload register (ARR) to it's
default if the ARR was previosly set by `timer_set_periodic()` by
comparing it to the channel's capture compare (CC) register _after_ it
has already set the CC register. Secondly, it clears spurious IRQs
_after_ the CC register has been set. If the value being set is equal to
the timer's current count (or the two become equal before the supurios
IRQ clearing happens), this could cause a legitimate IRQ to be cleared.
The implmentation of `timer_set()` has the same error in handling the
ARR as described above.
This patch reorders the operations of both functions to do:
1. handle ARR
2. clear spurious IRQs
3. set channel's CC
4. enable IRQ
Additionally, the calulation of `value` in `timer_set()` is moved
earlier in the function's exec path as a pedantic measure.
If a timer's channel was set with a really small realtive duration from
now, such that it would be missed (underflowed), the driver would stop
the timer, potentially causing missed ticks. It was stopped to ensure
that the channel's output-compare register could be set to the current
counter value, before re-enabling the timer's counter. This is a
condition that will ensure that the underflow won't happen again and the
interrupt will fire, at the cost of losing some ticks for very high
speed clocks.
This patch replaces the logic that stopped the timer. Instead it uses a
register provided by the timer hardware to trigger timer interrupts via
software.
Allow two threads to share the same timer - provided they use distinct
sets of timer channels - without occasionally corrupting registers or
state flags.
Seems like the Interrupt flag for a Capture/Compare channel gets set when
- the CC-value is reached
- the timer resets before the CC value is reached.
We only want the first event and ignore the second one. Unfortunately I did
not find a way to disable the second event type, so it is filtered in software.
That is we need to
- ignore the CC-interrupts when the COUNT register register is reset
- ignore the CC-interrupts > TOP value/ARR (auto-reload register)