Timer Interrupts: Here Arduino Due Forum Post
Timer Interrupts: Here Arduino Due Forum Post
Add comments
In this section we will write the SOS program using timer interrupts instead of delay()
We did some work with hardware interrupts back in the LCD tutorial, now we are going to work
with timer interrupts. Think of a timer interrupt as, “call this function once a second”. This is
done by attaching an interrupt function to one of the Arduino’s internal timers. I was able to find
a library that supported the use of timer interrupts for the Arduinos that use the Atmega
128/328 here . But not one for the Arduino Due, rather there was a very useful forum post on
using timer interrupts for the Due. Some of this code will look different from the code that you
usually see when using one of the libraries provided with the Arduino IDE. Most of it comes
directly from the Atmel ASF ( Atmel Software Framework ), which ultimately is used to write the
Arduino libraries. You don’t need to do anything extra to your build environment to use these,
the only problem is that they are not well documented, at least not for a beginner. You can find
the reference docs at http://asf.atmel.com/docs/latest/api.html.
Unfortunately this is not the easiest documentation to navigate. It can be hard to find what you
want if don’t know a particular acronym, or specific term to describe what you want. The
Arduino Due uses the SAM3X8E processor. The documentation is not organized by processor
type, (though you can sort by device type) but by the type of functionality you are interested in.
For example, if you wanted to read about timers, you would navigate to one of several entries,
then look for your processor. For this example there is a Timer entry, followed by RTC ( real
time clock) with a “sam3” in the supported device column, when you expand that entry you see
sam3x, which are the docs that refer to the Sam3x8E. I say all this just to point out that
reference material is usually written for a subset of devices, not a single device. You may also
find the datasheet for the SAM3X8E to be helpful.
To learn about timer interrupts lets build the SOS program, but using timer interrupts instead of
calls to delay(). There are 9 timer channels that we can use, some of them are used by other
libraries, for example the Servo library uses several, if you get a “multiple definition” error for
one of the TC_handler() functions, that is probably what is going on, you’ll just need to use a
different interrupt. There are 4 different clock frequencies we can use when we set how often
the interrupt should trigger. They simply divide the main processor frequency by /2, /8, /32, or
/128. Since the main processor has a frequency of 84Mhz, and we are trying to flash a LED a
couple times per second at most, we want the /128.
How fast is our timer if we hook it up to the /128 clock?
84 Mhz / 128 = 656,250 Hz (or 656 kHz).
Then how many timer “clicks” do we want to wait to turn the LED on or off? Lets assume the S
will blink every .2 seconds. Then we want
So from the view of the timer we are saying, turn the LED on then count to 131,250, then turn it
off.
For the O, lets flash the LED once every second, we want (1)*(656250) = 656,250.
Lets not get bogged down in details just yet, here is the code to run the SOS program with
timer interrupts, go ahead and upload it, then we’ll cover what the code does.
void loop()
{
// do nothing timer interrupts will handle the blinking;
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// INTERRUPT HANDLERS
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////
void TC7_Handler()
{
// We need to get the status to clear it and allow the interrupt to
fire again
TC_GetStatus(TC2, 1);
state = !state;
digitalWrite(led_pin, state);
That’s quite a bit more complicated than the first time we demonstrated this program. Lets go
line by line, and explain what is going on. The first 4 lines should look familiar.
const int led_pin = 13; // use port 13 for to power the LED.
int state = false; // 'state' will mean on or off
int interruptCtr = 1;
int S = 0;
The first line just assigns our LED to a port. The ‘state’ variable will be used to keep track of
whether the LED is on or off. The variable ‘interruptCtr’ is used to keep track of how many
interrupts have occurred since the last time we made a change, and the ‘S’ variable will keep
track of whether we are currently flashing ‘S’ or ‘O’
In the setup() function we have to do some work to get the timers set up, First we need to
disable write protection the pmc registers ( power management controllers). In other words,
enable the pmc registers. These are turned off by default, because power consumption is very
important for some users of these chips, by leaving them off you are less likely to unknowingly
waste power.
the first line disables write protection for the power management controller registers. The
second line enables the peripheral clock, we will use TC7. If you look at the sites I started with
for this, RC Arduino you’ll see they’re not using TC7, the problem I ran into is that the servo
library uses the same timers, so I had to use a different timer.
The next line is a call to TC_Configure(). The first parameter is choosing TC2 as the timer we
want to use, the second parameter chooses which channel of the TC2 to use, and the third
argument is using the bit wise OR operator, in effect it is saying to use the 3 settings,
TC_CMR_WAVE means to choose waveform mode ( as opposed to Capture Mode),
TC_CMR_WAVESEL_UP_RC means to set the counter to run up, and reset when it equals
RC, TC_CMR_TCCLKS_TIMER_CLOCK4 means we want to run the clock at MCR/128. For
more detail on these settings, see section 37.7 of the datasheet.
Next we need to enable the timer interrupts, this is done with the following two statements.
Next we need to enable the nested vector interrupt controller, which handles all interrupts.
We don’t need to do anything in the loop() section, our interrupt routines do all the work. Every
time the interrupt occurs, we toggle the ‘state’ variable. This is done with the line.
state = !state;
Then use digitalWrite() to set the led pin.
Next we check ‘interruptCtr’. We want to change the letter we are flashing every 6 interrupts,
on-off-on-off-on-off is a total of 6 interrupts. If it has been six times, then we toggle
the ‘S’ variable and call TC_SetRC() to change the interrupt interval.
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// INTERRUPT HANDLERS
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////
void TC7_Handler()
{
// We need to get the status to clear it and allow the interrupt to
fire again
TC_GetStatus(TC2, 1);
state = !state;
digitalWrite(led_pin, state);