Register manipulation ? ? ?

Folks,

I have come across this piece of code in setting up a software interrupt timer (after ploughing through the ATMEL 168 manual). Although it works, for my own benefit (and possibly others), I'd like to know what is actually happening.

Code snippet - start

TCNT2 = 0x00 ;
OCR2A = 250 ; // 1mS @ Fosc (16MHz)
TCCR2A = 0x02 ; // WGM: N wave gneration
TCCR2B = 0x04 ; // Start Timer - prescaler = 64

TIMSK2 = ( 1<<OCIE2A ) ; // Enable interrupt when Timer reaches OCRA

sei();

Code snippet - end

... in particular "TIMSK2 = ( 1<<OCIE2A )".

Normally, the following instruction would produce a value of 8;
1 << 3

OCIE2A is a bit value (either 0 or 1) within the TIMSK2 register.

In the case of (1<<OCIE2A) part of the code.

My assumption would be that;

  • If OCIE2A had a value of 0, then the result of the above expression would be 1.
  • If OCIE2A was set to 1 then the result to the expression would be 2.

What concerns me is that there are three bits in the TIMSK2 register. The assignment statement would over-write the bits with a resultant 1 or 2.

Would it not be easier to simply OR in a value???

Pardon the long background explanation but I'm confused.

Regards,
Nick

Nick:

Normally, the following instruction would produce a value of 8;

TCCR2A, TCCR2B, and TIMSK2 are bitmapped registers. This means that each individual bit (or sometimes a group of bits) controls something but the overall numeric value has no real meaning. You will be a lot better off in the long run if you don't think of bitmapped registers in terms of decimal numbers, but instead use binary.

So - TCCR2A = 0b00000010
TCCR2B = 0b00000100
and TIMSK2 = 0bxxxxxx1x

... in particular "TIMSK2 = ( 1<<OCIE2A )".

Would it not be easier to simply OR in a value???

Isn't that what is being done here? (I'm not fluent in C)

  • If OCIE2A had a value of 0, then the result of the above expression would be 1.
  • If OCIE2A was set to 1 then the result to the expression would be 2.

If OCIE2A was originally 0b00000000 then the result of the above expression would be 0b00000010
If OCIE2A was originally 0b00000001 then the result of the above expression would be 0b00000011

You might want to look at some diagrams I made for my own use in figuring out these timers. Go to http://web.alfredstate.edu/weimandn, scroll down to the Atmel ATmega Subsystem Diagrams section, follow the Reference Diagrams link, and look at some of the Timer/Counter2 diagrams.

73 - Don

You might want to look over the code in the software timer interrupt library called MStimer2 in the Arduino playground. Or just use that library, I've found it useful and effective.

http://www.arduino.cc/playground/Main/MsTimer2

Lefty

I have come across this piece of code in setting up a software interrupt timer (after ploughing through the ATMEL 168 manual). Although it works, for my own benefit (and possibly others), I'd like to know what is actually happening.

           TCNT2 = 0x00 ;

OCR2A = 250 ;                  // 1mS @ Fosc (16MHz)
          TCCR2A = 0x02 ;            // WGM: N wave gneration
          TCCR2B = 0x04 ;            // Start Timer - prescaler = 64

TIMSK2 = ( 1<<OCIE2A ) ; // Enable interrupt when Timer reaches OCRA
          sei();



... in particular "TIMSK2 = ( 1<<OCIE2A )".

OCIE2A is a bit value (either 0 or 1) within the TIMSK2 register.

You are confusing the actual bits in the hardware with the SYMBOLS that avr-gcc is defining to help you access them. While some languages aimed at microcontrollers allow you to access individual register bits by name, normal C/C++ is not one of them. Instead, symbols are defined to HELP you access the bits. Since OCIE2A is bit 1 in the TIMSK2 register, it is simply defined as #define OCIE2A 1  // in .../include/avr/iom328p.hSo (1<<OCIE2A) is simply a constant (2), and the assignment sets TIMSK2 to 2 (enabling one interrupt and disabling the two others.)
The careful programmer might write one of

  TIMSK2 = (0<<OCIE2B) | (1<<OCIE2A) | (0<<TOIE2); //yes, do all the bits
or
  TIMSK2 |= (1<<OCIE2A); // only change OCIE2A

(the bits COULD be defined as bitmasks instead of bitnumbers, like "#define OCIE2A 0x2", but using the bitnumbers is more consistent with the assembly languages instructions for bit set and bit clear, and as long as the definitions are consistent, either way should work fine.)

to check the current value of the OCIE2A bit, you would have to doif (TIMSK2 & OCIE2A) ...

