Search

How to modify the PWM frequency on the arduino-part1(fast PWM and Timer 0)

Please let us in the comment zone any suggestions that you think will improve the article!

If you like the article click the follow button from social media to stay in touch with us!

The default frequency of arduino PWM pins is around 490Hz for 9, 10, 3,11 and around 980 HZ for 5, 6, but for many applications we need some higher frequencies. The arduino uno can generate frequencies for PWM pins up to 8Mhz. To modify these values we need to work with timers(which contains registers). For PWM, arduino has three timers one for two pins like:

-timer 0- for pins 5 and 6

-timer 1-for pins 9 and 10

-timer 2-for pins 3 and 11

Beside these registers arduino can put the PWM pin in four modes like

-fast PWM

-phase correct pwm

-frequency and phase correct pwm

-ctc mode

Before to talk about timers let’s have a look at these PWM modes because we choose them from the timers bits:

Fast PWM mode -timer count from a BOTTOM value to a TOP value after that it overflow to BOTTOM value and repeat(sawtooth waveform), it can generate higher frequencies(picture from atmega datasheet).

fast pwm mode

For this mode the possible frequencies are given by the formula f=f_clk/(N*256), where f is the neccesary frequency, f_clk is the oscillator frequency(16Mhz) and N is the prescaler(it has precise values and it is given form the timer’s bits so we will explain it in more details when we will talk about timers).

Phase correct PWM mode-timer count from a BOTTOM value to a TOP value after that it not overflow it countdown from TOP value to BOTTOM value and repeat(triangle wave). This mode has half of fast pwm mode frequency.It is preferred in motors control(picture from atmega datasheet).

phase correct pwm

For this mode the possible frequencies are given by the formula f=f_clk/(N*510), with all the variables like in the fast pwm mode.

Frequency and phase correct pwm(only on timer 1)-are the same with phase correct pwm if the TOP value remains the same, if not let asumme that we have two TOP values TOP1 and TOP2, TOP1>TOP 2, when the timer count up to TOP 1 and down to BOTTOM the pulse have a specific time period but when the timer count up to TOP 2 and down to BOTTOM, because the TOP 2 is smaller than TOP 1 the pulse have a small  time period so a higher frequency(picture from atmega datasheet).

frequency and phase correct pwm mode

CTC mode-in this mode timer count to a TOP value and when it reach that value clear the timer and execute something. This mode let us to make very precise operation(picture from atmega datasheet).

CTC mode

Now let’s talk about timers!

Timer 0 manage pins 5 and 6, so next in a couple of examples we will show you how to manage the pwm frequencies.

Let’s assume we want to generate a Fast PWM Mode with a duty cycle at 50% (we will explain when we reach at the OCRA register ).

To choose the fast pwm mode in the TCCR0A we must make the WGM01 and WGM00 bits equals 1 like in the pictures below(from atmega datasheet).

TCCR0A

PWM modes

As we explained in this article in the arduino program we have TCCR0A=B10100011; this means that the WGM00 and WGM01 from the TCCR0A register are 1 which means that the pins 5 and 6 are in the fast pwm mode.



But first bit and the third why are they 1???

These bits are COM0A1 and COM0B1 and in the images below you(from atmega datasheet) can see that they controls the pin 6(COM0A1) and 5(COM0B1).

COM0A1

COM0B1

If we choose all bits(COM0A1 COM0A0,COM0B 1and COM0B0) 0 the pins are disconnected(they don’t work).

If you choose the COM0A1, COM0B1 1 and COM0A0, COM0B0  0 then pins 5 and 6 generate a PWM and with a prescaler let’s say 64(explain soon) from the formula  f=f_clk/(N*256) we will have a 976 Hz pwm signal.

In the image below we have such a signal(976.6Hz and a 20% duty cycle(ON) and 80%(OFF) (50 in program because it is from 0 to 255))

fast pwm noninverting mode

The program for this signal is:

void setup() {
pinMode(5, OUTPUT);
pinMode(6,OUTPUT);
TCCR0A=0;//reset the register
TCCR0B=0;//reset tthe register
TCCR0A=0b10100011;// fast pwm mode
TCCR0B=0b00000011;// prescaler 64
OCR0A=50;//duty cycle for pin 6
OCR0B=50;//duty cycle for pin 5
}
void loop() {
// put your main code here, to run repeatedly
}

If you choose all COM0A1, COM0B1  and COM0A0, COM0B0  1 then pins 5 and 6 generate a PWM and with a prescaler let’s say 64(explain soon) from the formula  f=f_clk/(N*256) we will have a 976 Hz pwm signal, but this signal is inverted like in the picture below so duty cycle is 80% (ON) and 20% (OFF):

fast pwm inverting mode

The program for this signal is:

void setup() {
pinMode(5, OUTPUT);
pinMode(6,OUTPUT);
TCCR0A=0;//reset the register
TCCR0B=0;//reset tthe register
TCCR0A=0b11110011;// fast pwm mode
TCCR0B=0b00000011;// prescaler 64
OCR0A=50;//duty cycle for pin 6
OCR0B=50;//duty cycle for pin 5
}
void loop() {
// put your main code here, to run repeatedly
}

Now if you choose  COM0A1 0 and COM0A0 1 and make the WGM02 bit from TCCR0B register 1, the pin 5 is disconnected and timer counts for pin 6 until it’s reach OCR0A not until 255(if OCR0A is not 255) which is maximum.

