Bug in the pyb.Timer's callback or a user mistake

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
User avatar
nadrimajstor
Posts: 4
Joined: Sat Jan 24, 2015 11:39 pm

Bug in the pyb.Timer's callback or a user mistake

Post by nadrimajstor » Sun Feb 08, 2015 6:55 pm

While trying to make a PR for addition of example "How to use named function for a pyb.Timer's callback" (i.e. make it obvious that named function will receive 1 argument - timer object) I came up with:

Code: Select all

def tick(timer):                # we will receive the timer object when being called from the timer
    print(timer.counter())      # show current timer's counter value
tim = pyb.Timer(4, freq = 1)    # create a timer object using timer 4 - trigger at 1Hz
tim.callback(tick)              # set the callback to our tick function
However, trying that example will show some value for the first trigger and print just zeros for all subsequent triggers. :?:

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Bug in the pyb.Timer's callback or a user mistake

Post by pythoncoder » Mon Feb 09, 2015 8:45 am

That's how timers work. They count up to a value determined by the desired frequency, then they reset to zero and the callback function is called. So your callback will always output zero, apart from the first instance. The timer appears to invoke the callback once at the moment it's assigned to it. Consequently it will return an arbitrary value at this point.
Peter Hinch
Index to my micropython libraries.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Bug in the pyb.Timer's callback or a user mistake

Post by dhylands » Mon Feb 09, 2015 4:28 pm

Whether the callback is called immediately depends on whether an interrupt has been queued for the timer or not.

As soon as the timer is initialized, it will start counting. If an interrupt is pending by the time the callback is assigned (seems unlikely in this particular case), then the callback will be called immediately.

If you really wanted to see the passage of time, then you could use 2 timers. One that interrupts every second, and one that wraps at some lower frequency.

The timers have a few key registers:
1 - The source frequency (which is either 42 or 84 MHz)
2 - A prescaler
3 - A period
4 - A counter

The timer increments the counter (source_freq / prescaler) times per second. When the counter reaches the period, then the counter is reset to zero and the interrupt fires (as @pythoncoder mentioned). This is for simple counting mode, other modes can have interrupts firing for different reasons.

User avatar
nadrimajstor
Posts: 4
Joined: Sat Jan 24, 2015 11:39 pm

Re: Bug in the pyb.Timer's callback or a user mistake

Post by nadrimajstor » Mon Feb 09, 2015 7:58 pm

Ahaaa...
I had utterly wrong notion of all counters having the same fixed maximum value, ticking at some internal maximum frequency, and wrapping to zero when the max value is reached. :oops:
I like this notion of having my own, per instance, counter's max value and wrapping to zero when triggered, more. :)

The discrepancy in values observed is due to the fact that I typed those lines in the REPL, so by the time I assigned callback function interrupt is already pending and my function is called immediately. (slight gotcha to keep in mind)

After a soft reboot I went on trying to set callback before initializing timer, and come with this little oddity:

Code: Select all

PYB: sync filesystems
PYB: soft reboot
Micro Python v1.3.9-6-g2f8c409-dirty on 2015-01-26; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> import pyb
>>> tim = pyb.Timer(4)
>>> tim.deinit()
>>> tim.callback(lambda t: print(t.counter()))
>>> 0
0
0
0
0
0
0
:?

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Bug in the pyb.Timer's callback or a user mistake

Post by dhylands » Mon Feb 09, 2015 11:11 pm

Yeah - it will disable the callback when you call deinit.

However, it doesn't really have a notion of open versus closed, so calling the callback function re-enables the interrupt.

User avatar
nadrimajstor
Posts: 4
Joined: Sat Jan 24, 2015 11:39 pm

Re: Bug in the pyb.Timer's callback or a user mistake

Post by nadrimajstor » Tue Feb 10, 2015 9:55 am

The thing that bugs me is how do I repurpose the timer with the same id?
As soon as I add new callback the timer starts with old freq value i.e. I did call

Code: Select all

deinit()
so I expect him to be inactive until I call

Code: Select all

init()
with new arguments.
Or is it a best practice to just use another id?

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Bug in the pyb.Timer's callback or a user mistake

Post by dhylands » Tue Feb 10, 2015 3:45 pm

You can pass calback as an argument to init using callback=

Any callback set between deinit and init will (or at least should) be wiped out when init is called anyways.

Specific timers are tied to specific pins, so normally you're restricted as to which id you use.

Post Reply