Help understanding setting bits for registers

I’m just looking for a little education here. I have several programs that use something like this to set register bits (actually, these bits in particular on an ATTiny85).

CLKPR = 1<<CLKPCE | 0<<CLKPS3 | 0<<CLKPS2 | 0<<CLKPS1 | 0<<CLKPS0;
CLKPR = 0<<CLKPCE | 1<<CLKPS1;

I’m trying to learn how to use timer/counter1 to manipulate PWM frequency so I can get whatever frequency I want. From the datasheet, these particular bits are part of the register CLKPR and what I am doing is setting the CLKPS1 bit (to get a prescaler of 4).

My question is can I use something like this

CLKPR = B10000000;
CLKPR = B00000010;

to achieve the same thing. If so, is there a particular name for this type of manipulation (like “bit shifting” in the above code)?

I’m thinking I can clean up my code if I can set all bits at once instead of having to set each one individually.

Yes, you can do it that way. You can also use hexidecimal (or base 10) numbers - however, these make your code less readable and less maintainable, because now you don’t know which bit means which, and have to look up which bit is which in the register, and then crossreference that with the description of that bit.

Note that the compiler is smart enough to optimize CLKPR = 1<<CLKPCE | 0<<CLKPS3 | 0<<CLKPS2 | 0<<CLKPS1 | 0<<CLKPS0; into a single assignment of the appropriate value (all the values are constants known at compiletime).

Note also that the cases where you’re shifting 0’s around are superfluous. CLKPR = 1<<CLKPCE | 0<<CLKPS3 | 0<<CLKPS2 | 0<<CLKPS1 | 0<<CLKPS0; is the same as CLKPR = 1<<CLKPCE;

You are changing the wrong register to adjust PWM frequency. What you are adjusting is the frequency for the entire processor (including PWM). To adjust just the PWM frequency, look at TCCR1 or TCCR0B. (for timer1 or timer0 respectively. Depending on what core you use, either timer may be the one used for millis. I use timer0 for millis on my core. Other attiny85 cores may use timer1. You should avoid reconfiguring whichever one was used for millis).

The following diagram has depicted the role of CLKPR (system Clock Prescaler Register) and and TC1 (Timer/Counter1) Prescaler Register in respect of dividing the system clock for the operating clock of the processor and TC1.

Here is a chart you may find useful from the Arduino Cookbook by Michael Margolis.

Timer0 (pins 5 & 6)

TCCROB value           Prescale factor           Frequency

32(1)                       1                               62500
33(2)                       8                               7812.5
34                           64                              976.5625
35                           256                            244.140625
36                           1024                          61.03515625

Tell me if you want timer1.

Thank you all for the replies, however I must be missing something. After DrAzzy pointed out that I was trying to manipulate the system clock, I started investigating his suggestion to use TCCR1 (timer1). According to the datasheet page 88 Table 12-3 shows that I should be able to get a 90kHz PWM from OC1A (PB1) or OC1B (PB4).

So, using DrAzzy’s core with the internal clock set to 8MHz and the timer1 clock set to CPU, I burned this bootloader and then loaded this sketch

void setup() {
  OCR1C = 0xB1; // set the top compare to 177, as per the table 12-3
  TCCR1 = B00000011;  // set the CS1 bits per the table  
  pinMode(1, OUTPUT);
  pinMode(0, OUTPUT);
  pinMode(4, OUTPUT);
}

void loop() {
  analogWrite(1, 127);
  analogWrite(0, 127);
  analogWrite(4, 127);
}

I get a 500Hz PWM signal on PB0 and PB1 and I get 11.6kHz on PB4. This clearly wasn’t right, so I changed timer1 to the 64MHz option and burned the bootloader. Running the same script, I get the same results. I did a little more searching and found this thread https://forum.arduino.cc/index.php?topic=461062.0 in which someone else had a similar problem. I assimilated the bits from that code that I was missing (excluding the dead time stuff because I didn’t need that) and tried again.

void setup() {
  OCR1C = 0xB1; // set the top compare to 177
  TCCR1 = B11100011;  // settings to get proper PWM frequency on PB1  
  GTCCR = 1<<PWM1B | 1<<COM1B1;
  pinMode(1, OUTPUT);
  pinMode(0, OUTPUT);
  pinMode(4, OUTPUT);
}

void loop() {
  analogWrite(1, 127);
  analogWrite(0, 127);
  analogWrite(4, 127);
}

I still get the same result. All I need is a 90kHz PWM signal on PB1. This is driving me crazy (it was already a short enough trip).

Run this function if you want 62500H on Timer0:

void set62500HTimer0() {
  TCCROB = (TCCROB & B11111000)   | 1;
}

Run this function if you want 3906H on Timer1:

void set3906HTimer1() {
  TCCRO1B = (TCCRO1B & B11111000)   | 1;
}

Those were the closest values I could get on the timers. Just ask if you want a different value.

He is using timer1 on a t85. He's doing something wrong above but unsure what. Let's see if I can get home fast enough to habe time to sort it out tonight

OK, I know I’m overlooking something, but I did manage to get a ~91.6kHz PWM signal on PB4 (wish I could get it on PB1). DrAzzy, I changed the clock to the “16MHz (PLL)” and reloaded the bootloader. I then noticed I was getting different speeds so I played around with CS1 bits until I got it close. Here’s the code, but I still don’t understand the “why”. PB0 and PB1 are steady at 1kHz regardless of what value CS1 is.

void setup() {
//  This gives ~91.6kHz on PB4
  OCR1C = 0xB1; // set the top compare to 177
  TCCR1 = B11000001;  // settings to get proper PWM frequency on PB1  
  GTCCR = 1<<PWM1B | 2<<COM1B0;
  pinMode(1, OUTPUT);
  pinMode(0, OUTPUT);
  pinMode(4, OUTPUT);
}

void loop() {
  analogWrite(1, 127);
  analogWrite(0, 127);
  analogWrite(4, 127);
}

I still would like to know what is going on here, but I can work with it for now.