Pages: [1] 2   Go Down
Author Topic: Feature request: Adjustable PWM frequency  (Read 19436 times)
0 Members and 1 Guest are viewing this topic.
Atascadero, CA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 468
Arduino addict
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm posting this here because I'm _hoping_ it's not a hardware limitation.  smiley-wink

It would be very useful if the frequency of the PWM output could be set in the software.  I have run across two scenarios that would be better handled by a frequency other than around 500 Hz.

In the case of using PWM on a high-power LED, the 500 Hz PWM is OK only if the LED is not moving.  In my case, I'm making an LED headlight for my bicycle and 500 Hz makes the ride very psychedelic and strains the eyes.  If I could set the PWM frequency to 2K-5KHz, it would be much better

At the other end, controlling the speed of a fan is better suited by a PWM frequency down around 10-30 Hz so that it's at the end or below the audible range.  Many fans and other mechanical devices vibrate as a result of the PWM signal because it's a very intense pulse.

Thanks!
Logged

What about elevensies? Luncheon? Afternoon tea? Dinner? Supper?

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

Having looked at the processor's data sheet, the PWM frequency is not a fixed value, but rather the results of values placed in the various timers parameters registers.

So I guess the PWM frequency could be changed but would require writing functions to replace or used instead of the standard PWM commands. There may be some other software limitation or interaction with other functions that utilize the times but I'm not software competent enough to undertake the analysis.

I agree it would be a nice addition to add to the tool box.

Lefty
Logged

Connecticut, US
Offline Offline
Edison Member
*
Karma: 2
Posts: 1036
Whatduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

There's no friendly setAnalogFrequency() kind of function included in the standard library, but it's a pretty straightforward task.

A google search for "arduino set pwm frequency" will find a few useful threads on this site and on other sites like uchobby.

I think one reason for excluding the function is because there are some subtle interplay that you should be familiar with, before you start messing with these things.

For example, there are six PWM-capable output pins, and each of the six outputs has their own PWM-comparator to adjust the duty cycle of that pin.  But there are only three actual timers, so pins in pairs, 3/11, and 5/6, and 9/10, each pair shares a timer.  Adjust the frequency of pin 3, and pin 11 also gets the new shared frequency.
Logged

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

Quote
For example, there are six PWM-capable output pins, and each of the six outputs has their own PWM-comparator to adjust the duty cycle of that pin.  But there are only three actual timers, so pins in pairs, 3/11, and 5/6, and 9/10, each pair shares a timer.  Adjust the frequency of pin 3, and pin 11 also gets the new shared frequency.

Also isn't one of the three timers a 16 bit Vs 8 bit for the other two? Does that mean it might also be possible to have a greater 'duty' cycle resolution then the 8 bit resolution that the PWM command now offers?

Lefty

Logged

Atascadero, CA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 468
Arduino addict
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

With an 8-bit resolution and a clock speed of 16Mhz, the theoretical max frequency of the PWM output would be around 64Khz  (16Mhz/256 steps) and at 16-bit, it would be about 256Hz (16MHz/65536 steps)  So if you wanted higher res, you would have to sacrifice frequency, which may actually work to an advantage.  And the converse is also true.  There's probably some processing overhead that I'm not considering.

It also seems like you would want (need/require) a frequency that is somewhat evenly divisible by either 256 or 65536 in order to avoid aliasing and rounding. (?)

I'm going to look around for info on this as halley suggested.  In the project I'm doing now, I only need one or two PWM outputs, so hacking it may be an option for me.  smiley
Logged

What about elevensies? Luncheon? Afternoon tea? Dinner? Supper?

0
Offline Offline
Newbie
*
Karma: 0
Posts: 30
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is a great guide for Arduino timers and there is a section for pwm frequency as well.

http://www.cs.mun.ca/~rod/Winter2007/4723/notes/timer0/timer0.html
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 137
Posts: 6792
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Heh.  My scope says it's about 1000Hz on pin5 and pin6, and about 500Hz on the other PWM outputs.

That's ... interesting.  I wonder if it's intentional, or whether it's a bug?
The pin5/6 PWM outputs share the timer with the core millis() timer, so they pretty much have to ~1000Hz.
The comments say that the prescaler factors are all being set to the 64, but they set different bits...
Logged

Atascadero, CA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 468
Arduino addict
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@cyberheater:  I read through that timer0 document.  It's pretty far beyond my knowledge of programming.   :-?  I'm really new to the microcontroller world.  Is this something that can be done through the Arduino IDE or does it require other tools?  Also, it looks like this is for a device other than the Arduino.  (Now I'm pretty sure my noob-ness is showing.)

@westfw: 1000Hz may work for my project.  500 Hz is too low, but 1KHz could be enough.  I'll check it out.

Thanks!
Logged

What about elevensies? Luncheon? Afternoon tea? Dinner? Supper?

0
Offline Offline
Newbie
*
Karma: 0
Posts: 30
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes you can set the pwm withing the IDE.

Here is an example:-
Code:
#include <avr/interrupt.h>

// This is using the 16-bit timer.  10-bit pwm

void setup() {

  // TCCR1B
  // Bit              7      6      5           4          3      2        1       0
  // Bit Name            COM1A1 COM1A0 COM1B1 COM1B0 -----       -----      WGM11      WGM10
  // Initial Value      0      0      0           0          0         0        0        0
  // changed to         1      1      1      1      0      0      1       0
TCCR1A = B11110010;

  // TCCR1B
  // Bit            7          6      5        4        3        2        1        0
  // Bit Name         ICNC1  ICES1       -----      WGM13      WGM12      CS12      CS11      CS10
  // Initial Value    0          0         0        0        0        0        0        0
  // changed to       0     0      0      1       1       0       0       1  
  // CS12,CS11,CS10 = (0,0,1) System clock, no division
TCCR1B = B00011001;

TCCR1B = 25;// 00011001
ICR1 = 1023 ; // 10 bit resolution
OCR1A = 511; // vary this value between 0 and 1024 for 10-bit precision
OCR1B = 511; // vary this value between 0 and 1024 for 10-bit precision      

pinMode (10, OUTPUT);
  
}

void loop()
{
  
unsigned int n;
  
  for (unsigned int i = 0; i <1024; i++) {
    OCR1A = i;
    OCR1B = i;
    delay (1);
  }

}

    

Logged

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

That code compiles fine and when run I see the changing PWM signal on D10 pin but not a second PWM signal on any other pin?

Never mind, I see it's only suppost to use pin 10. Someday I guess I'll have to read the data sheet and try and understand these timers.

Lefty
« Last Edit: February 17, 2009, 03:37:36 pm by retrolefty » Logged

Atascadero, CA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 468
Arduino addict
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sweet!  I will try this and see what I get.  It will be a few days because... well.... I don't actually HAVE an Arduino yet.   :-[  I've been simulating everything for my project with software and physical analog circuits for the time being.  

But my Arduino is on its way - just got shipment confirmation this morning!  <geeky excitement>
Logged

What about elevensies? Luncheon? Afternoon tea? Dinner? Supper?

Atascadero, CA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 468
Arduino addict
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Got my board!   smiley-grin

OK, I pasted cyberheater's example into the IDE and am running it.  I'm getting a ~64us period on pin 10 (and 9, but not the others), which is about 15.7KHz and the duty cycle appears to be in the range of 0-1023 now instead of 0-255.  But I have no idea what most of the stuff in void setup() does.  I'm going to poke around at it and see what I get.

This appears to affect both pins 9 and 10 at the same time.  How do I determine which one I want to use?  Can I set different duty cycles on each pin?

Can someone break down the "TCCR..." and "OCR..." lines so I can understand how to modify it and use it for my needs? Or point me at a doc that does?

This is awesome stuff!  Thanks!

EDIT:  The following related thread was updated today with a very nice chunk of info about this topic:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235060559/0
« Last Edit: February 22, 2009, 09:39:53 pm by koyaanisqatsi » Logged

What about elevensies? Luncheon? Afternoon tea? Dinner? Supper?

0
Offline Offline
Newbie
*
Karma: 0
Posts: 37
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

To add some simple code:

To change the PWM frequency on pins 3 and 11 (simultaneously, they use the same timer), add the following code to setup():

Code:
void setup() {
     TCCR2B = (TCCR2B & 0xF8) | value;
}
where the value is the number 1 to 7 from the following table:
31372.5      Hz    ->         1
3921.57      Hz    ->         2
980.392      Hz    ->         3
490.196      Hz    ->         4    (default)
245.098      Hz    ->         5
122.549      Hz    ->         6
30.6373      Hz    ->         7

There's no need for other code changes, simply use analogWrite(3, p) or analogWrite(11,p) as you would do.

Oh yeah, the frequencies are for 16MHz clock, they should be 1/2 for 8MHz.
« Last Edit: February 28, 2009, 03:07:19 pm by mekon83 » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
I love Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

How about Arduino Mega ?, i try that code  seem to be not work on Mega board
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I need a 140hz frequency, is there any way to do it with the internal clock?
Logged

Pages: [1] 2   Go Up
Jump to: