PWM frequency library

one question, how do I determine the PWM range fora a given pin with a modified frequency. Take for example my sketch below that uses 20khz on pin 9. Normally the values 0 256 work fine without the mod but I had to raise it to 256 to 512..it doesn't go as high as 512 more like in the 400 range..just want to know what I'm missing to understand that and if there is an easy calculation.

// simple move forward and backward one motor on the l298n using pins 12 13 9/ 9 being PWM
#include 
int ENA = 9;
int IN1 = 12;
int IN2 = 13;
int32_t frequency = 20000; //frequency (in Hz)

void setup ()
{
  Serial.begin(9600);
  InitTimersSafe(); 
  bool success = SetPinFrequencySafe(ENA, frequency);
  pinMode (ENA, OUTPUT);
  pinMode (IN1, OUTPUT);
  pinMode (IN2, OUTPUT);
}

void test_motor_1 ()
{
  for (int i = 256; i < 512; i++)
  {
    digitalWrite (IN1, HIGH);
    digitalWrite (IN2, LOW);
    analogWrite (ENA, i);
    delay (30);
    Serial.println(i);
  }

  delay (100);
  digitalWrite (IN1, LOW);
  
  for (int i = 256; i < 512; i++)
  {
    digitalWrite (IN1, LOW);
    digitalWrite (IN2, HIGH);
    pwmWrite  (ENA, i);  //was analogWrite
    delay (30);
   Serial.println(i);
  }

  delay (100);
  digitalWrite (IN2, LOW);
}

void loop()
{
  test_motor_1();
}

