Some questions about AVR Timers/counters - Page 1
Forum section: electronics / general

author: HwAoRrDk
author_rank: Super Contributor
timestamp: January 24, 2017, 11:24:06 pm
content: I was just working on some code that uses a couple of timers of my AVR (ATmega328P), and suddenly some doubts came to mind about whether I'm doing things 'properly' or leaving myself open to some inaccuracies or side-effects.What is the proper way that one should turn a timer on/off? And, if one turns a timer back on that had previously been turned off at an arbitrary point, should one manually reset the counter register?At the moment, to turn a timer 'off', I'm simply flipping the enable bit for the relevant Output Compare interrupt (e.g.TIMSK2 &= ~(_BV(OCIE2A))). However, I've come to realise that this isn'treallyturning the timer off - just disabling the interrupt. Should I also be zeroing the Clock Select bits to set the timer to 'no clock source' in order to actually turn it off? I'm assuming the timer still runs on otherwise. Or... alternatively, is there any harm in my current approach?Also, regarding the counter values, at the moment I'm also not touching the counter register when I turn the timer back 'on'. I had a thought that it's quite likely that if I turn the timer interrupt on at a point where the counter value is nearly at it's compare threshold, I'll get an interrupt virtually straight away, as opposed to until the expected amount of time has passed. Am I correct here? If so, is advisable for me to always explicitly zero the counter value (e.g.TCNT2 = 0) when turning 'on' the timer?What got me to thinking about this stuff is that I am attempting to drive a software UART (TX only) with Timer1, and have been getting some occasional garbage characters, inflicted by bad bit waveforms, which leads me to think that my timing isn't always spot-on - with the latter issue above perhaps being a major factor.

author: FreddyVictor
author_rank: Regular Contributor
timestamp: January 25, 2017, 08:47:10 am
content: To stop a timer, try:TCCR1B &= ~((1<<CS12) | (1<<CS11)|(1<<CS10)); // nb: not tested !yes, if you want the counter to restart from 0, then you'll need to clear it before you re-enable the timeralso, you might need to set pin hi/lo to known state if stopped unusually (?)Is this for Debugging, then using the Arduino SoftSerial (like I suggested) seems alot easier - I used it alot and can't remember having problems (interrupts running but all momentary)Have you tried UART Rx yet ? coz that's a little more challenging using Timer & PinChangeInt

author: ajb
author_rank: Super Contributor
timestamp: January 25, 2017, 01:17:54 pm
content: Mostly the answers to your questions depend on the application. If you're using the timer to fire an interrupt X clock ticks from now, you zero the timer and then and set OCR to X, or you can set OCR to CNT + X. The latter is better if you want to be able to use the timer's other compare channels for other purposes. In either case, you'd want to load OCR before re-enabling the interrupt. If you've left the timer running, you should also clear the interrupt flag manually before enabling the interrupt, as typically the interrupt flag is set at the relevant event even if the interrupt is not enabled.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: January 25, 2017, 03:11:22 pm
content: Okay, so before turning the timer back 'on', I should not only be zeroing the counter value, but also clearing the output-compare interrupt flag. So, for example:Code:TCNT2 = 0;TIFR2 |= _BV(OCF2A);By the way, I find the description of the latter register in the datasheet fairly nonsensical. So, a value of 1 for OCF2A means a compare match has been triggered, but in order to 'clear' it (which I take to mean set its value back to zero), you have to write a 1 to it... Eh, whatever.But anyway, this should take care of any spurious early interrupts I may have been getting, right?So part of my other question still stands: is there any downside to leaving the timer running but just turning off interrupts for it?Hmm, if I do stop it properly by zeroing the CS bits, I'll have to save what the value was first so it can be re-instated when the timer needs to be restarted. This is because I have some code that dynamically chooses the prescaler and OCR value according to what frequency is specified, so the CS bits could be anything.Quote from: FreddyVictor on January 25, 2017, 08:47:10 amYes, just for debug output. I did actually initially try a simple delay-based UART transmitter, but because I was disabling interrupts during transmission of each byte, it garbled the sound of the buzzer if I was beeping it at the same time as a printf(). Sounded like a small rodent being strangled.No need for RX - output only.