TIMSK2 |= (1<<OCIE2A); // only change OCIE2A

This is what I was thinking about when I said "Isn't that what is being done here?"

...and the assignment sets TIMSK2 to 2 (enabling one interrupt and disabling the two others.)

Correct, but I still maintain that the decimal value '2' doesn't really mean anything. One has to mentally convert the '2' to 00000010 and look at the bold part in order to come up with the information you have in parentheses. If it was stated in binary to begin with then the mental conversion would not be necessary.

Don

'2' doesn't really mean anything.

Of course not. Neither does "0b010" (or whatever you end up using for a binary number.) "OCIE2A" is much better than either one, once you understand how it is used.

Of course, the way things are set up, nothing prevents you from mismatching the register and the bit value like  UDR0 |= 1<<OCIE2A;
Some compilers end up defining complex data structures for each peripheral

typedef struct timer_intmsk_ {
   byte toie:1;
   byte ociea:1;
   byte ocieb:1;
   byte _pad:5; // define all 8 bits
} timer_intmsk_t;

and then you can do something like((timer_intmsk_t)(TIMSK2)).toie = 1;
But this tends to get overly verbose, may prevent the programmer and compiler from producing good code, is less portable (which end do YOUR bits get defined from?), doesn't match well with the way microcontroller programmers think (doesn't map to assembly), and really isn't that much clearer anyway.

(gcc for the TI msp430 (recently "in the news") seems to have such structs defined. And it looks like avr-gcc uses some sort of mixed method for atXmega. In the end, consistency within a particular set of code is more important than the exact syntax you end up using. Being consistent with manufacturer documentation is an added bonus...)

Don & lefty,

Thanks. What I was seeking was more of "Why is it so?" (Julius Sumner-Miller) stuff.

The byte register TIMSK2 has three bit-elements (which you know) but for possible clarity of others reading this forum - I'll continue;-

+---+---+---+---+---+-------+-------+-------+
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---+---+---+---+---+-------+-------+-------+
| - | - | - | - | - |OCIE2B |OCIE2A | TOIE2 |
+---+---+---+---+---+-------+-------+-------+

Going back to my original question of what's happening with;- TIMSK2 = (1<<OCIE2A) ;
Taking the “(1<<OCIE2A)” at face value. It suggests that the “1” will be binary shifted left subject to the value contained in the Bit-field OCIE2A. At least that is my reading of it. So-o-o-o-o, mathematically, using the following maths;-

Using universal mathematical principles.
42 = 16 (equivalent of bit shift of 2) – that is, 4 in binary notation 00000100 being squared becomes 16 or in binary 00010000.
4
1 = 4. This is mathematically correct but, if we use the analogy of a “power” equivalent to a bit-shift left of 1 – WRONG.
4**0 = 1. Mathematically correct. Any non-zero number raised to the power of 0 equals 1.

Using binary principles.
1<<1 means that the value “1” will be changed from B00000001 to a value of “2” or B00000010.
1<<0 means that the value “1” remain “1” – actually pretty useless statement.

Back to the original. If TIMSK2 = (1<<OCIE2A) is set (ie the bit value is 1), my reading of the code suggests that the value one will be bit-wise shifted to the left to produce a value of two (assumption that it is working in byte-value). BUT - HANG ON. It's already set (0x00000010) - so why the heck do it?

