Pages: [1] 2   Go Down
Author Topic: Highest PWM frequency output for the Uno/Nano  (Read 5018 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What is the highest PWM frequency that can be output by the Uno or Nano?

I cant remember exactly right now but I remember measuring around 70kHz output using an oscilloscope with the following program:

Code:
void loop ()
{
  digitalWrite(outPin, HIGH);
  digitalWrite(outPin, LOW);
}

That program above is essentially the fastest that it can generate a PWM pulse right? So is it capped at 70kHz then?

How do you get higher frequencies straight out of the digital I/O?
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17259
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Direct port manipulations will allow you to toggle a output pin as fast as possible for a given clock rate.

 http://www.arduino.cc/playground/Learning/PortManipulation

Lefty
« Last Edit: October 20, 2012, 09:32:11 pm by retrolefty » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
 digitalWrite(outPin, HIGH);
  digitalWrite(outPin, LOW);

That's not really PWM. Use the internal timers to do that.

I have some examples near the bottom of this page:

http://www.gammon.com.au/forum/?id=11504

If you use the "fast PWM mode, top at OCR0A" mode then you can get quite high frequencies, the trade-off being lower PWM resolution.

As an example:

Code:
#include <TimerHelpers.h>

// Timer 0

// output    OC0B   pin 11  (D5)

const byte timer0OutputB = 5;
  
void setup() {
   pinMode (timer0OutputB, OUTPUT);
   TIMSK0 = 0;  // no interrupts
   Timer0::setMode (7, Timer0::PRESCALE_1, Timer0::CLEAR_B_ON_COMPARE);
   OCR0A = 3;   // count to 4, zero-relative
   OCR0B = 1;   // duty cycle
}  // end of setup

void loop() {}

Because OCR0A is small it counts up to 4, giving a frequency of 4 MHz (one quarter of the system clock). However the duty cycle can only be 0, 1 or 2, so basically you can have a 33% or 66% duty cycle.

The higher you make OCR0A the lower the frequency but the higher resolution of PWM duty cycle.
« Last Edit: October 20, 2012, 10:29:57 pm by Nick Gammon » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Screenshot of above test confirms results:



Note the frequency and the duty cycle. To get a duty cycle of 33.3% you need OCR0B to be 2 rather than 1.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks. Looks like the default digitalWrite() has too much overhead. I just tried measuring the uno with the OP code and I topped at 116kHz. The nano that I measured before topped at 70kHz. But seeing there are many different timers I guess it depends on which pin too?

For the sample code you supplied using the TimersHelpers.h library, I downloaded it and tried the sample code. There was an error on debug saying TImer0 is not defined?

If I want to create 50% duty cycle signals at the highest frequency possible (essentially just a normal periodic square wave). Can that be done up to 4MHz (you mentioned 4MHz can only choose between 33% or 66% duty)?
« Last Edit: October 20, 2012, 10:40:16 pm by PeekabuPi » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

For a normal square wave use a simpler timer mode like CTC. Example:

Code:
#include <TimerHelpers.h>

// Timer 0

// output    OC0A   pin 12  (D6)

const byte timer0OutputA = 6;
  
void setup() {
   pinMode (timer0OutputA, OUTPUT);
   TIMSK0 = 0;  // no interrupts
   Timer0::setMode (2, Timer0::PRESCALE_1, Timer0::TOGGLE_A_ON_COMPARE);
   OCR0A = 1;  // count to 2
}  // end of setup

void loop() {}

That outputs a 4 MHz square wave.

If you change OCR0A to 0 you get a 8 MHz square wave.

If you are getting compile errors, that code was for the Uno. Did you install the timer helpers library?

http://gammon.com.au/Arduino/TimerHelpers.zip
« Last Edit: October 20, 2012, 10:52:45 pm by Nick Gammon » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am using an Uno right now too. Yeah I saw the link from the site you linked to earlier.

It says Timer0 is not declared?
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Install the library, restart the IDE. It should compile then.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Unzip that file, copy the folder TimerHelpers into the libraries folder (in your Arduino sketches folder) then restart the IDE. Copy the whole folder, not just the contents.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks. I got it to work. The restart seemed to do it.

I also measure 4MHz square wave now too! Cheers!A few noob question:

Does it still source the maximum 50mA current?
Does this code also work for the nano?
Does the code work for all digital pins?

I just tried to move part of the code over to loop and the signal is no longer steady and 50% dutycycle i guess because there is some time lag with the restarting the loop? So this method only works under void setup()?
« Last Edit: October 20, 2012, 11:23:06 pm by PeekabuPi » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Does it still source the maximum 50mA current?

20 mA more like. 40 mA is the absolute maximum.

Quote
Does this code also work for the nano?

I imagine so.

Quote
Does the code work for all digital pins?

The timers have fixed output pins. Each timer has two pins dedicated to it which is why you have 6 PWM outputs on the Uno (3 timers x 2 pins each).

Quote
I just tried to move part of the code over to loop and the signal is no longer steady and 50% duty cycle i guess because there is some time lag with the restarting the loop? So this method only works under void setup()?

That doesn't make sense. Show your amended code please. Once you have the timer set up it doesn't matter what the code is doing. However if you put that code into loop it might be restarting the timer very rapidly. You don't want that.

The timer (that I showed) runs independently, so that is why I had it in setup. You don't have to keep calling the code. It's all done in hardware.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi I think I just tired this:


Code:
#include <TimerHelpers.h>

// Timer 0

// output    OC0A   pin 12  (D6)

const byte timer0OutputA = 6;
 
void setup() {
   pinMode (timer0OutputA, OUTPUT);
}  // end of setup

void loop() {

   TIMSK0 = 0;  // no interrupts
   Timer0::setMode (2, Timer0::PRESCALE_1, Timer0::TOGGLE_A_ON_COMPARE);
   OCR0A = 1;  // count to 2
}

Also I tried it with the nano recently. I noticed that the uno produces better square waves than the nano. Are the pulses generated by the microcontroller (which are the same for the uno and nano)? Or the crystal?

I was wondering if there is any documentation on how to use the TimeHelper header file?
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Don't do that in loop.

Quoting myself, who you have chosen to ignore:

Quote
However if you put that code into loop it might be restarting the timer very rapidly. You don't want that.
Logged

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
What is the highest PWM frequency that can be output by the Uno or Nano?

The hardware pwm module can be quite helpful here.

The spi / uart module can also be used to generate pwm in case that's needed.

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry didnt mean to ignore the advice. I just tried it for the sake of it. Actually the reason is I intend to be able to modulate the frequency so maybe Id want it in the loop instead.
Logged

Pages: [1] 2   Go Up
Jump to: