# inclusive OR used with bitwise left shift MADDENING!

Discussion in 'Programmer's Corner' started by KLillie, Mar 28, 2015.

1. ### KLillie Thread Starter Member

May 31, 2014
126
14
Could anybody explain to me what is going on in this code?
TCCR0A = 3<<COM0A0 | 3<<COM0B0 | 3<<WGM00;
This is from a RGB led program for the attiny85. The author is trying to create 3 pwms. This an 8 bit timer register where bits are being set. I found other examples of people setting bits this way, but I don't understand. Could someone rewrite this to make it more understandable or try to explain what this code does? Thanks

2. ### Papabravo Expert

Feb 24, 2006
11,124
2,171
In order to under stand what is going on you have to know the values of the constants. They are no doubt located in a #define statement somewhere. For example if COM0A0 is 6 and COM0B0 is 4 and WGM00 is 2, then the expression would read
TCCR0A = 3 << 6 | 3 << 4 | 3 << 2

3 << 6 = 0b11000000 = 0xC0
3 << 4 = 0b00110000 = 0x30
3 << 2 = 0b00001100 = 0x0C

If you incusive OR the three constants together you get 0b11111100 = 0xFC

The symbols refer to the location of the respective bit fields within the register.

3. ### WBahn Moderator

Mar 31, 2012
20,221
5,747
Let's take it in three chunks.

The expression (x)|(y)|(z) performs an exclusive OR on the bit patterns that represent x, y, and z. So the each bit in the final result is a 1 if that bit is a 1 in ANY of the representations.

The expression (a<<b) left shifts the bit pattern in 'a' by the number of positions given by 'b'.

The constant '3' has the lower two bits set since this is the representation for the number three in two's complement (which is almost certainly the representation used).

My guess is that the symbolic constants COM0A0, COM0B0, and WGM00 are equal to the number of bits from the right that the corresponding two-bit field is located within the TCCR0A register.

So, combining these, what you are doing is configuring three different bit fields that are housed within a single variable by taking the value for each bit field (which happen to all be '3' in this case), left shifting them by the amount needed to position them properly within the variable (as controlled by the symbolic constants), and then ORing them together to combine them into a single value.

4. ### KLillie Thread Starter Member

May 31, 2014
126
14
Here's the code:
I still don't know the value of the constants.

Code ( (Unknown Language)):
1.
2. /* Three PWM Outputs */
3.
4. // ATtiny85 outputs
5. const int Red = 0;
6. const int Green = 1;
7. const int Blue = 2;
8.
9. volatile uint8_t* Port[] = {&OCR0A, &OCR0B, &OCR1B};
10. int Pin[] = {0, 1, 4};
11.
12. void setup() {
13. pinMode(Pin[Red], OUTPUT);
14. pinMode(Pin[Green], OUTPUT);
15. pinMode(Pin[Blue], OUTPUT);
16. // Configure counter/timer0 for fast PWM on PB0 and PB1
17. TCCR0A = 3<<COM0A0 | 3<<COM0B0 | 3<<WGM00;
18. TCCR0B = 0<<WGM02 | 3<<CS00; // Optional; already set
19. // Configure counter/timer1 for fast PWM on PB4
20. GTCCR = 1<<PWM1B | 3<<COM1B0;
21. TCCR1 = 3<<COM1A0 | 7<<CS10;
22. }
23.
24. // Sets colour Red=0 Green=1 Blue=2 to specified intensity 0 (off) to 255 (max)
25. void SetColour (int colour, int intensity) {
26. *Port[colour] = 255 - intensity;
27. }
28.
29. void loop() {
30. for (int colour=0; colour<3; colour++) {
31. SetColour((colour+2) % 3, 0);
32. for (int i=0; i <= 255; i++) {
33. SetColour((colour+1) % 3, i);
34. SetColour(colour, 255-i);
35. delay(25);
36. }
37. }
38. }
39.

Last edited: Mar 28, 2015
5. ### KLillie Thread Starter Member

May 31, 2014
126
14
This was more code from a different website that does not compile either. (Maybe by the same guy?) But he uses that same convention. I Arduino IDE gave me no clues as why this didn't compile. What's the deal?

DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0;
Is the shifting done first then the "ORing" from left to right and does it matter if we know what are in these bits?

Code ( (Unknown Language)):
1.  /*
2. all my ATtiny85 chips have their 8MHz fuse set
3. by default they run at 1MHz, so adjust accordingly
4. this constant is used by delay.h, so make sure it stays above the include
5. */
6. #define F_CPU 8000000
7.
8. /*
9. io.h provides lots of handy constants
10. delay.h provides _delay_ms and _delay_us functions
11. */
12. #include <avr/io.h>
13. #include <util/delay.h>
14.
15. /*
16. program entry-point
17. */
18. void main()
19. {
20.   /*
21.   Starting values for red, green and blue
22.   */
23.   uint8_t r=0, g=85, b=170;
24.
25.   /*
26.   Port B Data Direction Register (controls the mode of all pins within port B)
27.   DDRB is 8 bits: [unused:unused:DDB5:DDB4:DDB3:DDB2:DDB1:DDB0]
28.   1<<DDB4: sets bit DDB4 (data-direction, port B, pin 4), which puts PB4 (port B, pin 4) in output mode
29.   1<<DDB1: sets bit DDB1 (data-direction, port B, pin 1), which puts PB1 (port B, pin 1) in output mode
30.   1<<DDB0: sets bit DDB0 (data-direction, port B, pin 0), which puts PB0 (port B, pin 0) in output mode
31.   */
32.   DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0;
33.
34.   /*
35.   Control Register A for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
36.   TCCR0A is 8 bits: [COM0A1:COM0A0:COM0B1:COM0B0:unused:unused:WGM01:WGM00]
37.   2<<COM0A0: sets bits COM0A0 and COM0A1, which (in Fast PWM mode) clears OC0A on compare-match, and sets OC0A at BOTTOM
38.   2<<COM0B0: sets bits COM0B0 and COM0B1, which (in Fast PWM mode) clears OC0B on compare-match, and sets OC0B at BOTTOM
39.   3<<WGM00: sets bits WGM00 and WGM01, which (when combined with WGM02 from TCCR0B below) enables Fast PWM mode
40.   */
41.   TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
42.
43.   /*
44.   Control Register B for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
45.   TCCR0B is 8 bits: [FOC0A:FOC0B:unused:unused:WGM02:CS02:CS01:CS00]
46.   0<<WGM02: bit WGM02 remains clear, which (when combined with WGM00 and WGM01 from TCCR0A above) enables Fast PWM mode
47.   1<<CS00: sets bits CS01 (leaving CS01 and CS02 clear), which tells Timer/Counter-0 to not use a prescalar
48.   */
49.   TCCR0B = 0<<WGM02 | 1<<CS00;
50.
51.   /*
52.   Control Register for Timer/Counter-1 (Timer/Counter-1 is configured with just one register: this one)
53.   TCCR1 is 8 bits: [CTC1:PWM1A:COM1A1:COM1A0:CS13:CS12:CS11:CS10]
54.   0<<PWM1A: bit PWM1A remains clear, which prevents Timer/Counter-1 from using pin OC1A (which is shared with OC0B)
55.   0<<COM1A0: bits COM1A0 and COM1A1 remain clear, which also prevents Timer/Counter-1 from using pin OC1A (see PWM1A above)
56.   1<<CS10: sets bit CS11 which tells Timer/Counter-1  to not use a prescalar
57.   */
58.   TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
59.
60.   /*
61.   General Control Register for Timer/Counter-1 (this is for Timer/Counter-1 and is a poorly named register)
62.   GTCCR is 8 bits: [TSM:PWM1B:COM1B1:COM1B0:FOC1B:FOC1A:PSR1:PSR0]
63.   1<<PWM1B: sets bit PWM1B which enables the use of OC1B (since we disabled using OC1A in TCCR1)
64.   2<<COM1B0: sets bit COM1B1 and leaves COM1B0 clear, which (when in PWM mode) clears OC1B on compare-match, and sets at BOTTOM
65.   */
66.   GTCCR = 1<<PWM1B | 2<<COM1B0;
67.
68.   /*
69.   loop forever
70.   */
71.   for (;;)
72.   {
73.     /*
74.     increment and boundary-check each color
75.     */
76.     if (++r>255) r=0;
77.     if (++g>255) g=0;
78.     if (++b>255) b=0;
79.
80.     /*
81.     update compare registers with red, green and blue values
82.     */
83.     OCR0A = r;
84.     OCR0B = g;
85.     OCR1B = b;
86.
87.     /*
88.     brief pause so we can perceive what is happening
89.     */
90.     _delay_ms(10);
91.   }
92. }
93.

