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
    10,165
    1,797
    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
    17,777
    4,805
    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.  
    This had an error compiling.
     
    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
    10,165
    1,797
    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
    10,165
    1,797
    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
    17,777
    4,805
    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,321
    304
    thank you taking time to poste detailed description of your solution, that was very helpful o_O
     
  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.
     
Loading...