runnerup: I discovered in a recent project involving an Arduino microcontroller that there was no method to change PWM frequency without directly manipulating low-level memory. As far as I can Google, there is no general purpose library that can change PWM frequencies on Arduino Microcontrollers. The internet is full of partial examples and code snippets for changing PWM frequency, but in the end I still had to consult the 400+ page sec sheet (http://www.atmel.com/Images/doc2549.pdf) to get the code for my Mega functional. It is my speculation that the programmers at Arduino have not released any methods for changing PWM frequency because it is difficult to write a simple and intuitive wrapper for hardware timers that wont run the risk of confusing a beginner (the whole draw to Arduino in the first place). The hardware is has very specific limitations that present themselves in odd ways. Allow me to share a few:

  • PWM behavior is determined by integrated components called timers. Every timer has two to four channels. Each channel is connected to a pin. Changing one pin's frequency requires changes to the timer it connects to. Which in turn changes the frequency of other pins connected to that same timer.
  • Timer 0 is usually used for Arduino's time keeping functions, (i.e. the millis() function). Changing the frequency on timer 0 will break the time keeping functions you may or may not be using in other parts of your project
  • There are two types of timer, 8bit and 16bit. Long story short, they have nuances that make common code difficult to implement without limiting one or the other.
  • Creating custom frequencies (beyond messing with the prescaler) with an 8bit timer requires the sacrifice of one channel. In other words, each 8bit timer that creates a custom frequency loses the ability to perform PWM on one pin (the one connected to the A channel to be more precise). All Arduinos except the Leonardo have two 8bit timers, meaning that setting all timers to a particular frequency will sacrifice a total of two pins on said Ardiuno.

Regardless of this, I still felt it would still be worth while to make a library/wrapper for hardware timers so that I, and anyone else who chooses to use this, will not have to spend quite as many hours needlessly digging through blocks of bug prone bit wise and preprocessor slurry.

The library has five global functions:

| InitTimers() | Initializes all timers. Needs to be called before changing the timers frequency or setting the duty on a pin | | - | - | | InitTimersSafe() | Same as InitTimers() except timer 0 is not initialized in order to preserve time keeping functions | | pwmWrite(uint8_t pin, uint8_t val) | Same as 'analogWrite()', but it only works with initialized timers. Continue to use analogWrite() on uninitialized timers | | SetPinFrequency(int8_t pin, int32_t frequency) | Sets the pin's frequency (in Hz) and returns a bool for success | | SetPinFrequencySafe(int8_t pin, int32_t frequency) | Same as SetPinFrequency except it does not affect timer 0 |

The library also has five functions for each Timer 'object'. I could not get the code size down to what I felt was reasonable so I ditched C++ classes and did some fancy macro work instead. Each of these functions are technically preprocessor macros with nice self explanatory names that swap out for more cryptic functions inside the library header just before compile time. For timer 1 the functions are:

| Timer1_GetFrequency() | Gets the timer's frequency in Hz | | - | - | | Timer1_SetFrequency(int frequency) | Sets the timer's frequency in Hz | | Timer1_GetPrescaler() | Gets the value (not bits) of the prescaler. Don't know what this means? Don't worry about it, just use SetFrequency(int frequency) | | Timer1_SetPrescaler(enum value) | Sets the prescaler* | | Timer1_GetTop() | Gets the timer register's maximum value | | Timer1_SetTop(int top) | Sets the timer register's maximum value | | Timer1_Initialize() | Initializes the timer |

*The prescaler is inconsistent among different timers. I figured using enumerators was the best solution because most types of invalid input will be caught at compile time. For a normal timer, use one of these as a parameter: ps_1, ps_8, ps_64, ps_256, ps_1024. If those give a type error, then the timer you are using is one of the inconsistent ones, and you should use psalt_1, psalt_8, psalt_32, psalt_64, psalt_128, psalt_256, or psalt_1024 instead.

If you want to mess with a different timer, just change the number (i.e Timer2_GetFrequency() to get timer 2's frequency). It is up to your discretion whether or not you want to use the timer specific functions. The global ones should be good enough for most situations.

With this Library, 16bit timers have a frequency range from 1Hz to 2MHz. 8bit timers have a range from 31Hz to 2MHz. As the frequency becomes larger, the smaller the range power duties for a pin becomes. It is technically possible to push the frequency to 8MHz, but the range of possible power duties get stupidly small by that point. To be sure the frequency was correctly set, be sure to check the return value. If you don't want to sacrifice any 8bit PWM pins, don't call the initialize function for that timer, try changing the prescaler to manipulate frequency instead. There are many tutorials on how the prescaler affects timers and this library contains methods that make easier and less bug prone to manipulate. So far, I have tested this library on an Uno and a Mega. [u]This library should be compatible with all Arduinos except the Leonardo and Due[/u]. If you have an Arduino that is not a Mega or Uno, please test it and tell me how it went. If somebody has an oscilloscope on hand to verify the frequencies being generated are correct, that would also be helpful.

For now, consider this library to be in beta. Developments on this library are described in later posts. Here are some of the current features of this library:

  • Wraps timer specific properties (such as timer top and prescaler) with functions
  • Has pin based (timer agnostic) functions
  • Has functions for getting and setting frequency at the timer level and pin level
  • Has tools for measuring timer resolution at the timer level and pin level

The latest is version .05 link: http://code.google.com/p/arduino-pwm-frequency-library/downloads/list

There are technically libraries out there that allow you to set the PWM frequency. They are, however, typically labeled as audio "tone" libraries. It doesn't matter if the library is designed for audio, it's still just a PWM library. I've written some of these libraries, some of which will output PWM signals at up to the megahertz range.

Tim

Do you still need someone to verify correct frequencies ? I set 100 Hz and got 99.6995 Hz so I'm guessing your pretty spot on.

Any thoughts regarding why you can't use digital pin 11 with timer2, using arduino uno? The oscilloscope doesn't output anything

There are technically libraries out there that allow you to set the PWM frequency. They are, however, typically labeled as audio "tone" libraries. It doesn't matter if the library is designed for audio, it's still just a PWM library. I've written some of these libraries, some of which will output PWM signals at up to the gigahertz range.

This interests me. Particularly the part about the gigahertz range. I haven't heard of this before. Could you point me to somewhere that explains how this is done?

The UNO runs at 16MHz so at best you will get 16MHz with a 50% duty, gigaherz is pure imagination.

That is what I had thought, but if it isn't a typo... if it's possible...

3.21 Jigahertz! Tom!

TanHadron:

There are technically libraries out there that allow you to set the PWM frequency. They are, however, typically labeled as audio “tone” libraries. It doesn’t matter if the library is designed for audio, it’s still just a PWM library. I’ve written some of these libraries, some of which will output PWM signals at up to the gigahertz range.

This interests me. Particularly the part about the gigahertz range. I haven’t heard of this before. Could you point me to somewhere that explains how this is done?

Sorry, must have been drunk, I meant MEGAhertz, not gigahertz.

One of my tone libraries (toneAC) does PWM control of two pins alternating at up to 2.66 MHz with an ATmega running at 16MHz.

Official site
Arduino Playground
Support forum

Sorry about the confusion.

Tim

Hi!! I just want to say, thanks for the library!!!, it seems to be very helpful, because, as you said, you did found a necessity, and well, you are now giving us a solution... Well, then, I'm an Arduino begginer ^_^, and I'm developing some project that involves the use of Ardu...and also the PWM management, thus, its frequency. I did download your library, but, when I compile the first example, in the IDE message area says: "PWM_lib_example.cpp: In function ‘void setup()’: PWM_lib_example:23: error: ‘InitTimersSafe’ was not declared in this scope PWM_lib_example:26: error: ‘SetPinFrequencySafe’ was not declared in this scope PWM_lib_example.cpp: In function ‘void loop()’: PWM_lib_example:38: error: ‘pwmWrite’ was not declared in this scope"

Also I was reading some comments, that it actually works perfectly =(...what you think could be the problem?? It seems like the IDE does not detect the #include ... Thanks!!

breslopez: Hi!! I just want to say, thanks for the library!!!, it seems to be very helpful, because, as you said, you did found a necessity, and well, you are now giving us a solution... Well, then, I'm an Arduino begginer ^_^, and I'm developing some project that involves the use of Ardu...and also the PWM management, thus, its frequency. I did download your library, but, when I compile the first example, in the IDE message area says: "PWM_lib_example.cpp: In function ‘void setup()’: PWM_lib_example:23: error: ‘InitTimersSafe’ was not declared in this scope PWM_lib_example:26: error: ‘SetPinFrequencySafe’ was not declared in this scope PWM_lib_example.cpp: In function ‘void loop()’: PWM_lib_example:38: error: ‘pwmWrite’ was not declared in this scope"

Also I was reading some comments, that it actually works perfectly =(...what you think could be the problem?? It seems like the IDE does not detect the #include ... Thanks!!

The compiler is telling you that it can't find the functions you are calling. Assuming your includes are correct (which is the case if you are using an example), then you didn't add the library to the 'libraries' folder.

If you don't understand how libraries work in the Arduino environment try looking at this: http://www.arduino.cc/en/Hacking/Libraries

Hi, thank you so much for your help, I already solve the problem....now, I'm traying to manipulate the "frequency" value from the Serial monitor...but I can't make it work, here's the code: PD: Any help, THANKS!!!

/************************** TEC -2013 **************************

Este sketch es una variacion del PWM_lib_example de la biblioteca PWM, donde se controla la frecuencia desde el monitor serial del IDE, dando con ello un poco mas de practicidad, y mayor manejo sobre la frecuencia deseada.


*/

include

int brightness = 0; //how bright the LED is. int fadeAmount = 5; //how many points to fade the LED by

void setup() { //Inicializa todos los timers del Arduino, excepto el 0, para mantener las funciones de tiempo del micro Serial.begin(9600); InitTimersSafe();

}

void loop() { int32_t frequency; if (Serial.available()) {

frequency = Serial.read(); SetPinFrequency(led, frequency);

} pwmWrite(led, brightness);

brightness = brightness + fadeAmount;

if (brightness == 0 || brightness == 255) { fadeAmount = -fadeAmount ; }

delay(30);

}

I have done the following program (as initial steps for a thermostat program)

#include 



int T;
int32_t frequency = 500; //initialize the pwm output at 100Hz

void setup(){
  InitTimersSafe();
  SetPinFrequencySafe(11, frequency);
}


void loop(){

T = analogRead(0);

pwmWrite(11, 50); // write the duty to the output

delay(2000);

}

Nothing happens, other than the output being full on. I can't use the standard PWM as it makes the fan (and powersupply transformer) hum. Mind you even the standard analogwrite has stopped working or does the library do that ?

I only can said thanks runnerup!

breslopez: Hi, thank you so much for your help, I already solve the problem....now, I'm traying to manipulate the "frequency" value from the Serial monitor...but I can't make it work, here's the code: PD: Any help, THANKS!!!

/************************** TEC -2013 **************************

Este sketch es una variacion del PWM_lib_example de la biblioteca PWM, donde se controla la frecuencia desde el monitor serial del IDE, dando con ello un poco mas de practicidad, y mayor manejo sobre la frecuencia deseada.


*/

include

int brightness = 0; //how bright the LED is. int fadeAmount = 5; //how many points to fade the LED by

void setup() { //Inicializa todos los timers del Arduino, excepto el 0, para mantener las funciones de tiempo del micro Serial.begin(9600); InitTimersSafe();

}

void loop() { int32_t frequency; if (Serial.available()) {

frequency = Serial.read(); SetPinFrequency(led, frequency);

} pwmWrite(led, brightness);

brightness = brightness + fadeAmount;

if (brightness == 0 || brightness == 255) { fadeAmount = -fadeAmount ; }

delay(30);

}

Hi! I have the same prolem as you. What did you do to solve it?

Chino76:

breslopez: Hi, thank you so much for your help, I already solve the problem....now, I'm traying to manipulate the "frequency" value from the Serial monitor...but I can't make it work, here's the code: PD: Any help, THANKS!!!

/************************** TEC -2013 **************************

Este sketch es una variacion del PWM_lib_example de la biblioteca PWM, donde se controla la frecuencia desde el monitor serial del IDE, dando con ello un poco mas de practicidad, y mayor manejo sobre la frecuencia deseada.


*/

include

int brightness = 0; //how bright the LED is. int fadeAmount = 5; //how many points to fade the LED by

void setup() { //Inicializa todos los timers del Arduino, excepto el 0, para mantener las funciones de tiempo del micro Serial.begin(9600); InitTimersSafe();

}

void loop() { int32_t frequency; if (Serial.available()) {

frequency = Serial.read(); SetPinFrequency(led, frequency);

} pwmWrite(led, brightness);

brightness = brightness + fadeAmount;

if (brightness == 0 || brightness == 255) { fadeAmount = -fadeAmount ; }

delay(30);

}

Hi! I have the same prolem as you. What did you do to solve it?

I'm not sure how the other guy solved it. But this is how I solved it: read http://arduino.cc/en/Guide/Libraries thoroughly the library .h and/or .cpp files should be in their own folder and no more than one directory level deep. see the description on the bottom of the page i linked to. once I rearranged my files, it worked. Just make sure that your .h or .cpp file is in its own folder in the library folder, and not in subdirectories under its own folder

for 'local' h and cpp files the format is #include "myFile.h" instead of #include .. When I have library issues I move everything to the sketch folder and change the left and right 'arrows' to double quotes for the included files that are in the sketch folder... Works for me quite well, YMMV...

Doc

Hi.. I am getting an error InitTimersSafe() was not declared in this scope while running this code .

#include "PWM.h"

//use pin 11 on the Mega instead, otherwise there is a frequency cap at 31 Hz
int led = 9;                // the pin that the LED is attached to
int brightness = 0;         // how bright the LED is
int fadeAmount = 5;         // how many points to fade the LED by
int32_t frequency = 35; //frequency (in Hz)

void setup()
{
  //initialize all timers except for 0, to save time keeping functions
  InitTimersSafe(); 

  //sets the frequency for the specified pin
  bool success = SetPinFrequencySafe(led, frequency);
  
  //if the pin frequency was set successfully, turn pin 13 on
  if(success) {
    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);    
  }
}

void loop()
{
  //use this functions instead of analogWrite on 'initialized' pins
  pwmWrite(led, brightness);

  brightness = brightness + fadeAmount;

  if (brightness == 0 || brightness == 255) {
    fadeAmount = -fadeAmount ; 
  }     
  
  delay(30);      
}

I have already added the PWM frequency library still i am getting the error. I am using Arduino 1.0.5 version

Some one please help me...

I'm trying to use this library to create a variable frequency quadrature output. I have confirmed I can set two outputs with the same frequency and different duty cycles but is there a way to offset on output by 1/2 pulse width? I am an arduino/programming/microcontroller noob. I tried spacing pwmWrite()s out with a delay() but it did not work :(

ADI89: Some one please help me...

Kind of an old post and you may have figured this out but I compiled your code just fine. Double check your library was added properly.

Hey guys, i am trying to control a dc motor with the pwm library (Arduino mega 2560) but the frequency that is generated it's too low because the motor doesn't move. I tried with 20KHZ frequency and didn't work. Here is my code:

include

int motor = 11 , valor_adc , tension; int32_t frequency = 20000; void setup(){ InitTimersSafe(); bool success = SetPinFrequencySafe(motor,frequency); } void loop(){ valor_adc=0; valor_adc=analogRead(A0); tension=valor_adc/4; pwmWrite(motor,tension); delay(30); }