Trying to understand some ATMEL Example code

I’m reading through Atmel’s document “AVR130: Setup and Use the AVR Timers” and I’m trying to understand the example code for the Timer Input Capture Interrupt.

I “think” I understand the programming semantics involved, but what I thought I understand is not consistent with the example before me. Here is the example, as it appears in Atmel’s application note:

void init_Ex2(void) {

TCCR1B = (1<<CS11)|(1<<CS10);  //Timer clock = system clock/64
TIFR = 1<<ICF1;           // Clear ICF1/clear pending interrupts
TIMSK = 1<<TICIE1;      // Enable Timer 1 Capture Event Interrupt
DDRB = 0xFF;               // Set Port B as Output
DDRD &= ~(1<<PD6);     // Set PD6 as input

}

My questions have to do with this segment of code, so I won’t list out the corresponding ISR with this code.

My first problem is the use of the “=” sign. For instance, the first line of code (if I understand it correctly) sets the CS11 and CS10 bit’s to “1” and sets all other bits to “0”. Right?

CS11 = 1
CS10 = 0

Following the left-shift operation followed by the bitwise OR operation would result in: b00000011. Following the “=” operation, the result would be TCCR1B = b00000011, right? The 0’s of the value would over write any 1’s that were originally set? Maybe this is what is desired, but I recall reading that a “|=” operator is better because then you just set the specific bits that you want. Or perhaps I’m missing something and the “=” operator on special registers performs some OR operation behind the scenes?

My other issue with this example is this line here:

TIFR = 1<<ICF1;           // Clear ICF1/clear pending interrupts

Wouldn’t setting the ICF1 bit in the TIFR register to “1” effectively set the interrupt flag (not clear it like the comment suggests)? Maybe my logic is inverted in my mind, but I thought “1” in that bit of that register means that the interrupt flag is set. If you look at the corresponding assembly language example, it looks like the author does the exact same thing. Am I missing something?

Thanks,
-Nickerbocker

My first problem is the use of the "=" sign. For instance, the first line of code (if I understand it correctly) sets the CS11 and CS10 bit's to "1" and sets all other bits to "0". Right?

CS11 = 1 CS10 = 0

Following the left-shift operation followed by the bitwise OR operation would result in: b00000011. Following the "=" operation, the result would be TCCR1B = b00000011, right? The 0's of the value would over write any 1's that were originally set?

The shift is higher priority than the OR. So it shifts a 1 left the appropriate number of bits. It ORs the appropriate ones together and assigns the result to TCCR1B so whatever was in TCCR1B before is irrelevant.

Wouldn't setting the ICF1 bit in the TIFR register to "1" effectively set the interrupt flag (not clear it like the comment suggests)?

Page 140 of the datasheet:

ICF1 is automatically cleared when the Input Capture Interrupt Vector is executed. Alternatively, ICF1 can be cleared by writing a logic one to its bit location.

The interrupt event sets the flag. You don't set it. Executing the interrupt routine clears it, or if you want to clear it in advance (to avoid spurious interrupts) you write a 1 to that flag. It is done that way so that writing zero has "no effect", not clearing the flag.

The other bits in TCCR1B are:

bit 2: CS12

This is the other prescaler bit. To get the speed they say, you’d have to set this to zero. It would be dangerous to just leave it in the old state since you need it to be zero.

bits 3 and 4:WGM12 and WGM13

These bits have to do with PWM driving and should best be set to zero since this code isn’t using PWM.

bit 6: ICES1
bit 7: ICNC1

These two should be thought about and set whenever you set up the register. If you want falling edge detection and no noise cancellation, then both should be set to zero. You wouldn’t want to just leave them as is unless you already knew what they were.

So they are not using an |= because they don’t want to leave those bits set to whatever they were before. They are using = because they want those bits set to zero. Shifting in zeros to all those positions would be wasteful.

Maybe this is what is desired, but I recall reading that a "|=" operator is better because then you just set the specific bits that you want

It's the difference between:

a = 1;
a |= 1;

The first line sets all bits to a known state, which you probably want in this case. The second line sets a single bit (which may already be set).

I recall reading that a "|=" operator is better because then you just set the specific bits that you want.

I find the "|=" operator to be overused on hardware registers in Arduino code, when the previous content of the register is unknown, and really SHOULD be set to a known value. When you reconfigure a timer, you really do want to set all the bits to the correct values for the new configuration, and not just leave some of them at whatever they happened to be beforehand.

Thank you for the feedback.

[quote author=Nick Gammon link=topic=176564.msg1310252#msg1310252 date=1373414016]

My first problem is the use of the "=" sign. For instance, the first line of code (if I understand it correctly) sets the CS11 and CS10 bit's to "1" and sets all other bits to "0". Right?

CS11 = 1 CS10 = 0

Following the left-shift operation followed by the bitwise OR operation would result in: b00000011. Following the "=" operation, the result would be TCCR1B = b00000011, right? The 0's of the value would over write any 1's that were originally set?

The shift is higher priority than the OR. So it shifts a 1 left the appropriate number of bits. It ORs the appropriate ones together and assigns the result to TCCR1B so whatever was in TCCR1B before is irrelevant.

Wouldn't setting the ICF1 bit in the TIFR register to "1" effectively set the interrupt flag (not clear it like the comment suggests)?

Page 140 of the datasheet:

ICF1 is automatically cleared when the Input Capture Interrupt Vector is executed. Alternatively, ICF1 can be cleared by writing a logic one to its bit location.

The interrupt event sets the flag. You don't set it. Executing the interrupt routine clears it, or if you want to clear it in advance (to avoid spurious interrupts) you write a 1 to that flag. It is done that way so that writing zero has "no effect", not clearing the flag. [/quote]

Thanks for explanation. I missed that part in the manual. I had a feeling it was a matter of convention. So right after setting the 1, would a read operation read a 0 for that bit?

westfw:

I recall reading that a "|=" operator is better because then you just set the specific bits that you want.

I find the "|=" operator to be overused on hardware registers in Arduino code, when the previous content of the register is unknown, and really SHOULD be set to a known value. When you reconfigure a timer, you really do want to set all the bits to the correct values for the new configuration, and not just leave some of them at whatever they happened to be beforehand.

Being that I'm inexperienced with AVRs, I think it comes from a fear of mucking something up due to not fully understanding all the functionality.

Nickerbocker: Thanks for explanation. I missed that part in the manual. I had a feeling it was a matter of convention. So right after setting the 1, would a read operation read a 0 for that bit?

Yes it would, unless a timer event occurred which set it back on in the meantime.