Ok ok  but what is the relation between OCR0A and frequency. Also from datasheet we have the formula (it is in CTC mode but it is avaible in here also)  fOCR0A­­=fclk/(2*N*(1+OCR0A)).

With these setting you can obtain up to 8Mhz 50%(fixed) duty cycle signal (if OCRA is 0 and we have no prescaler) but only on pin 6 like in the picture below:

8 Mhz fast pwm signal

This mode has advantage that can reach very high frequencies but the disavantage is that you have a fix duty cycle.

The program to reach 8Mhz is:

void setup() {
pinMode(5, OUTPUT);
pinMode(6,OUTPUT);
TCCR0A=0;//reset the register
TCCR0B=0;//reset tthe register
TCCR0A=0b01010011;// fast pwm mode
TCCR0B=0b00001001;// no prescaler and WGM02 is 1
OCR0A=0;//control value
}
void loop() {
// put your main code here, to run repeatedly
}

If OCR0A is 50(and no prescaler) the frequency from formula is 156.862Hz as you can see in the image from oscilloscope:

fast pwm OCR0A

The program is:

void setup() {
pinMode(5, OUTPUT);
pinMode(6,OUTPUT);
TCCR0A=0;//reset the register
TCCR0B=0;//reset tthe register
TCCR0A=0b01010011;// fast pwm mode
TCCR0B=0b00001001;// no prescaler and WGM02 is 1
OCR0A=50;//control value
void loop() {
// put your main code here, to run repeatedly
}

With the formula OCR0A ­­=(fclk/2*N*fOCR0A)  -1 (first formula but rearranged) and this mode if you want a specified frequency you calculate the OCR0A and introduce it in the program. For example if you want a 25kHz (but is at 50% duty cycle) you must choose a OCR0A=39 and a prescaler=8, because if we don’t use prescaler the OCR0A from the formula give us OCR0A=319, and because timer 0 has 8bits the OCR0A <= 255.

The result is:

25kHz fast pwm

And the program:

void setup() {
pinMode(5, OUTPUT);
pinMode(6,OUTPUT);
TCCR0A=0;//reset the register
TCCR0B=0;//reset tthe register
TCCR0A=0b01010011;// fast pwm mode
TCCR0B=0b00001010;// prescaler 8 and WGM02 is 1
OCR0A=39;//control value
}
void loop() {
// put your main code here, to run repeatedly
}

Finally we will talk about prescaler, OCR0A and OCR0B(which give the duty cycle).

The prescaler is used to control the frequency(from formules) and is managed in the TCCR0B register like in the images(from atmega datasheet)

TCCR0BTimer 0 prescaler

It is controlled by CS00, CS01 and CS02 bits with different combinations as you can see in the image above.

Now the OCR0A and OCR0B registers can take values from 0 to 255 because they are on 8 bits(they can be written on decimals-as we do) and OCR0A is for pin 6 and OCR0B is for pin 5 like in the image below:

OCR0A and OCR0B

A short video:

Facebooktwitterpinterest

Related posts

14 thoughts on “How to modify the PWM frequency on the arduino-part1(fast PWM and Timer 0)

  1. kolle

    hello, gg i’ve a question about the code, i’ve tried it but it doesn’t work well, there’s nothing on pin 5 and 6

    1. admin

      Which of programs you have try because each of them i have analized on the oscilloscope and work well???

    2. Karo

      Hi. If you use proteus to simulate, nothing is going to happen.
      I had the same issue

      If you can use a osciloscope and if you dont have one use the multimeter to mesure frequency

  2. Benjamin

    hello, thanks for this article this has helped me understand how the microcontroller works to produce the pwm signal I just had a question about the code. Is this code just used on a standard arduino uno and could it possibly be modified to work on a standalone atmega328 to produce a 40kHz pwm signal?

    1. admin

      If you don’t need the program right now i will write a post but in a few days(i don’t have free time right now).
      Sorry for late response!

    2. admin

      i have uploaded a post with 40kHz signal and yes it works on atmega standalone but with an external 16Mhz oscillator

  3. Samadi

    hello, Sir, I’m using Proteus but this code timer 0 is not working mean pin 5 and pin 6 is in silent mode but the code of timer2 is pin 9 and pin 10 is working fine please help me why?

  4. henok girma

    if u can please i need an automatic transfer switch for solar diesel power system with arduino base.

  5. Thiemo

    Hi, very nice Tutorial!
    I’m facing with a problem in one of my projects. I’ve an Arduino Nano and a 4pin Fan and need to change the duty cycle of the 25khz singnal. Is that possible?

    1. admin

      At 25kHz from what i know it is not possible because the frequencies with variable duty cycle are calculated with formula f=16Mhz/(N*256) where N=1 or 8 or 64 or 256 and 1024.

  6. Aditya Barve

    Thank you!
    Very useful………………..

  7. rina

    f=fclk/N*510 where does the number 510 come from?

    1. admin

      The 510 parameter is because in the phase correct mode the counter increment and also decrement until update the registers see the datasheet.
      Have a nice day :)!

  8. Jimmy

    hi, you might want to update formulas with parenthesis to respect order of opperations,
    f=f_clk/N*256 should either become f=f_clk/N/256 or f=f_clk/(N*256).

Leave a Comment

Show Buttons
Hide Buttons