RTC wakeup callback should be executed immediately rather than deferred
AFAIK the callback invoked by RTC.wakeup is scheduled for later execution rather than being executed immediately, as the pin interrupts are.
See: https://github.com/micropython/micropython/blob/master/ports/stm32/extint.c#L657
IMHO this is undesirable behaviour. If the RTC is used to (a) wake the processor after machine.sleep() and (b) set a flag to be inspected by the main thread, then it has the effect that the flag may not be ready for inspection.
The code below illustrated the problem. I find that for correct operation it is necessary to add a delay after execution resumes and before inspecting variables changed by the callback. Commenting out the delay at line 17 results in undesirable behaviour.
I ran this on an OpenMV camera and the OpenMV github issue here provides more details of how I found this bug/feature, and some further analysis https://github.com/openmv/openmv/issues/1032
`
import machine, pyb, time
global triggered
triggered = False
def callback(arg):
global triggered
triggered = True
pyb.RTC().wakeup(1000, callback)
while (True):
machine.sleep()
# At this point the RTC will have woken us but the callback may not have been executed.
# This delay is essential to allow the callback to execute and update 'triggered'
time.sleep_ms(1) # Required minimum delay is not known. Do not use sleep_us()
if (triggered):
# Toggle green LED to indicate correct behaviour.
# 'triggered' is seen as having changed
pyb.LED(2).toggle()
else:
# Toggle red LED to indicate incorrect behaviour.
# 'triggered' is NOT seen as having changed
pyb.LED(1).toggle()
triggered = False
`
rtc.wakeup() behaves anomalously
The following sample does not behave as expected. The first and last LED flashes are of the correct duration, but the middle one is about 25% of that programmed. The problem seems to occur when a short delay is followed by a long one. Note that if in line 6 True is changed to False, the duration of the long flash is correct.
import pyb
rtc = pyb.RTC()
leds = tuple(pyb.LED(x) for x in range(1, 5)) # rgyb
for led in leds:
led.off()
if True:
x = 0
leds[x].on()
rtc.wakeup(1000)
pyb.stop()
rtc.wakeup(None)
leds[x].off()
x = 1
leds[x].on()
rtc.wakeup(15000) # far too short
pyb.stop()
rtc.wakeup(None)
leds[x].off()
x = 2
leds[x].on()
rtc.wakeup(400)
pyb.stop()
rtc.wakeup(None)
leds[x].off()
[edit]
The error is on this line
// set WUTIE to enable wakeup interrupts
// set WUTE to enable wakeup
// program WUCKSEL
RTC->CR |= (1 << 14) | (1 << 10) | (wucksel & 7);
Oring wucksel & 7 is leaving some bits set. This fixes it.
RTC->CR &= ~7;
RTC->CR |= (1 << 14) | (1 << 10) | (wucksel & 7);