This is a post about changing the PWM frequency of an ATTiny85 which has been programmed via the Arduino IDE.

I wanted a faster PWM frequency to remove audible noise on a dump load controller I had been designing. This controls an output load using PWM and a FET. This produced audible noise when running. I wanted to increase the frequency so that the noise is moved into the above-audible range (20kHz or higher).

This needed the internal timers in the ATTiny85 to be changed to ‘Fast PWM’ mode.

Arduino PWM

The frequency of the PWM output of the Arduino is quoted as around 500Hz ( – its actually 490Hz but with different frequencies on different PWM output pins on the Arduino. Writing a value of 0-255 with write a duty cycle of between 0% and 100%. This is the standard output frequency set by the Arduino folk.

The actual IC used (either the ATMega328 or, in this case, the ATTiny85) can have much faster PWM output. The outputs can be altered as shown in this post:

There are a couple of youtube videos on changing the PWM frequency by Julian Ilett (who is working on a MPPT solar charge controller) here: one and two. He is using an Arudino Nano, but the videos explain the Arduino PWM very well.

There is also an Application note from Atmel relating to using fast PWM on the AVR.

There is also a good discussion of the issues in this thread.

Fast PWM examples

Doing a search for fast PWM on the ATTiny85 I came across this example code:

Also, checking the ATTiny85 datasheet to look at the Timer 0 and 1 and setting fast PWM we find the bits we need to set. Its not very obvious, but here is a brief explaination of the bits to set. One problem with changing Tiner0 is that it will affect the normal delay function (as this depends upon the Timer 0 value for its timing).

In order to overcome this we have to use a different delay function, by including the library “#include <util/delay.h>”. This also requires us to set the define the CPU frequency, which is used to calculate the correct delays “#define F_CPU 8000000”, as I have set the clock  to 8MHz. We must also use the new delay functions from the new delay library. These are written as “_delay_ms(500);”. The “delay(500); ” does not work as it uses the timer 0, which we need to change in order to get fast PWM.

We also include the library “#include <avr/io.h>” which has the definitions for the various register we need to set.

When we read the data sheet we see that we need to set:

  • WGM0[2:0] to 3 (binary 011):  this is the Waveform Generation Mode which we set to Fast PWM.
  • COMOA0/COMOB0 to 2 (binary 10): Compare Match Output Mode needs to be ‘Clear on Match. Set at Bottom’
  • CS00/CS10 = 1: This tells Timer 0/1 NOT to use a prescaler.
  • PWM1B = 1: This enables the use of Output Compare Unit B from Timer 1 (OC1B).
  • PWM1A = 0: This disables the use of Output Compare Unit A from Timer 1 (OC1A) as that pin is shared with OC0B.

If we check the data sheet we see that OC1B is on pin 3 (Arduino pin 4), OC0A is on pin 7 (Arduino pin 2/A1) and OC1A/OC0B is on pin 6 (arduino pin 1) of the IC. In the end I only want OC1B to give me fast PWM, but its good to see how the other outputs can be used.

This is done by setting the following registers (notes have been copied from here):

TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
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

TCCR0B = 0<<WGM02 | 1<<CS00;   
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

TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
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 pre-scalar

GTCCR = 1<<PWM1B | 2<<COM1B0;
General Control Register for Timer/Counter-1 (this is for Timer/Counter-1 and is a poorly named register)
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

Arduino code for ATTiny85

This is a test code which writes a 50% duty cycle to an output pin (redled) and turns on and off an output (buzzLedSw) every 500mS. We are also outputting serial data every second.

The output frequency is 8MHz, our pre-scalar is 1 and the output will roll over when we have reached a value of hex FF = 256, so we will have an output frequency of 8Mhz/ (1x 256) = 31.25kHz.

Note: The maximum available output frequency for PWM comes from the maximum clock frequency. The max clock frequency is 64MHz, when a PLL (Phase Locked Loop) is used. So the maximum output frequency is 64MHk / 256 = 250kHz.

Here are some ‘scope waveforms of the outputs.

This is the 50% duty cycle PWM on pin 5 (OC0A). As expected we get an output of around 31.25kHz (this scope is not too accurate).

This is an ON/OFF output controlled by the ‘_delay_ms(500)’ line, which gives an output of around 1 second (very approximately as there are other things happening (such as serial write) which slow this down).

So I now have fast PWM working on the output for my ATTin85.

2 responses to “Fast PWM on ATTiny85

  1. Hello,

    I found your page very useful, I am working on a project that I need to make a serial communication via the Bluetooth to the Attiny85 am a Hardware guy so I need some help in writing the program. I just need a pwm out from 0-3v from pin 5. can you help with the program?

  2. Thanks for the code.. I found it confusing, using something other than a 1 in the shit, “GTCCR = 1<<PWM1B | 2<<COM1B0;" with your docs saying you are setting bit COM1B1 and clearing bit COM1B0. There is no need to 'zero' bits in a bit mask, as you're doing. So anything with a "0 << value" does nothing as the compiler is building this value, and it's zero to start with. All of the Atmel docs show it as "1 << COM1B1". The whole idea of using these defines is to show which bit's you're setting. By using "2 << COM1B0", instead of "1 << COM1B1" as COM1B0 is not being set it only obfuscates what you are doing to the reader. I write it as _BV(COM1B1) (BV is bit value) which is a standard macro that I've used used for many years with Atmel or Arduino code and resolves to "1 << COM1B1".

    I also had a difficult time with the site and getting the code. It would not let me copy and paste and I could only do fragments. It compiles but fails to generate PWM on any pin. Not blaming your code, but the difficulty in getting it to my machine is partially the problem. Part of the issue is that it's not wide enough to really read your comments as I have to scroll to the bottom and 'guess' where I want to slide the 'window' and scroll back up, since the scroll bar is at the bottom.

    Thanks, take care…

Leave a Reply

Your email address will not be published. Required fields are marked *