So we start off with a TIMSK2 value of 0x00000011, we can see that Bit 1 (OCIE2A) is 1. This implies that we will have s shift of 1. The value “1” the left of the is (I presume) in working memory so appears as 0x00000001. Shifting it left results in 0x00000010 (or 2 in decimal notation.

So now we equate that with the byte field TIMSK2 resulting in the original value of 0x00000011 being replaced with our new value of 2 (0x00000010). A corruption of data.

My feeling is that if I want to set a bit-value in a register it far, far safer to set it with an explicit OR statement. To reset it, use an AND statement with the negative of what you want. The use of “short-hand” code – I'm not convinced it served a purpose. Have I missed something?

(Dave), I had a look at the diagrams. Nice – very nice.
Unfortunately I couldn't find an explanation of how the (1<<OCIE2A) is applied.

73,
Nick

Nick:

I'm with you. I can't help you with why the (1<<OCIE2A) technique is used since I don't use it.

Here's an example of how I handle this sort of thing and how I document it so I will understand what I did a decade later. It's in assembly language, and for a different timer and register, but you will get the idea.

; set up the output mode and part of the waveform generation mode
; TCCR0A
;   0 0 0 0 0 0 1 0
;   | | | | | | | |________ WGM00 ..... CTC mode
;   | | | | | | |__________ WGM01
;   | | | | | |
;   | | | | | |____________ not implemented
;   | | | | |______________ 
;   | | | |  
;   | | | |________________ COM0B0 .... not used with Compare Match "A"
;   | | |__________________ COM0B1
;   | |
;   | |____________________ COM0A0 .... Normal Port Operation, OC0A disconnected
;   |______________________ COM0A1

    ldi     temp, 0b00000010                      ; use CTC mode - important bits: 00xxxx10
    out     TCCR0A, temp

Keep in mind that my background is in education. A professional programmer who is going to reuse the code in different applications would probably do things differently.

Don

A professional programmer who is going to reuse the code in different applications would probably do things differently.

Not if they are smart.

Don,

"I'm with you. I can't help you with why the (1<<OCIE2A) technique is used since I don't use it.". - that's what I have eluded to;- "why is it used?".

Worse still, no-one seems to be able to articulate its structure. ". . . 'cause it works" is not a rational explanation. Although mimicking others might be flattering, it really does little for progressive development.

If we ALL only mimicked originators, the original stone wheel would still be used instead of modern pneumatic tyres - but I digress.

At a language compiler level, applying lexical analysis to the expression "TIMSK2 = ( 1<<OCIE2A)" would follow certain programming rules;-- TIMSK2 - result (result of the expression to the right of the equate symbol).- "=" - assignment separator (and evaluator in the case of operand preceding the assignment separator- eg;- "|=")- (1<<OCIE2) - expression. This is further broken down to;-

  • "1" - a constant.- "<<" - left binary shift- "OCIE2" - variable.At first my thoughts were that the "<<" indicated a direction (either a bit shift or "piping") but the way it works - it's all frack to bont. The direction is all wrong!

The best I can conjure up (not having access to the compiler code) is that the expression is treated as a lexicon of "1<<" followed by a bit address. I possibly need to follow this up with Kerningham and Ritchie on the true structure of the C language perse but my intuition is;-
If a binary shift left (<<) is preceded by either a 0 or 1, use it a a lexicon meaning set or reset (as the case may be) the bit value referred to be the following variable.

Forget the "<<" operand in the normal context of C-programming.

Unless someone can direct me to some definitive reference on how/why it works the way it does, I'd like to close this thread. Using the published/printed references available to me, I see nothing comes close to suggesting a formal discipline in using 1<<var.

It's been a great journey into the inner sanctum of C using the above construct. As a professional programmer, I work to devlop my knowledge beyond the mundane. Having worked with machine code, 2GLs, 3GLs & 4GLs I still marvel at what can be done with a bit of imagination.

Don, thanks for the references. Great value. I will personal-post some suggestions (if I may).

Thanks everyone. I hope I have contributed in some small way to your tool-box of knowledge. You've definitely contributed to mine by allowing me to use the forum as a "sounding board".

Regards,
Nick

@westfw:

to check the current value of the OCIE2A bit, you would have to do Code:

if (TIMSK2 & OCIE2A) ...

I think you mean:

TIMSK2 & (1 << OCIE2A)

#define _pin0 0
#define _pin1 1
#define _pin2 2
...
#define _pin7 7

uint8_t _byte;

_byte = (1 << pin2) | (1 << pin0);

this means that I only want these 2 bits to be high.

if I wanted to force pin 2 to be 0 and it was important that everyone sees it, I could do this...

_byte &= !(1 << pin2);

This is a way to manipulate bits in a variable/register/port, which was one of the advantages for using assembly code.

This here is easy to see what is being done...

_byte |= (1 << pin0) | (1 << pin1) | (0 << pin2) | (1 << pin4) | (1 << pin5);

Notice that everyone can see that I want pin2 to be low, and I don't care about 3,6,7

the way that the code works is...

/Logical Shift Left "1" by 5 places/
(1 << pin5) = (1 << 5)

0000 0001 (0)
0000 0010 (1)
0000 0100 (2)
0000 1000 (3)
0001 0000 (4)
0010 0000 (5)

The advantage of using the name pin5 over the number is that I don't need to know what number it actually is (might not be as obvious in this example of why you would need that). Think about it: Do you actually care what pin OCIE2A is on? And what if you want to compile the code on another Arduino with different pin layouts? Would you want to change all of the pin numbers individually?

_byte |= (1 << pin0) | (1 << pin1) | (0 << pin2) | (1 << pin4) | (1 << pin5);

I don't think you can shift a '0'. Another reason why I don't use this technique.

Don

You can't-

Notice that everyone can see that I want pin2 to be low

It's for the ease of reading the code.

Just curious, if you don't use this technique for manupulating bits, what do you do?

It's just that the data sheet recommends this technique in it's example code.

Just curious, if you don't use this technique for manupulating bits, what do you do?

I start out by writing the whole byte as shown in reply # 7. After that I use the bit setting and clearing instructions to manipulate individual bits whenever I can, otherwise I simply use a straightforward 'AND' or 'OR'. It is my opinion that while the shifting technique may be intuitively obvious to those that have used it for a while, it is not so obvious to those who haven't seen or used it before.

It's just that the data sheet recommends this technique in it's example code.

That's just the programming style of the person who wrote the examples for the datasheet. Data sheets are not known for giving the clearest programming examples, just ones that will work.

Don

@floresta

I don't think you can shift a '0'.

Sure you can: Zero shifted left two bits (or any number of bits) is zero.

@floresta

why I don't use this technique

The issue that I have with that particular statement is that if bit number 2 "just happens" to be a logic "one" before that statement is executed, the register still has a logic "one" at that position after the statement is executed. ORing a "zero" with bit 2 in the register leaves that bit unchanged.

So, here's how I see it:

If you want to make sure one of more bits are set to logic "one" without changing other bits, you use a logical OR. An |= expression with "one" shifted left certain numbers of bits can do it.
If there is only one bit that you want to set, the Arduino bitSet macro (in wiring.h) will perform that operation in a way that is more readable to me.

However...

If you want to make sure one or more bits are reset to logic "zero" without changing other bits, you can use a logical AND with a mask that has values of "one" in bit positions that are not to be changed and values of "zero" in bit positions that you want to reset to "zero." So you could might be able to use an &= expression similar to the one shown.
If you have only one bit position that you want to reset, the Arduino macro bitClear does the deed in a very readable (to me) way.

@InvalidApple

It's for the ease of reading the code.

Well "ease of reading" is in the eye of the beholder.

However...

My objection (regardless of the subjective elegance or lack thereof):
Issues of readability aside, that particular statement doesn't guarantee that bit 2 is zero after executing that statement.

I mean, if you knew that the register was zero beforehand and you want to OR in zero bits here and there, well OK, but...

@floresta

Data sheets are not known for giving the clearest programming examples, just ones that will work.

Indeed. (See Footnote.)

Furthermore---
Maybe they work under certain circumstances that may or may not have been spelled out by the person who wrote the data sheet. Like assuming that the register contained all zeros before that particular statement, (if, indeed, that particular statement was in the data sheet).

Bottom line as I see it:
At the beginning of the program I would use an assignment statement that puts required values in all bit positions.

Later, as the program is running, if I wanted to change certain bit values without changing others, I might use logical OR and logical AND operations.

Regards,

Dave

Footnote:
At a design review (hardware or software) if someone challenges a particular piece of the design, you can't fall back on something like, "Well that's what the Application Note said." At least not if My Boss is there (bless her heart). Believe me. Don't try it!
Been there; done that. (And have the resounding sounds of deprecatory laughter echoing in my little head even now, all these years later.)

It's for the ease of reading the code.

No I think you are missing the point, it is used so that if you want it to be a 1 in bit 2 all you have to do is to change that one bit, you don't have to add the '| (0 << pin2)' bit as well.
As mentioned before oring anything with zero produces no change in the result so in effect it is a NOP instruction. However oring with zero is useful sometimes when you want to change status bits. Sometimes different bits are changed doing this than using a compare instruction.

There seems an awful lot of discussion for something that I thought was pretty straight forward.

a lexicon of "1<<" followed by a bit address

...is correct. "OCIE2A" is indeed a bit address intended for use with the TIMSK2 register. Use the other bitwise | & and ~ operators to control it the way you want; to set/clear the bit location, or the entire register.

It is my opinion that while the shifting technique may be intuitively obvious to those that have used it for a while, it is not so obvious to those who haven't seen or used it before.

Yeah, sure. I've seen a lot of new programmers confused by the whole "1<<CONSTANT" format. wiring.h even includes a macro "bit" to hide it

   TIMSK2 = bit(OCIE2A);

But it's a good idea to get used to it, because it's a very common thing to see in embedded C programs...

some definitive reference on how/why it [1<<CONSTANT] works the way it does

Huh? I don't understand the objections. It works exactly like the shift operator is supposed to work, and the "direction" is fine. Assuming that you number your bits starting at the LSB, (1<<CONSTANT) is 1 shifted left CONSTANT bit positions, which gives you a value that has (only) "bit # CONSTANT" set.

1<<0 == 0b00000001 == 1 == bit 0 set
1<<1 == 0b00000010 == 2 == bit 1 set
1<<5 == 0b00100000 == 32 == bit 5 set

Yes, you have to be careful about when you mean to set the entire register and when you mean to change only specific bits...