6. ### KLillie Thread Starter Member

May 31, 2014
126
14
WBahn said,
"My guess is that the symbolic constants COM0A0, COM0B0, and WGM00 are equal to the number of bits from the right that the corresponding two-bit field is located within the TCCR0A register."

Could you rephrase that? I do not understand.

7. ### Papabravo Expert

Feb 24, 2006
11,124
2,171
The 8 bit register consists of at least 3 bit fields. The number of shifts is equal to the bit number of the least significant bit of the bit field in the register. The idea is for the compiler to compute a single 8 bit constant by OR'in three bit fields, properly aligned together. Look at the precedence of the operators << and |

8. ### Papabravo Expert

Feb 24, 2006
11,124
2,171
That is correct, those constants locate the bit fields in the register. Consult the datasheet for details.

COM0A1:COM0A0 are in bits 7 & 6
COM0B1:COM0B0 are in bits 5 & 4
WGM01;WGM00 are in bits 1 & 0

Bits 3 & 2 are unused and should be written as 0's

So the original constant to be written to TCCR0A should evaluate to 0xF3

Last edited: Mar 28, 2015
9. ### WBahn Moderator

Mar 31, 2012
20,221
5,747
Read the comments in the code you are using. Do you think that, perhaps, the file avr/io.h might possibly contain some "handy constants"?

You need to also look at the precedence of operators for the language you are using. In C, bit shift operations take precedence over logical operations, which take precedence over assignment operations. so

DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0;

is evaluated as

DDRB = ( (1<<DDB4) | (1<<DDB1) | (1<<DDB0) );

10. ### KLillie Thread Starter Member

May 31, 2014
126
14
Took me a while but I finally figured it out AND why the second code didn't compile. Thanks for your responses!

11. ### panic mode Senior Member

Oct 10, 2011
1,420
347
thank you taking time to poste detailed description of your solution, that was very helpful

12. ### KLillie Thread Starter Member

May 31, 2014
126
14
@ Panic mode...sarcasm will get you nowhere! ...I take that back cuz' I just can't stands it! It had something to do with this.
void main()
I was trying to use Atmel Studio 6 for this because at the time it looked like C and not the pseudo-code of the Arduino IDE.
Well that line is a mix of them.
Arduino Ide requires void setup() and void loop(). C is looking for int main(). I'll post my re-written code for the Arduino IDE.
Code ( (Unknown Language)):
1.
2.
3. /*
4. all my ATtiny85 chips have their 8MHz fuse set
5. by default they run at 1MHz, so adjust accordingly
6. this constant is used by delay.h, so make sure it stays above the include
7. */
8. #define F_CPU 8000000
9.
10. /*
11. io.h provides lots of handy constants
12. delay.h provides _delay_ms and _delay_us functions
13. */
14. #include <avr/io.h>
15. #include <util/delay.h>
16.
17. /*
18. program entry-point
19. */
20. int main()
21. {
22.   /*
23.   Starting values for red, green and blue
24.   */
25.   uint8_t r=0, g=85, b=170;
26.   /*
27.   Port B Data Direction Register (controls the mode of all pins within port B)
28.   DDRB is 8 bits: [unused:unused:DDB5:DDB4:DDB3:DDB2:DDB1:DDB0]
29.   1<<DDB4: sets bit DDB4 (data-direction, port B, pin 4), which puts PB4 (port B, pin 4) in output mode
30.   1<<DDB1: sets bit DDB1 (data-direction, port B, pin 1), which puts PB1 (port B, pin 1) in output mode
31.   1<<DDB0: sets bit DDB0 (data-direction, port B, pin 0), which puts PB0 (port B, pin 0) in output mode
32.   */
33.   DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0;
34.
35.   /*
36.   Control Register A for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
37.   TCCR0A is 8 bits: [COM0A1:COM0A0:COM0B1:COM0B0:unused:unused:WGM01:WGM00]
38.   2<<COM0A0: sets bits COM0A0 and COM0A1, which (in Fast PWM mode) clears OC0A on compare-match, and sets OC0A at BOTTOM
39.   2<<COM0B0: sets bits COM0B0 and COM0B1, which (in Fast PWM mode) clears OC0B on compare-match, and sets OC0B at BOTTOM
40.   3<<WGM00: sets bits WGM00 and WGM01, which (when combined with WGM02 from TCCR0B below) enables Fast PWM mode
41.   */
42.   TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
43.   /*
44.   Control Register B for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
45.   TCCR0B is 8 bits: [FOC0A:FOC0B:unused:unused:WGM02:CS02:CS01:CS00]
46.   0<<WGM02: bit WGM02 remains clear, which (when combined with WGM00 and WGM01 from TCCR0A above) enables Fast PWM mode
47.   1<<CS00: sets bits CS01 (leaving CS01 and CS02 clear), which tells Timer/Counter-0 to not use a prescalar
48.   */
49.   TCCR0B = 0<<WGM02 | 1<<CS00;
50.   /*
51.   Control Register for Timer/Counter-1 (Timer/Counter-1 is configured with just one register: this one)
52.   TCCR1 is 8 bits: [CTC1:PWM1A:COM1A1:COM1A0:CS13:CS12:CS11:CS10]
53.   0<<PWM1A: bit PWM1A remains clear, which prevents Timer/Counter-1 from using pin OC1A (which is shared with OC0B)
54.   0<<COM1A0: bits COM1A0 and COM1A1 remain clear, which also prevents Timer/Counter-1 from using pin OC1A (see PWM1A above)
55.   1<<CS10: sets bit CS11 which tells Timer/Counter-1  to not use a prescalar
56.   */
57.   TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
58.   /*
59.   General Control Register for Timer/Counter-1 (this is for Timer/Counter-1 and is a poorly named register)
60.   GTCCR is 8 bits: [TSM:PWM1B:COM1B1:COM1B0:FOC1B:FOC1A:PSR1:PSR0]
61.   1<<PWM1B: sets bit PWM1B which enables the use of OC1B (since we disabled using OC1A in TCCR1)
62.   2<<COM1B0: sets bit COM1B1 and leaves COM1B0 clear, which (when in PWM mode) clears OC1B on compare-match, and sets at BOTTOM
63.   */
64.   GTCCR = 1<<PWM1B | 2<<COM1B0;
65.   /*
66.   loop forever
67.   */
68.   for (;;)
69.   {
70.   /*
71.   increment and (boundary-check each color(deleted)values rollover)
72.   */
73.   ++r;
74.   ++g;
75.   ++b;
76.
77.   /*
78.   update compare registers with red, green and blue values
79.   */
80.   OCR0A = r;
81.   OCR0B = g;
82.   OCR1B = b;
83.
84.   /*
85.   brief pause so we can perceive what is happening
86.   */
87.   _delay_ms(10);
88.   }
89. }
90.
I don't know if this will work, but it did compile.
I re-wrote it slightly for the common Arduino coder. The variables had to be declared before the prototypes to be global. The other program was able to declare them in the main program. The Arduino code is almost four times as big when compiled
Code ( (Unknown Language)):
1.
2.
3.   #define F_CPU 8000000
4.
5.
6.   #include <avr/io.h>
7.   #include <util/delay.h>
8.
9.
10.   byte r=0;
11.   byte g=85;
12.   byte b=170;
13.
14.   void setup()
15.   {
16.
17.   DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0;
18.
19.   TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
20.
21.   TCCR0B = 0<<WGM02 | 1<<CS00;
22.
23.   TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
24.
25.   GTCCR = 1<<PWM1B | 2<<COM1B0;
26.
27.   /*
28.   loop forever
29.   */
30.    }
31.      void loop()
32.
33.   {
34.   /*
35.   increment and boundary-check each color
36.   */
37.   ++r;
38.   ++g;
39.   ++b;
40.
41.   /*
42.   update compare registers with red, green and blue values
43.   */
44.   OCR0A = r;
45.   OCR0B = g;
46.   OCR1B = b;
47.
48.   /*
49.   brief pause so we can perceive what is happening
50.   */
51.   _delay_ms(10);
52.   }
53.

Last edited: Mar 30, 2015
13. ### KLillie Thread Starter Member

May 31, 2014
126
14
Code verified! It works.