inclusive OR used with bitwise left shift MADDENING!

Thread Starter

KLillie

Joined May 31, 2014
137
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
 

Papabravo

Joined Feb 24, 2006
22,082
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.
 

WBahn

Joined Mar 31, 2012
32,823
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
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.
 

Thread Starter

KLillie

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

Rich (BB code):
/* Three PWM Outputs */

// ATtiny85 outputs
const int Red = 0;
const int Green = 1;
const int Blue = 2;

volatile uint8_t* Port[] = {&OCR0A, &OCR0B, &OCR1B};
int Pin[] = {0, 1, 4};

void setup() {
pinMode(Pin[Red], OUTPUT);
pinMode(Pin[Green], OUTPUT);
pinMode(Pin[Blue], OUTPUT);
// Configure counter/timer0 for fast PWM on PB0 and PB1
TCCR0A = 3<<COM0A0 | 3<<COM0B0 | 3<<WGM00;
TCCR0B = 0<<WGM02 | 3<<CS00; // Optional; already set
// Configure counter/timer1 for fast PWM on PB4
GTCCR = 1<<PWM1B | 3<<COM1B0;
TCCR1 = 3<<COM1A0 | 7<<CS10;
}

// Sets colour Red=0 Green=1 Blue=2 to specified intensity 0 (off) to 255 (max)
void SetColour (int colour, int intensity) {
*Port[colour] = 255 - intensity;
}

void loop() {
for (int colour=0; colour<3; colour++) {
SetColour((colour+2) % 3, 0);
for (int i=0; i <= 255; i++) {
SetColour((colour+1) % 3, i);
SetColour(colour, 255-i);
delay(25);
}
}
}
This had an error compiling.
 
Last edited:

Thread Starter

KLillie

Joined May 31, 2014
137
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?

Rich (BB code):
 /*
all my ATtiny85 chips have their 8MHz fuse set
by default they run at 1MHz, so adjust accordingly
this constant is used by delay.h, so make sure it stays above the include
*/
#define F_CPU 8000000

/*
io.h provides lots of handy constants
delay.h provides _delay_ms and _delay_us functions
*/
#include <avr/io.h>
#include <util/delay.h>

/*
program entry-point
*/
void main()
{
  /*
  Starting values for red, green and blue
  */
  uint8_t r=0, g=85, b=170;
 
  /*
  Port B Data Direction Register (controls the mode of all pins within port B)
  DDRB is 8 bits: [unused:unused:DDB5:DDB4:DDB3:DDB2:DDB1:DDB0]
  1<<DDB4: sets bit DDB4 (data-direction, port B, pin 4), which puts PB4 (port B, pin 4) in output mode
  1<<DDB1: sets bit DDB1 (data-direction, port B, pin 1), which puts PB1 (port B, pin 1) in output mode
  1<<DDB0: sets bit DDB0 (data-direction, port B, pin 0), which puts PB0 (port B, pin 0) in output mode
  */
  DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0;

  /*
  Control Register A for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
  TCCR0A is 8 bits: [COM0A1:COM0A0:COM0B1:COM0B0:unused:unused:WGM01:WGM00]
  2<<COM0A0: sets bits COM0A0 and COM0A1, which (in Fast PWM mode) clears OC0A on compare-match, and sets OC0A at BOTTOM
  2<<COM0B0: sets bits COM0B0 and COM0B1, which (in Fast PWM mode) clears OC0B on compare-match, and sets OC0B at BOTTOM
  3<<WGM00: sets bits WGM00 and WGM01, which (when combined with WGM02 from TCCR0B below) enables Fast PWM mode
  */
  TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
 
  /*
  Control Register B for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
  TCCR0B is 8 bits: [FOC0A:FOC0B:unused:unused:WGM02:CS02:CS01:CS00]
  0<<WGM02: bit WGM02 remains clear, which (when combined with WGM00 and WGM01 from TCCR0A above) enables Fast PWM mode
  1<<CS00: sets bits CS01 (leaving CS01 and CS02 clear), which tells Timer/Counter-0 to not use a prescalar
  */
  TCCR0B = 0<<WGM02 | 1<<CS00;
 
  /*
  Control Register for Timer/Counter-1 (Timer/Counter-1 is configured with just one register: this one)
  TCCR1 is 8 bits: [CTC1:PWM1A:COM1A1:COM1A0:CS13:CS12:CS11:CS10]
  0<<PWM1A: bit PWM1A remains clear, which prevents Timer/Counter-1 from using pin OC1A (which is shared with OC0B)
  0<<COM1A0: bits COM1A0 and COM1A1 remain clear, which also prevents Timer/Counter-1 from using pin OC1A (see PWM1A above)
  1<<CS10: sets bit CS11 which tells Timer/Counter-1  to not use a prescalar
  */
  TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
 
  /*
  General Control Register for Timer/Counter-1 (this is for Timer/Counter-1 and is a poorly named register)
  GTCCR is 8 bits: [TSM:PWM1B:COM1B1:COM1B0:FOC1B:FOC1A:PSR1:PSR0]
  1<<PWM1B: sets bit PWM1B which enables the use of OC1B (since we disabled using OC1A in TCCR1)
  2<<COM1B0: sets bit COM1B1 and leaves COM1B0 clear, which (when in PWM mode) clears OC1B on compare-match, and sets at BOTTOM
  */
  GTCCR = 1<<PWM1B | 2<<COM1B0;
 
  /*
  loop forever
  */
  for (;;)
  {
    /*
    increment and boundary-check each color
    */
    if (++r>255) r=0;
    if (++g>255) g=0;
    if (++b>255) b=0;
   
    /*
    update compare registers with red, green and blue values
    */
    OCR0A = r;
    OCR0B = g;
    OCR1B = b;
   
    /*
    brief pause so we can perceive what is happening
    */
    _delay_ms(10);
  }
}
 

