← index #1128Issue #2971
Related · high · value 0.068
QUERY · ISSUE

Performing operations on non-initialized Timer leads to crashes/lockups

openby nadrimajstoropened 2015-02-22updated 2015-10-25
ports

After pressing RESET button and typing:

Micro Python v1.3.10 on 2015-02-13; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> n = 3
>>> def countdown(timer):
...     global n
...     if n <= 0:
...         print("Launch!")
...         timer.deinit()
...     else:
...         print(n)
...         n -= 1
... 
>>> tim = pyb.Timer(4, freq=1, callback=countdown)

At this moment REPL hangs and I need to press RESET to recover. :cry:

Probably related issue:

Micro Python v1.3.10 on 2015-02-13; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> n = 3
>>> def countdown(timer):
...     global n
...     if n <= 0:
...         print("Launch!")
...         timer.deinit()
...     else:
...         print(n)
...         n -= 1
... 
>>> tim = pyb.Timer(4)
>>> tim.callback(countdown)
>>> tim.init(freq=1)
>>> # Nothing happens :|

Nevertheless it does work if I continue and provide both kwargs:

>>> tim.init(freq=1, callback=countdown)
3
>>> 2
1
Launch!

However, if I continue with:

>>> tim.deinit()
>>> tim.callback(countdown)
>>> Launch!

I did not expect after issuing deinit() to have triggered callbacks without explicitly calling init with freq kwarg. :confused:
And after issuing a soft reset

PYB: sync filesystems
PYB: soft reboot
Micro Python v1.3.10 on 2015-02-13; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> tim = pyb.Timer(4, callback=print("I did not set freq option"))
I did not set freq option
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: must specify either freq, or prescaler and period
>>> tim = pyb.Timer(4)
>>> tim.callback(print("I did not set freq option"))
I did not set freq option
>>> 

It certainly comes as a surprise that callback is still kicking without explicit freq

CANDIDATE · ISSUE

RFC: defining machine.Timer

openby dpgeorgeopened 2017-03-21updated 2026-03-18
proposed-close

This issue is to discuss the API of the machine.Timer class. There are currently 3 different version of Timer which don't have much in common:

esp8266:

# id must be -1, period is in milliseconds, mode is PERIODIC or ONE_SHOT
Timer(id, *, period, mode, callback) # constructor
Timer.init(*, period, mode, callback) # reinitialise all parameters
Timer.deinit() # stop the timer

cc3200/wipy:

# mode is PERIODIC, ONE_SHOT or PWM
Timer(id, mode, *, width=16) # constructor
Timer.init(mode, *, width=16) # reinitialise
Timer.deinit() # stop

# each timer has one or more channels
# each timer channel is associated with a specific IO pin (eg for PWM)
Timer.channel(*, freq, period, polarity, duty_cycle) # create channel assoc with TImer
TimerChannel.freq([freq]) # get/set
TimerChannel.period([period]) # get/set
TimerChannel.duty_cycle([duty]) # get/set
TimerChannel.irq(...) # get or set up the IRQ callback

stmhal/pyboard (actually pyb.Timer):

# freq is in Hz (can be float <1), prescaler/period are raw values, mode is UP/DOWN/CENTER
Timer(id, *, freq, prescaler, period, mode, div, callback, deadtime) # constructor
Timer.init(*, freq, prescaler, period, mode, div, callback, deadtime) # reinit
Timer.counter([value]) # get/set the raw timer counter
Timer.source_freq() # get source frequency that clocks this timer
Timer.freq([value]) # get/set
Timer.prescaler([value]) # get/set
Timer.period([value]) # get/set
Timer.callback(callable) # get/set callback (pass None to disable)

# each timer has multiple chanels (usually 4)
# pin is the pin to associate with the channel (eg for PWM)
Timer.channel(mode, *, callback, pin, pulse_width, pulse_width_percent, compare, polarity) # create
TimerChannel.pulse_width([value]) # get/set
TimerChannel.pulse_width_percent([value]) # get/set
TimerChannel.capture([value]) # get/set
TimerChannel.compare([value]) # get/set
TimerChannel.callback(callable) # get/set callback

To compare current usage, for a simple periodic timer at 10Hz one would do:

# esp8266
t = Timer(-1)
t.init(period=100, mode=Timer.PERIODIC, callback=lambda t:print(t))

# stmhal/pyboard
Timer(1, freq=10, callback=lambda t:print(t))

For a one-shot after 2 seconds:

# esp8266
t = Timer(-1)
t.init(period=2000, mode=Timer.ONE_SHOT, callback=lambda t:print(t))

# stmhal/pyboard
def cb(t):
    print(t)
    t.deinit() # or t.callback(None)
Timer(1, freq=0.5, callback=cb)

At the very least I'd suggest that all ports have the same interface to create periodic and one-shot timers, as well as the same way to configure the timer irq/callback. Configuration of the irq should follow the samy signature as machine.Pin.irq(); see also #2297.

I also feel that a timer should have start() and stop() methods, so that one can create an initialise a timer at one point in the code, then start it precisely when needed. This requires definining that the first callback happens one period after start() is called.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied