PWM frequency library

This would be my first attempt at using a library like this.
Can someone explain the limitations of creating a specific frequency when using this library?
I keep seeing the phrase"resolution" tossed around but I cannot really grasp what that means relative to a clock signal.
I am trying to generate two clocks of 104 khz and 165khz on a UNO.
When I run the following code I get close but there is some deviation.
Tweaking the two frequency variables slightly does nothing or it makes it jump past my target freq.
Per my oscilloscope I am getting 105.290 khz & 166.710 khz. This is within 1.25% of my target and would probably be fine for my application but I really want to know what I would have to do if my tolerances needed to be tighter.
Is this expected behavior or is my programming a hot mess?

#include <PWM.h>
#include <FastLED.h>

#define LED_PIN     4
#define NUM_LEDS    300
#define BRIGHTNESS  64
#define LED_TYPE    WS2811
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
#define UPDATES_PER_SECOND 300


//------

int fosc1 = 9;                // the pin that the timer1 is attached to
int fosc2 = 3;                // the pin that the timer2 is attached to
int32_t frequency1 = 165000;   //frequency (in Hz)
int32_t frequency2 = 104000;   //frequency (in Hz) 

//-------

CRGBPalette16 currentPalette;
TBlendType    currentBlending;

extern CRGBPalette16 myRedWhiteBluePalette;
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;


void setup() {
    delay( 3000 );     // power-up safety delay
    FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
    FastLED.setBrightness(  BRIGHTNESS );
    
    currentPalette = RainbowColors_p;
    currentBlending = LINEARBLEND;

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

    //sets the frequency for the specified pin
    bool success1 = SetPinFrequencySafe(fosc1, frequency1);
    bool success2 = SetPinFrequencySafe(fosc2, frequency2);
  
    //if the pin frequency was set successfully, turn pin 13 on
    if(success1 && success2){
    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);
  }
    
    pwmWrite(fosc1, 128);
    pwmWrite(fosc2, 128);
    
}


void loop()

Resolution is basically how close you can come to the frequency you are looking at delivering.
How close you can get depends on the clock speed of your arduino, how high the target frequency is (you play with the prescaler) and which timer you use (8 bit or 16 bit)

Go back and Read the first page of this discussion, especially post #7

Hi everyone,

I want to use the library on my Mega 2560 to generate a PWM of 20kHz. I have been able to do so on my Uno but my waveform is getting distorted in Mega. I will really appreciate some help in understanding where I am going wrong.

The code I used is as follows:

#include <PWM.h>


void setup()
{
  // put your setup code here, to run once:
  pinMode(3, OUTPUT);
  InitTimersSafe();
  bool success = SetPinFrequency(3,20000);
}

void loop() 
{
  // put your main code here, to run repeatedly:
  pwmWrite(3, 127);
  
}

Hi,
I am using this library to change frequency using pin9 on an arduino mini pro and is working fine but I want to ask if is possible to change pwm resolution using this library?

I mean now I can set values between 1 to 255 for duty cycle, that means 8 bits. Can this be somehow changed to have 10 bits (1024 values) or even more? Is there any way doing that with this library?

Thank you

Well this lib for sure aint working anymore, even if I fixed the issue according to post #135. I could get one timer working at the same time, after the fix I got another working, but then I couldnt get the first working.

Hi,

I am thinking about converting an old inverter welder to use an Arduino to switch on/off the two IGBT:s that control the welding current by sending a positive or a negative voltage to a transformer, to create the MMA welding current.

The idea is to start with just mimicking the existing welder control electronics that gives a PWM signal at 19 kHz. This works fine with the pwm.h library. However, I need to control two IGBT:s in the welder with two pins on the Arduino in such a way that when one pin goes high the other one goes low. So essentially, I want to invert the time axis for the output to one of the two PWM pins. Any idea about if this can be done by tweaking the library?

An other way to do it would to phase shift one of the signals, but then the phase shift has to be recalculated when the duty cycle is changed, since the two pins must never be high simultaneously.

If I can get this to work the next step would be to fine tune the welder behaviour with the welding current as input data.

Hello. does anyone know if this library is still usable? I found this webpage DIY Arduino Waveform Generator or Function Generator

on how to build an adjustable waveform generator. And then stumbled onto this topic which seems to use the same library. Tho i'm thinking someone else used the library to make this waveform generator webpage.

I've been able to install the library and upload the code, which was posted on the bottom of the website. I had to make a couple minor changes to accept my LCD screen, but that's it. It'll upload fine, but it's like the encoder isn't working, and it's new, and identical to the one he used. but for some reason the code isn't working for me. The frequency multiplier seems to change on it's own, starts at 1, then 10, 100, 1000, and then stays there. If i turn the encoder, sometimes it will register and make the adjustment.... but i'm lucky to get it to change at all.

here's the code i'm using. any ideas on what could be the problem. i know it mentions modifying the internal timers, and didn't know if that's something that my arduino IDE 1.8.8 is blocking or effecting somehow... or if there's something else going on.

one thing i've noticed, tho not sure if it's related. when i've added the library, #include <PWM.h>, the PWM isn't highlighted like rest of the libraries are. so i wasn't sure if that's because it's a non-arduino approved library, or if it's not actually uploading the library.

thanks

#include <PWM.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,20,4);



int Encoder_OuputA  = 11;
int Encoder_OuputB  = 12;
int Encoder_Switch = 10;
int Previous_Output;
int multiplier = 1;

double angle = 0;
double increment = 0.2;

const int signal_pin = 9;  
const int Sine_pin = 5;
int32_t frequency; //frequency to be set
int32_t lower_level_freq = 1; //Lowest possible freq value is 1Hz
int32_t upper_level_freq = 100000; //Maximum possible freq is 100KHz

void setup()
{
  lcd.init(); //Initialise  LCD
  lcd.backlight();
  lcd.setCursor(0, 1);
  lcd.print("Signal Generator"); //Intro Message line 1
  
  lcd.print("-CircuitDigest "); //Intro Message line 2
  delay(2000);
  lcd.clear();
  lcd.print("Freq:00000Hz");
  lcd.setCursor(0, 1);
  lcd.print("Inc. by: 1 ");
  
  Serial.begin(9600); //Serial for debugging
  InitTimersSafe(); //Initialize timers without disturbing timer 0
  
//pin Mode declaration 
  pinMode (Encoder_OuputA, INPUT);
  pinMode (Encoder_OuputB, INPUT);
  pinMode (Encoder_Switch, INPUT);

  Previous_Output = digitalRead(Encoder_OuputA); //Read the inital value of Output A

 attachInterrupt(0,generate_sine,CHANGE);
}

 

void loop()
{
  if (digitalRead(Encoder_OuputA) != Previous_Output)
   { 
     if (digitalRead(Encoder_OuputB) != Previous_Output) 
     { 
       frequency = frequency + multiplier;
      Serial.println(frequency);
       pwmWriteHR(signal_pin, 32768); //Set duty cycle to 50% by default -> for 16-bit 65536/2 = 32768
       SetPinFrequencySafe(signal_pin, frequency);
       lcd.setCursor(0, 0);
       lcd.print("Freq:     Hz");
       lcd.setCursor(5, 0);
       lcd.print(frequency);
     } 
     else 
     {
       frequency = frequency -   multiplier;
       
Serial.println(frequency);
       pwmWriteHR(signal_pin, 32768); //Set duty cycle to 50% by default -> for 16-bit 65536/2 = 32768
       SetPinFrequencySafe(signal_pin, frequency);
       lcd.setCursor(0, 0);
       lcd.print("Freq:     Hz");
       lcd.setCursor(5, 0);
       lcd.print(frequency);
     }
   }

      if (digitalRead(Encoder_Switch) == 0)
   {
   multiplier = multiplier * 10;

   if (multiplier>1000)
   multiplier=1;
   
  Serial.println(multiplier);
   lcd.setCursor(0, 1);
   lcd.print("Cng. by:     ");
   lcd.setCursor(8, 1);
   lcd.print(multiplier);
   
   delay(500);
   while(digitalRead(Encoder_Switch) == 0);
   }

   Previous_Output = digitalRead(Encoder_OuputA);  
 
}

void generate_sine()
{
   double sineValue = sin(angle);
   sineValue *= 255;
   int plot = map(sineValue, -255, +255, 0, 255);
   Serial.println(plot);
   analogWrite(Sine_pin,plot);
   angle += increment; 

   if (angle > 180)
   angle =0;
}

I'd written something not to far (without the Sine Wave stuff) that will work with an I2C LCD, a rotary encoder and switch and the PWM Frequency library.

rotating the know increases or decreases the frequency and clicking on the knob will switch the steps between 1,10,100, 1k, 10k, 100k, display the value you set on the 1st line of the LCD and the actual frequency the UNO achieves on the second line.

I've just tested it again after recompiling with the current IDE and checked on my oscilloscope and it seems to work fine all the way to 2MHz.

here is the code:

// -----------------------------------------
// written for Arduino UNO, should work on a Mega is you switch the frenquencyPin to 11
// Leveraging multiple libraries (see links below)
// Author: J-M-L for Arduino Forum (https://forum.arduino.cc/index.php?action=profile;u=438300)
// originally posted at  https://forum.arduino.cc/index.php?topic=117425.msg4309683#msg4309683
//
// Pin 0 & 1 : left unused for Serial
// Pin 2 to rotary encoder DT  (will use interrupts)
// Pin 3 to rotary encoder CLK (will use interrupts)
// Pin 4 to rotary encoder SW
// Pin 5
// Pin 6
// Pin 7
// Pin 8
// Pin 9 The Pin exhibing the frequency
// Pin 10
// Pin 11
// Pin 12
// Pin 13
// Pin A0
// Pin A1
// Pin A2
// Pin A3
// Pin A4 to I2C SDA (LCD)
// Pin A5 to I2C SCL (LCD)
// -----------------------------------------

#include <PWM.h> // https://github.com/terryjmyers/PWM (https://forum.arduino.cc/index.php?topic=117425.msg883455#msg883455)

// As frequency increases, resolution will decrease and you won't get the exact match
const long MinFrequency = 0L; // 0 Hz
const long MaxFrequency = 2000000L; // 2 MHz

const byte frenquencyPin = 9;

#include <LiquidCrystal_I2C.h> // https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
LiquidCrystal_I2C lcd(0x27, 16, 2); // 16 cols, 2 lignes. I2C address is 0x27. connect LDC's SDA on A4, SCL on A5

#include <Encoder.h> // https://www.pjrc.com/teensy/td_libs_Encoder.html
Encoder rotaryEncoder(2, 3); // connect pin D2 to Encoder's DT & D3 to Encoder's CLK)

#include <simpleBouton.h> // http://forum.arduino.cc/index.php?topic=375232.0  @bricoleau efficient button's library.
simpleBouton encoderSwitch(4);// connect pin D4 to Encoder's SW

long currentFrequency;
long currentRotaryValue;

enum : long {x1 = 1L, x10 = 10L, x100 = 100L, x1000 = 1000L, x10000 = 10000L, x100000 = 100000L} stepMultiplier = x1;

void displayFrequencyTarget(long f)
{
  char freqMessage[20];
  dtostrf(f, 7, 0, freqMessage); // right aligned, white space padding 7 positions to accomodate from 0 to 2000000
  strcat(freqMessage, "Hz");
  Serial.println(freqMessage);
  lcd.setCursor(0, 0);
  lcd.print(freqMessage);
}

void displayActualFrequency()
{
  char freqMessage[20];
  dtostrf(Timer1_GetFrequency(), 7, 0, freqMessage); // right aligned, white space padding 7 positions to accomodate from 0Hz to 2000000Hz
  strcat(freqMessage, "Hz");
  Serial.println(freqMessage);
  lcd.setCursor(0, 1);
  lcd.print(freqMessage);
}

void displayStepMultiplier()
{
  char multMessage[20];
  switch (stepMultiplier) {
    case x1: strcpy(multMessage,      "   1"); break;
    case x10: strcpy(multMessage,     "  10"); break;
    case x100: strcpy(multMessage,    " 100"); break;
    case x1000: strcpy(multMessage,   "  1k"); break;
    case x10000: strcpy(multMessage,  " 10k"); break;
    case x100000: strcpy(multMessage, "100k"); break;
  }
  Serial.println(multMessage);
  lcd.setCursor(12, 0);
  lcd.print(multMessage);
}

void setup()
{
  Serial.begin(115200);         // initialize Serial connection
  lcd.begin();                  // initialize the LCD
  lcd.backlight();

  currentRotaryValue = 0;// initialize the rotary encoder
  rotaryEncoder.write(currentRotaryValue);

  InitTimersSafe(); //initialize all timers except for 0, to save time keeping functions
  currentFrequency  = 0L;
  displayFrequencyTarget(currentFrequency);
  displayStepMultiplier();
  pwmWriteHR(frenquencyPin, 32768u);
  SetPinFrequency(frenquencyPin, currentFrequency);  //setting the frequency
}

void loop()
{
  // modify step factor
  if (encoderSwitch) {
    switch (stepMultiplier) {
      case x1: stepMultiplier = x10; break;
      case x10: stepMultiplier = x100; break;
      case x100: stepMultiplier = x1000; break;
      case x1000: stepMultiplier = x10000; break;
      case x10000: stepMultiplier = x100000; break;
      case x100000: stepMultiplier = x1; break;
    }
    displayStepMultiplier();
  }

  long newRotaryValue = rotaryEncoder.read() >> 1;   // my rotary delivers 2 ticks per step, others delivers 4 in which case do >>2

  if (newRotaryValue != currentRotaryValue) { // we turned the knob
    long newFrequency = currentFrequency + (newRotaryValue - currentRotaryValue) * stepMultiplier;
    currentRotaryValue = newRotaryValue;
    newFrequency = constrain(newFrequency, MinFrequency, MaxFrequency);

    if (newFrequency != currentFrequency) {
      currentFrequency = newFrequency;
      displayFrequencyTarget(currentFrequency);
      pwmWriteHR(frenquencyPin, 32768u);
      if (SetPinFrequencySafe(frenquencyPin, currentFrequency)) displayActualFrequency();
    }
  }
}

Note that the library I use for the rotary encoder connected to those pins will switch to interrupt based tick capture, so you can't use those pins for the sine wave of the example. The library works though with only 1 pin on interrupt (or none) so you could free up pin 2 to generate the the Sine wave.

of course issuing ISR at 2MHz would put quite a toll on your UNO and so you should not go that far then.

I tried to compile the code and it's not letting me because i have a nano. But i do have a spare uno and mega 2560 i'll try it on later.

i was able to play around with the code i posted yesterday, and got it to do a little more. But there is something wrong somewhere as the rotary encoder isn't working like it's supposed too. but i'm gonna continue working on it on my free time to see if i can get it working.

For the moment i'm just crudely coding a PWM so i can run a mosfet to control a homemade hot air soldering gun using a gas drier igniter element and a small air pump so i can repair a computer motherboard. but i would like to get a working frequency generator so i can test some transformers i want to make in the future.

wildcat99s:
I tried to compile the code and it's not letting me because i have a nano.

It should compile just fine (I just did), you need to install the 4 libraries I'm using:

#include <PWM.h> // https://github.com/terryjmyers/PWM (https://forum.arduino.cc/index.php?topic=117425.msg883455#msg883455)
#include <LiquidCrystal_I2C.h> // https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
#include <simpleBouton.h> // http://forum.arduino.cc/index.php?topic=375232.0  @bricoleau efficient button's library.
#include <Encoder.h> // https://www.pjrc.com/teensy/td_libs_Encoder.html

don't try to reinvent the wheel - focus on solving your specific use case and leverage an existing Rotary encoder library. This one is pretty stable and proven#include <Encoder.h> // https://www.pjrc.com/teensy/td_libs_Encoder.htmlThat's what I have used in the example above

once your stuff work, if you want to use your own code for the encoder then you'll have a "simple" step

Did anyone ever have any luck getting this to work on an Atmega1284? I'm stuck at this point.

Good morning all,
I would have liked to know if it is possible to disable the PWM to be able to manage the output for something else and to be able to activate it after.
Can be: success = SetPinFrequencySafe (Output, 0);
then: success = SetPinFrequencySafe (Output, Frequency);
for example.

Very good bookstore in any case.
Thank you.

Hi everyone,

I am using the 0.5 version of this lib on an Mega 1280. Im am trying to output 10kHz PWM signals on 6 different pins, without interfering with Timer0. So I chose pins: 2,3,5 (timer3) and 6,7,8 (timer4).
However, when I run the following without writing PWM to pin 9, theres no PWM signal on Pin 5.

I have no idea why this is the case, but i thought i migth aswell post about it, so if anyone has a similar problem they can refer to this.

#include <PWM.h>

const int in_U = 2;
const int in_V = 3;
const int in_W = 5;
const int in_X = 6;
const int in_Y = 7;
const int in_Z = 8;


void setup() {

  pinMode(in_U, OUTPUT); 
  pinMode(in_V, OUTPUT); 
  pinMode(in_W, OUTPUT); 
  pinMode(in_X, OUTPUT); 
  pinMode(in_Y, OUTPUT); 
  pinMode(in_Z, OUTPUT);
  
  pinMode(9, OUTPUT);

  InitTimersSafe();
  SetPinFrequencySafe(in_U,10000); 
  SetPinFrequencySafe(in_V,10000);
  SetPinFrequencySafe(in_W,10000);
  SetPinFrequencySafe(in_X,10000); 
  SetPinFrequencySafe(in_Y,10000);
  SetPinFrequencySafe(in_Z,10000);
  
  SetPinFrequencySafe(9,10000);
}

void loop() {
    pwmWrite(in_U, 128);
    pwmWrite(in_V, 128);
    pwmWrite(in_W, 128);
    pwmWrite(in_X, 128);
    pwmWrite(in_Y, 128);
    pwmWrite(in_Z, 128);

    pwmWrite(9, 128);

Hi everyone

I have a question , about the use of the library?
I have aproject where i currently use the nrf24l01 library to communicate with 2 uno's.
One uno is playing the role of the remote controller, and the other is used to move two dc motors through PWM.
One of the motors need higher PWM frequency, that the standard that uno has.
The question is am planning to sue the PWM library found here.Is this play any roll on my connection betwwen the 2 arduino's , due to the change of timer prescales.
Currently nrf24l01 is connected to Pin 7,8,10,11,12.
Thanks beforehand for your answers and help.

Hello there,
I need help with something. I am a user due to Arduino mega . I cannot generate PWM in DUE. The pwm.h library does not work. I need PWM from 1Hz to 3000 Hz, which can be adjusted continuously. this PWM will be set in the loop. can you send me a sample.
e-mail: hasanturgut@kuark.com.tr

Hi,

I wanted to know if the library is compatible with arduino nano every and if there is a pwm library for it ?

Thanks

@mktime

PLEASE DO NOT HIJACK / NECRO POST !

Could you take a few moments to Learn How To Use The Forum.
Other general help and troubleshooting advice can be found here.
It will help you get the best out of the forum in the future.

Hi RunnerUp,

Great Library! Works like a charm on the Nano. Even verified the accuracy of both the frequency and the DutyCycle.

Now the big question (could go out to everyone as well). My script is getting bigger by the day and I still need to add a rotary pot&button User Interface. The infamous 10lbs of stuff in a 5lb bag!! Not enough space. I believe all the code is transferable to the Every except the PWM.h libary.

I've done the search for PWM & Every and there are attempts - some good, some wild. But, none are as elegant and simple to use as yours.

Would it be possible to update (or new version) to run on the 4809 Every? Could call it PWM-Every.h.

Thanks,
Dave

I can't compile this on any Arduino SAMD:

*: undefined reference to `InitTimersSafe()'
*: undefined reference to `SetPinFrequencySafe(signed char, unsigned long)'
collect2.exe: error: ld returned 1 exit status
Using library pwm at version 5.0 in folder: *\Documents\Arduino\libraries\pwm

This is the same on all SAMD boards.

Same sketch for AVR compiles without issues.

Any suggestions?

bergstar:
Any suggestions?

it's meant for AVR only

may be you can read this thread for ideas (or here too)