Thread Starter

KLillie

Joined May 31, 2014
137
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.
 

Papabravo

Joined Feb 24, 2006
22,082
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 |
 

Papabravo

Joined Feb 24, 2006
22,082
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.
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:

WBahn

Joined Mar 31, 2012
32,823
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?

Rich (BB code):
 /*
/*
io.h provides lots of handy constants
delay.h provides _delay_ms and _delay_us functions
*/
#include <avr/io.h>
#include <util/delay.h>
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) );
 

Thread Starter

KLillie

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

Thread Starter

KLillie

Joined May 31, 2014
137
@ 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.
Rich (BB code):
/*
all my ATtiny85 chips have their 8MHz fuse set
by default they run at 1MHz, so adjust accordingly
this constant is used by delay.h, so make sure it stays above the include
*/
#define F_CPU 8000000

/*
io.h provides lots of handy constants
delay.h provides _delay_ms and _delay_us functions
*/
#include <avr/io.h>
#include <util/delay.h>

/*
program entry-point
*/
int main()
{
  /*
  Starting values for red, green and blue
  */
  uint8_t r=0, g=85, b=170;
  /*
  Port B Data Direction Register (controls the mode of all pins within port B)
  DDRB is 8 bits: [unused:unused:DDB5:DDB4:DDB3:DDB2:DDB1:DDB0]
  1<<DDB4: sets bit DDB4 (data-direction, port B, pin 4), which puts PB4 (port B, pin 4) in output mode
  1<<DDB1: sets bit DDB1 (data-direction, port B, pin 1), which puts PB1 (port B, pin 1) in output mode
  1<<DDB0: sets bit DDB0 (data-direction, port B, pin 0), which puts PB0 (port B, pin 0) in output mode
  */
  DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0;

  /*
  Control Register A for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
  TCCR0A is 8 bits: [COM0A1:COM0A0:COM0B1:COM0B0:unused:unused:WGM01:WGM00]
  2<<COM0A0: sets bits COM0A0 and COM0A1, which (in Fast PWM mode) clears OC0A on compare-match, and sets OC0A at BOTTOM
  2<<COM0B0: sets bits COM0B0 and COM0B1, which (in Fast PWM mode) clears OC0B on compare-match, and sets OC0B at BOTTOM
  3<<WGM00: sets bits WGM00 and WGM01, which (when combined with WGM02 from TCCR0B below) enables Fast PWM mode
  */
  TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
  /*
  Control Register B for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
  TCCR0B is 8 bits: [FOC0A:FOC0B:unused:unused:WGM02:CS02:CS01:CS00]
  0<<WGM02: bit WGM02 remains clear, which (when combined with WGM00 and WGM01 from TCCR0A above) enables Fast PWM mode
  1<<CS00: sets bits CS01 (leaving CS01 and CS02 clear), which tells Timer/Counter-0 to not use a prescalar
  */
  TCCR0B = 0<<WGM02 | 1<<CS00;
  /*
  Control Register for Timer/Counter-1 (Timer/Counter-1 is configured with just one register: this one)
  TCCR1 is 8 bits: [CTC1:PWM1A:COM1A1:COM1A0:CS13:CS12:CS11:CS10]
  0<<PWM1A: bit PWM1A remains clear, which prevents Timer/Counter-1 from using pin OC1A (which is shared with OC0B)
  0<<COM1A0: bits COM1A0 and COM1A1 remain clear, which also prevents Timer/Counter-1 from using pin OC1A (see PWM1A above)
  1<<CS10: sets bit CS11 which tells Timer/Counter-1  to not use a prescalar
  */
  TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
  /*
  General Control Register for Timer/Counter-1 (this is for Timer/Counter-1 and is a poorly named register)
  GTCCR is 8 bits: [TSM:PWM1B:COM1B1:COM1B0:FOC1B:FOC1A:PSR1:PSR0]
  1<<PWM1B: sets bit PWM1B which enables the use of OC1B (since we disabled using OC1A in TCCR1)
  2<<COM1B0: sets bit COM1B1 and leaves COM1B0 clear, which (when in PWM mode) clears OC1B on compare-match, and sets at BOTTOM
  */
  GTCCR = 1<<PWM1B | 2<<COM1B0;
  /*
  loop forever
  */
  for (;;)
  {
  /*
  increment and (boundary-check each color(deleted)values rollover)
  */
  ++r;
  ++g;
  ++b;
 
  /*
  update compare registers with red, green and blue values
  */
  OCR0A = r;
  OCR0B = g;
  OCR1B = b;
 
  /*
  brief pause so we can perceive what is happening
  */
  _delay_ms(10);
  }
}
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
Rich (BB code):
  #define F_CPU 8000000


  #include <avr/io.h>
  #include <util/delay.h>

  
  byte r=0;
  byte g=85;
  byte b=170;
    
  void setup()
  {
  
  DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0;

  TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
  
  TCCR0B = 0<<WGM02 | 1<<CS00;
  
  TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
  
  GTCCR = 1<<PWM1B | 2<<COM1B0;
  
  /*
  loop forever
  */
   }
     void loop()
  
  {
  /*
  increment and boundary-check each color
  */
  ++r;
  ++g;
  ++b;
  
  /*
  update compare registers with red, green and blue values
  */
  OCR0A = r;
  OCR0B = g;
  OCR1B = b;
  
  /*
  brief pause so we can perceive what is happening
  */
  _delay_ms(10);
  }
 
Last edited:
Top