The Pyboard's Hardware Timers
Contents
What are Microcontroller Timers?
Microcontroller timers are in-chip hardware peripherals that count clock pulses, independently of the main CPU, to accurately measure time, create precise delays, schedule tasks, generate waveforms (e.g. PWM).
In order to measure longer durations a hardware divider (prescaler) is used to divide a high-speed clock frequency into a slower rate for the timer.
The STM32F405RGT6 microcontroller has 17 timers of which 14 are exposed on the Pyboard. These are numbered 1 through to 14. Three of these timers (3, 5 and 6) are reserved by the Pyboard for other uses so should not be used in MicroPython programs.
MicroPython gains access to the timers through the pyb.Timer class. The next section provides a fairly simple introduction to this class.
MicroPython pyb.Timer Class
While timers can be used for a variety of tasks, the pyb.Timer class currently only implements the periodic calling of a function.
Syntax:
pyb.Timer(id, *, freq, callback=None)
Creates and returns a Timer object.
Where:
id : The timer number; can be 1 to 14.
freq : The frequency at which the timer
completes one full cycle in Hz.
callback : Sets the function to be called when
the timer triggers. If None is passed
then the callback is disabled.
Syntax:
Timer.deinit()
Deinitialises the timer.
Syntax:
Timer.callback(fun)
Set the function to be called when the timer
triggers. The callback function must have one
parameter. See the example in the next section.
There are additional methods not covered above. The important concept of channels is covered in this article; PWM on the Pyboard.
Example: Using Pyboard's Timers
This example will use two of the Pyboard's timers to manipulate the onboard LEDs while the main program independently performs the lengthy mathematical calculation of summing up the series of the first 1,000,000 integers.
Code:
# The LEDs are sequenced by timers while the main program
# performs a large mathematical calculation.
# The red, green and orange LEDs flash in turn each second.
# The blue LED separately flashes three times per second.
from pyb import Timer, LED
# Define the global variable.
id = 0
# Callback function for timer2.
def RunSeq(t):
global id
leds[id].toggle()
id += 1
if id == 3: id = 0
leds[id].toggle()
# Set up the LEDs.
red, green, orange, blue = LED(1), LED(2), LED(3), LED(4)
leds = (red, green, orange)
leds[0].on()
blue.on()
# Define the timers.
timer1 = Timer(1, freq=6)
timer2 = Timer(2, freq=1)
# Assign callbacks to the timers.
timer1.callback(lambda t: blue.toggle())
timer2.callback(RunSeq)
# Main program performs a mathematical intensive
# calculation while the timers periodical interrupt
# to continue sequencing the LEDs.
sum = 0
for i in range(1, 1000001):
sum += i
print('Sum of first 1,000,000 integers:', sum)
Output:
Sum of first 1,000,000 integers: 500000500000
Important Notes:
- Both of the callback functions have one parameter, t, each. When a timer is triggered it passes a reference to itself to the callback function through that parameter.
- A hard interrupt occurs when a timer is triggered. One of the consequences of this is the callback function cannot allocate memory (i.e. create variables, extend lists or dictionaries and so on).
Any variables used in the callback must already be allocated i.e. global variables. Hence the use of the global keyword in the RunSeq() function.