# ATTiny85 PWM frequency selection

**URL:** <https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785>\
**Category:** Programming\
**Created:** [May 12, 2011, 6:27am UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785 "2011-05-12T06:27:14Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![system](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/system/32/1140315_2.png) [@system](https://forum.arduino.cc/u/system)\
**Post date:** [May 12, 2011, 6:27am UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/1 "2011-05-12T06:27:14Z")

</div>

A bit of background:  
I'm looking to control PWM computer cooling fans directly from an ATTiny85, the fans want a ~15-25khz PWM signal. The currant involved in minimal.

At default settings with Coding Badly's excellent arduino port I got 500hz from pin0 and 1khz from pin1.  
If I use " TCCR0B = TCCR0B & 0b11111101 | 0x01;" from the Arduino PWM frequency howto, I can get 1khz from pin0 and 2khz from pin1.

However from reading about AVRs in general it appears that far higher is possible, just not doable through the arduino environment.  
Is this correct? Am I totally out to lunch?

Any help/advice would be greatly appreciated.  
(Sidenote: The 328p's ~32khz output works, but is horrendously inefficient in controlling fans, they don't like it much)

---

<div class="post-metadata">

**Author:** ![Coding\_Badly](https://avatars.discourse-cdn.com/v4/letter/c/f14d63/32.png) [@Coding\_Badly](https://forum.arduino.cc/u/Coding_Badly)\
**Post date:** [May 13, 2011, 8:16am UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/2 "2011-05-13T08:16:58Z")

</div>

> Bobnova:  
> I'm looking to control PWM computer cooling fans directly from an ATTiny85, the fans want a ~15-25khz PWM signal.

Sounds good.

> The currant involved in minimal.

How minimal? It's extremely rare to find a motor that can be driven directly from a microprocessor. Or do the cooling fans have a "control line" separate from the power?

> At default settings with Coding Badly's excellent arduino port

Thanks! 😃

> I got 500hz from pin0 and 1khz from pin1.

Are you running the processor at 16 MHz?

> However from reading about AVRs in general it appears that far higher is possible

The ATtiny85 is capable of generating a 64 MHz PWM signal. So "far higher" is a good description.

> just not doable through the arduino environment.

The Tiny Core includes a "veneer" that makes changing the timers a bit easier. Confirm the processor speed and I'll try to help.

---

<div class="post-metadata">

**Author:** ![MarkT](https://avatars.discourse-cdn.com/v4/letter/m/c89c15/32.png) [@MarkT](https://forum.arduino.cc/u/MarkT)\
**Post date:** [May 13, 2011, 10:50am UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/3 "2011-05-13T10:50:53Z")

</div>

> If I use " TCCR0B = TCCR0B & 0b11111101 | 0x01;" from the Arduino PWM frequency howto, I can get 1khz from pin0 and 2khz from pin1.

I don't know if the ATTiny85 is similar to the 328, but if so that line needs to be:

```arduino
TCCR0B = TCCR0B & 0b11111000 | 0b001 ; // set to divide-by-1 prescale

```

(The 328 timer prescaler fields are 3 bits wide)

---

<div class="post-metadata">

**Author:** ![system](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/system/32/1140315_2.png) [@system](https://forum.arduino.cc/u/system)\
**Post date:** [May 13, 2011, 1:54pm UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/4 "2011-05-13T13:54:37Z")

</div>

Minimal currant like \<=15ma, the fans are four pin type things: +12v, ground, tach output (you pull it high, it grounds that wire twice per revolution) and PWM input.  
The PWM input goes to a controller on the fan circuitboard that figures out when to switch the mosfets to get the fan to run at the speed you selected via PWM. It's a pretty cool setup, though they cost more than the three pin non-PWM fans.

Processor speed wise I've tried both 1mhz and 8mhz, I don't have any spare 16mhz crystals/resonators. I should get some.

I'll try that line in my attiny85 and report back in with what happens.

Thanks for the input!

(Sidenote: I got 15.4khz PWM out of a 328p by using the internal oscillator at 8mhz and running the timer at full speed, but attiny85's are cheaper and easier to find)

EDIT:  
That worked beautifully! I now have a pair of 15.6khz PWM outputs from my attiny85.  
Thank you very much!

---

<div class="post-metadata">

**Author:** ![system](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/system/32/1140315_2.png) [@system](https://forum.arduino.cc/u/system)\
**Post date:** [June 21, 2012, 12:08pm UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/5 "2012-06-21T12:08:47Z")

</div>

> Bobnova:  
> EDIT:  
> That worked beautifully! I now have a pair of 15.6khz PWM outputs from my attiny85.  
> Thank you very much!

how did you get it to work ? 🙂

---

<div class="post-metadata">

**Author:** ![HermannSW](https://avatars.discourse-cdn.com/v4/letter/h/9e8a1a/32.png) [@HermannSW](https://forum.arduino.cc/u/HermannSW)\
**Post date:** [January 10, 2017, 4:17pm UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/6 "2017-01-10T16:17:00Z")

</div>

> how did you get it to work ? 🙂

Adding the "TCCR0B = TCCR0B & 0b11111000 | 0b001 ;" line to Setup() results in 32.35kHz on [Digispark ATtiny85 module](https://forum.arduino.cc/index.php?topic=442087.msg3076335#msg3076335) (pin 0 as well as pin 1):

> The ATtiny85 is capable of generating a 64 MHz PWM signal. So "far higher" is a good description.

How to configure ATtiny85 for MHz PWM frequencies?

---

<div class="post-metadata">

**Author:** ![HermannSW](https://avatars.discourse-cdn.com/v4/letter/h/9e8a1a/32.png) [@HermannSW](https://forum.arduino.cc/u/HermannSW)\
**Post date:** [January 11, 2017, 6:05pm UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/7 "2017-01-11T18:05:32Z")

</div>

Found "Setting High Speed PWM on ATTiny85":

> <https://stackoverflow.com/questions/21654618/setting-high-speed-pwm-on-attiny85>

Adapted for Arduino IDE I measured up to 676.7kHz with "OCR1C = 123;".

```arduino
123*676.7
83234.1
127*648
82296
141*590.8
83302.8
159*524.4
83379.6

```

This is from comment of sketch below, not sure why I measured 1.3 times as much:

```arduino
    // Set PWM TOP value - counter will count and reset
    //  after reaching this value
    //          OCR1C
    // 400Khz  159     
    // 450khz  141
    // 500khz  127

```

```arduino
400*159
63600
450*141
63450
127*500
63500

```

Hermann.

```arduino
//#include <avr/io.h>
//#include <avr/interrupt.h>

void setup()
{
    PORTB = 0;      //Reset values on port B

    // After setting up the timer counter, 
    // set the direction of the ports to output
    DDRB |= (1<<PB1) | (1<<PB0); // Set the direction of PB1 to an output

    // PLLCSR - PLL control and status register:
    // PLL is a clock multiplier - multiplies system    8Mhz by 8 to 64Mhz
    // PLL is enabled when:PLLE bit is enabled, 
    // CKSEL fuse is programmed to 0001.  This clock is 
    //  switched off in sleep modes!
    PLLCSR |= (1<<PLLE);    // PLL enable

    // Wait until the PLOCK bit is enabled 
    //  before allowing the PCK to be enabled
    // WaitForPLOCK();
    // unsigned int i = 0;

    while ((PLLCSR & (1<<PLOCK)) == 0x00)
    {
        // Do nothing until plock bit is set
    }

    PLLCSR |= (1<<PCKE); // Enable asynchronous mode, sets PWM clock source

    TCCR1 =
            (1<<CTC1) |  //enable pwm
            (1<<PWM1A) | // set source to pck
            (1<<(CS10)) | // clear the pin when match with ocr1x
            (1<<COM1A1);
    GTCCR =  (1<<PWM1B) | (1<<COM1B1);

    // Set PWM TOP value - counter will count and reset
    //  after reaching this value
    //          OCR1C
    // 400Khz  159     
    // 450khz  141
    // 500khz  127
    OCR1C = 159;

    //enable Timer1 OVF interrupt
    TIMSK = (1<<OCIE1A) | (1<<TOIE1);   

    sei();

    //This should set the duty cycle to about 75%
    OCR1A = 120;
}

void loop() {
}

```

---

<div class="post-metadata">

**Author:** ![HermannSW](https://avatars.discourse-cdn.com/v4/letter/h/9e8a1a/32.png) [@HermannSW](https://forum.arduino.cc/u/HermannSW)\
**Post date:** [January 11, 2017, 6:43pm UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/8 "2017-01-11T18:43:38Z")

</div>

Some measurements are strange, but I was able to measure 10MHz PWM frequency with these changes:

```cpp
...
    OCR1C = 5;
...
    OCR1A = 3;
...

```

Nice clean 10MHz PWM signal from 1$ ATtiny85. 10MHz is maximum that I was able to measure with 24Msps logic analyzer. Will try with 400Msps analyzer when back at home.

 ![](https://europe1.discourse-cdn.com/arduino/original/4X/7/4/6/7469464e6265d2d13300135849203ac8c5de9209.png)

---

<div class="post-metadata">

**Author:** ![HermannSW](https://avatars.discourse-cdn.com/v4/letter/h/9e8a1a/32.png) [@HermannSW](https://forum.arduino.cc/u/HermannSW)\
**Post date:** [January 15, 2017, 6:57pm UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/9 "2017-01-15T18:57:02Z")

</div>

I had problems determining average frequency for measurement with [400Msps logic analyzer](https://www.aliexpress.com/item/DSLogic-logic-analyzer-of-up-to-400-M-sampling-16-channel-for-debugging/32375169003.html) DSView GUI.

Therefore I used [100Msps logic analyzer](https://www.aliexpress.com/item/USB-Logic-Analyzer-100M-max-sample-rate-16Channels-10B-samples-MCU-ARM-FPGA-debug-tool/32285979458.html). Salea Logic 1.2.10 GUI allows to determine average frequency as one of many options for measurements.

Maximal frequency is achieved with

```arduino
...
    OCR1C = 2;
...
    OCR1A = 1;
...

```

Interestingly maximal PWM frequency is different depending on "board" used in Arduino IDE to program ATtiny85:

- 22.12MHz for "Digispark (Default - 16.5mhz)"
- 28.27MHz for "Digispark (16mhz - No USB)"

Hermann.  
 ![](https://europe1.discourse-cdn.com/arduino/original/4X/f/e/4/fe4fa342490c3b977af20397aff2e693f0538578.png)

---

<div class="post-metadata">

**Author:** ![claudiocfv](https://avatars.discourse-cdn.com/v4/letter/c/9f8e36/32.png) [@claudiocfv](https://forum.arduino.cc/u/claudiocfv)\
**Post date:** [March 25, 2020, 8:30pm UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/10 "2020-03-25T20:30:02Z")

</div>

Using your code I can reach the high frequency as I want, but I cannot modulate the Duty Cycle by an analog road for example, it is fixed at the value selected in the code. How could I do that? it seems that other functions are disabled with this code.

> HermannSW:  
> Found "Setting High Speed PWM on ATTiny85":  
> [c - Setting high speed PWM on ATtiny85 - Stack Overflow](http://stackoverflow.com/questions/21654618/setting-high-speed-pwm-on-attiny85)
> 
> Adapted for Arduino IDE I measured up to 676.7kHz with "OCR1C = 123;".
> 
> ```arduino
> 123*676.7
> 
> ```

83234.1  
127_648  
82296  
141_590.8  
83302.8  
159\*524.4  
83379.6

> ```arduino
> 
> This is from comment of sketch below, not sure why I measured 1.3 times as much:
> 
> ```
> 
> // Set PWM TOP value - counter will count and reset  
> &nbsp; &nbsp; //&nbsp; after reaching this value  
> &nbsp; &nbsp; //&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OCR1C  
> &nbsp; &nbsp; // 400Khz&nbsp; 159&nbsp; &nbsp;  
> &nbsp; &nbsp; // 450khz&nbsp; 141  
> &nbsp; &nbsp; // 500khz&nbsp; 127
> 
> ```arduino
> 
> ```
> 
> 400_159  
> 63600  
> 450_141  
> 63450  
> 127\*500  
> 63500
> 
> ```arduino
> 
> Hermann.
> 
> ```
> 
> //#include \<avr/io.h\>  
> //#include \<avr/interrupt.h\>

void setup()  
{  
&nbsp; &nbsp; PORTB = 0;&nbsp; &nbsp; &nbsp; //Reset values on port B

// After setting up the timer counter,  
&nbsp; &nbsp; // set the direction of the ports to output  
&nbsp; &nbsp; DDRB |= (1\<\<PB1) | (1\<\<PB0); // Set the direction of PB1 to an output

// PLLCSR - PLL control and status register:  
&nbsp; &nbsp; // PLL is a clock multiplier - multiplies system&nbsp; &nbsp; 8Mhz by 8 to 64Mhz  
&nbsp; &nbsp; // PLL is enabled when:PLLE bit is enabled,  
&nbsp; &nbsp; // CKSEL fuse is programmed to 0001.&nbsp; This clock is  
&nbsp; &nbsp; //&nbsp; switched off in sleep modes!  
&nbsp; &nbsp; PLLCSR |= (1\<\<PLLE);&nbsp; &nbsp; // PLL enable

// Wait until the PLOCK bit is enabled  
&nbsp; &nbsp; //&nbsp; before allowing the PCK to be enabled  
&nbsp; &nbsp; // WaitForPLOCK();  
&nbsp; &nbsp; // unsigned int i = 0;

while ((PLLCSR & (1\<\<PLOCK)) == 0x00)  
&nbsp; &nbsp; {  
&nbsp; &nbsp; &nbsp; &nbsp; // Do nothing until plock bit is set  
&nbsp; &nbsp; }

PLLCSR |= (1\<\<PCKE); // Enable asynchronous mode, sets PWM clock source

TCCR1 =  
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (1\<\<CTC1) |&nbsp; //enable pwm  
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (1\<\<PWM1A) | // set source to pck  
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (1\<\<(CS10)) | // clear the pin when match with ocr1x  
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (1\<\<COM1A1);  
&nbsp; &nbsp; GTCCR =&nbsp; (1\<\<PWM1B) | (1\<\<COM1B1);

// Set PWM TOP value - counter will count and reset  
&nbsp; &nbsp; //&nbsp; after reaching this value  
&nbsp; &nbsp; //&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OCR1C  
&nbsp; &nbsp; // 400Khz&nbsp; 159&nbsp; &nbsp;  
&nbsp; &nbsp; // 450khz&nbsp; 141  
&nbsp; &nbsp; // 500khz&nbsp; 127  
&nbsp; &nbsp; OCR1C = 159;

//enable Timer1 OVF interrupt  
&nbsp; &nbsp; TIMSK = (1\<\<OCIE1A) | (1\<\<TOIE1);

sei();

//This should set the duty cycle to about 75%  
&nbsp; &nbsp; OCR1A = 120;  
}

void loop() {  
}

> ```arduino
> 
> ```

---

<div class="post-metadata">

**Author:** ![b\_force](https://avatars.discourse-cdn.com/v4/letter/b/d9b06d/32.png) [@b\_force](https://forum.arduino.cc/u/b_force)\
**Post date:** [June 14, 2020, 9:16pm UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/11 "2020-06-14T21:16:15Z")

</div>

> claudiocfv:  
> Using your code I can reach the high frequency as I want, but I cannot modulate the Duty Cycle by an analog road for example, it is fixed at the value selected in the code. How could I do that? it seems that other functions are disabled with this code.

Another way of doing this, is using an external XOR or XNOR gate.  
With adjusting the delay on the 2nd output, you can generate a PWM signal.

As a bonus, the XOR will DOUBLE the frequency as well.

---

<div class="post-metadata">

**Author:** ![system](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/system/32/1140315_2.png) [@system](https://forum.arduino.cc/u/system)\
**Post date:** [May 5, 2021, 7:31pm UTC](https://forum.arduino.cc/t/attiny85-pwm-frequency-selection/60785/12 "2021-05-05T19:31:31Z")

</div>

Closed on May 5, 2021, 7:31pm UTC