author: ajb
author_rank: Super Contributor
timestamp: January 25, 2017, 03:48:36 pm
content: Quote from: HwAoRrDk on January 25, 2017, 03:11:22 pmThat's just a result of how they've implemented set by hardware and clear by software in the same register location. Some MCUs provide the basic register as well as dedicated set/clear registers at separate locations.QuoteWell, that will take care of one class of possible spurious interrupts. There could be others, without examining the rest of your code it's impossible to say.QuoteProbably not, as long as you clear the interrupt flag before re-enabling that should work fine. The only real downside, as long as the timer isn't tied into other things that should stop at the same time, is maybe slightly higher power consumption, but unless you're counting microamps that's probably not a concern.

author: eblc1388
author_rank: Frequent Contributor
timestamp: January 26, 2017, 04:20:04 am
content: Quote from: HwAoRrDk on January 25, 2017, 03:11:22 pmLet's suppose one has to write a '0' to clear it, so you duly placed a '0' in where the compare match bit is. Please then ask yourself what logic value one should put in the other 7 bits before sending the value to the TIFR2 register?Your obvious answer would be '1', right? Now, in addition to clearing the compare match bit, your are also setting all the 7 other bits, is this what you want?Your next answer would be a '0'. Unfortunately, in addition to have cleared the bit you wanted, you also cleared every other bits that represent interrupt triggered but has not been serviced yet.Your final answer may be "I'll read the value of the register first and then clear that particular bit I wanted.". Looks good, but then you need three steps, read-modify-write. What happens if an interrupt bit in TIFR2 gets set during the first two steps? You have just cleared a pending interrupt with the write operation.Luckily, the engineers at ATMEL had decided that a '0' will do nothing to the bit value so you can safely clear a single bit using by setting that bit to '1', preserving any bit changes while the operation is carried out.

author: dgtl
author_rank: Regular Contributor
timestamp: January 27, 2017, 10:43:20 am
content: Write 1 to clear is the best way of doing it. Actually, the important part is "write 0 to do nothing". Some manufacturers have also used the inverse (write 0 to clear, write 1 to do nothing), same thing.For bits that can be modified by both the code and the hw (hw sets irq flag, code clears it), the safe implementation requires "do not touch" option. If there are multiple bits in one register, you have to be able to write some and not write the others.For a programming language point of view, it is easier to start with value of 00..0 and add bits, not the opposite of starting of 11..1 and clear bits (ie if you want to clear 3 of the 8 bits). So the Atmel's implementation is the preferred way. If the implementation is "write 1 to clear", you can just write back the value you have read from the same register to clear those bits that were set, another bonus.The typical use of irq flags is following: you read the flags register, handle these that are set and clear these. You do not want to touch whatever other flags got set inbetween. If the irq flags register was a typical read-write register, then even if you do the clear with read-modify-write, there is still a possibility that a flag got set between the read and write instruction (or even during write, so atomic read-modify-write command doesn't help as well if the architecture has it) and you'll overwrite that bit low without knowing that there was an interrupt condition.For an example of a terrible and programmer-unfriendly hw, see STM32 non-otg USB device controller register EPnR. In one 16-bit register where are 1) read-write bits 2) write 0 to clear bits 3) write 1 to toggle bits. There are even bitfields, that consist of "write 1 to toggle" bits. Although it is safe in a sense that no information gets lost between hw and sw concurrent accesses, it is terrible and very inefficient on sw side. I understand that they probably did this to simplify their clock-crossing between the system clock and usb clock parts, but still... This is how it should not be done. At least have the same "dont change" values in one register, whatever the value is.

author: Brutte
author_rank: Frequent Contributor
timestamp: January 27, 2017, 11:31:35 am
content: Quote from: HwAoRrDk on January 25, 2017, 03:11:22 pmand prescaler. Prescaler also belongs to the state of TCNTx, if used. Actually it is shared between several timers so that one could synchronize them.As for stopping, starting and resetting a TCNTx, that is a matter of definition but usually stop means about same thing as initializing. I'd say that disconnecting a clocking source could be qualified as pausing but not stopping. YMMV.