LOW-LEVEL ARDUINO PROGRAMMING(ASSEMBLER): TIMER INTERRUPTS

INTRODUCTION

In the third part ofÂ low-levelÂ programming AVR microcontrollers, we’ll be introduced with some new registries. We will use timer interrupts to create our own delay function in order to blink the LED on pin13.Â C programingÂ will be reused and in the next tutorial, we’ll switch toÂ Assembler.

So far we’ve done these:
Lesson 2.Â Bitwise operators

WHAT IS A TIMER?

Timer (more preciselyÂ Timer/Counter) is a piece of hardware-implemented into a microcontroller (other controllers and processors also have it). The timer is programed over special registries. For example, we configure aÂ prescaler, his mode, waveform generator which will be explained more thoroughly soon.

While we work with Dasduino (Atmel AVR ATmega328 microcontroller) we will concentrate on that part again. ATmega328 has three timers: timer0, timer1 i timer2. Timer0 and timer2 are 8bit timers, timer1 is 16bit. The main difference is the resolution, 8bit has 256 values and 16bit have 65536 for bigger a 16bitno 65536 for bigger resolutions.
All timers rely on system clocks, on Dasduino it is 16Mhz. All timers on Arduino firmware (bootloader) are configured on 1kHz frequency and all interrupts are enabled.

Imagine that you have a counter which on a press of a button increases by one. Timer/counter works on the same principle: counts beatsÂ of a clock. We’ve mentioned that the speed of counting is 16 million beats per second, approximately Â 63ns per beat or operation. 8bit timer will count from 0-255 and 16bit from 0-65535. The time needed for a counter to reset is 256/16.000.000= 16us, and 65536/16.000.000 = 4ms for a 16bit registry. it’s not a really practical way toÂ illuminateÂ the LED every 1 second. Instead of controlling the speed of timer/counter we will use something calledÂ Prescaler. In the next section, we will focus on registries in charge of timers, and in one of them, we will define the Prescaler.

Prescaler

Prescaler defines the speed of a certain timer (timer0, timer1 or timer2) according to this formula:

(timer speed [Hz]) = (Arduino clock speed (16MHz) [Hz]) / prescaler

According to theÂ datasheet, theÂ Prescaler has defined values ofÂ 1, 8, 64, 256 i 1024. It can be seen that the Prescaler 1 will increment the clock of 16MHz, Prescaler 8 2Mhz, Prescaler 64 250kHz, etc. Simply said, Prescaler set to 1024 will after every 1024 beats of 16Mhz timer/counter add 1 on his counter (timer0, timer1, timer2). To make it simple, In the time while John eats 1024 hamburgers, Bob will eat 1.

Let’s get back to timers. The first new registry we will mention in this tutorial isÂ OCRÂ –Â output compare registerÂ in which we will saveÂ compare matchÂ value. Does it seem to be too much at once? It is not, we’ve already mentioned all of the above, and now they’ve been given the official names. Insert it in the formula so we can visualize it better:

Explanation:
16Mhz – the speed of Arduino’s clockÂ timer/counter, we insert it as 16.000.000 Hz
brzina.timera – considering that we want to blink the LED every second, we insert the frequency 1Hz
-1 – counter number 0 so we insert -1 in the formula

From the table, we can see that the smallest Prescaler we can use is 256 for 16bit timer 1. Reason? ValueÂ 62499Â can be saved in the 16bit registry of timer1.
To measure counters in the frequency of 1Hz(1 second) we can use the Prescaler 1024, but it is much more accurate to use a smaller Prescaler. In none of these cases we can’t use 8bit timers timer0 and timer2.

Now when we’ve chosen the timer and prescaler it’s time to meet the registries that we need to set up.

Registries

For more check theÂ datasheet

TCCR1AÂ Timer count control registerÂ –Â 0b00000000Â (normal)(normal)
TCCR1BÂ Timer count control registerÂ –Â 0b00000100Â (no icr)(256-prescaler)
TCCR1CÂ Timer count control registerÂ –Â 0b00000000Â (no force)

OCR1AHÂ output compare register – high byteÂ 0xF4
OCR1ALÂ output compare register – low byteÂ 0x23

On these registries, we set up a calculated compare match value, 62499. Since we set upÂ high and low byteÂ separately we change 62499 from decimal to hexadecimal and that isÂ 0xF423. So high byte is Â 0xF4, and low byte 0x23.

TIMSK1Â timer interrupt maskÂ 0b00000010Â (output compare u enable – OCIE1A)

DDRB
PORTB

We’ve already mentionedÂ DDRBÂ andÂ PORTBÂ registries in theÂ first lesson.

C CODE

`void` `setup``() {`
`Â Â ``DDRB = B00100000; ``// portB5 (pin13) is set as output`
`Â Â ``cli();Â Â  ``//we are disabling all interrupts, so the timer interrupt won't be distrupted by another interrupt with higher priority`
`Â Â ``TCCR1A = 0b00000000;`
`Â Â ``TCCR1B = 0b00000100;`
`Â Â ``TCCR1C = 0b00000000;`
`Â Â ``OCR1AH = 0xF4;`
`Â Â ``OCR1AL = 0x23;`
`Â Â ``TIMSK1 = 0b00000010;`
`Â Â ``sei();Â Â  ``// we re-enable interrupts including timer interrupts`
`}`
`ISR(TIMER1_COMPA_vect) { ``// timer compare interrupt service routine`
`Â Â ``PORTB ^= 0b00100000;Â Â  ``// XOR operator, if the LED is on we turn it off and vice versa`
`}`
`void` `loop``() {`
`}`

TIMER LIBRARY

There are a couple of timer libraries that use different functions. We will get busy only with those that we’d use in the example of blinking LED, find more onÂ Arduino references.

Timer0
For functions it represents itself as delay(), millis() and micros().

delay()Â – stops the microcontroller for a given time in milliseconds, there is also this functionÂ delayMicroseconds()Â  etc.
millis()Â – a function that has saved time from the start of a microcontroller or its restart in milliseconds. Until theÂ overflow,Â it can count for around 15days.
micros()Â – a function that has saved time from the start of a microcontroller or its restart in microseconds. Until theÂ overflow,Â it can count for around 70 minutes.

Example of a blinking LED without the delay() function:

`unsigned ``long` `proslo_vrijeme = 0;Â Â Â Â Â Â Â  ``// we generaly use unsigned long for variables that save time`
`void` `setup``() {`
`Â Â ``pinMode``(13, ``OUTPUT``);`
`}`
`void` `loop``() {`
`Â Â ``unsigned ``long` `trenutno_vrijeme = ``millis``();Â  ``// saves current time from the start of the microcontroller`
`Â Â ``if` `(trenutno_vrijeme - proslo_vrijeme >= 1000) {`
`Â Â Â Â ``proslo_vrijeme = trenutno_vrijeme; ``// saves when did the LED blink last time`
`Â Â Â Â ``digitalWrite``(13, ``digitalRead``(13) ^ 1); ``// change the state of LED`
`Â Â ``}`
`}`

CONCLUSION

Besides the fact that the functions we’ve just worked with allow us toÂ multitask,Â they give us a much better insight into the duration time of the process itself. If we compare the blinking of a LED on this way and the one on ArduinoÂ digitalWrite()Â andÂ delay()Â functions, we can see that after some time we have deviations in moments when the LED blinks.

For much more accurate work monitoring of microcontrollers and interrupts it is necessary to go down a bit on program language scale. After these short introduction lessons, we will start with AssemblyÂ programming.