I am working on a project where I am using 2 PWM signals and want to set the frequency. I am looking to change the frequency from 100Khz up to around 160Khz, possibly as high as 200Khz.
I am using a DF Robot MEGA 2560 board with 16Mhz clock and the ATMega2560 chip. I also have an oscilloscope to verify output frequencies.
I found some code and modified it to make it simpler for testing purposes and am using the TimerOne library and pins 11 and 12 on Timer 1 (16 bit Timer).
Problem:
When I try to change the frequency to say 110Khz I get 111Khz and if I try to get 120 I get 125Khz. I believe this has to do with the ICR1 setting in the library but am not sure. It seems like it is only taking a
whole number and not a decimal. I don't know if ICR1 can accept decimals or not. I am also not sure if I need to modify the library or make some adjustments in my code. I am thinking the ICR1 is limiting my accuracy. I was thinking I could just change the setPeriod to change the frequency and that works but that frequencies are limited.
I have spent about 3 days searching forums and reading through the Atmega PDF document. The parts about the registers are a bit confusing to me and most examples I found weren't done for a Mega2560 chip.
Future Goals:
Have 2 PWM signals on Timer1 at 120Khz and 2 PWM signals on another timer (thinking Timer3) at 150Khz running at the same time.
Thanks for any advice or help!
#include <TimerOne.h>
int pwm_on1 = 11;
int pwm_on2 = 12;
float pwm_duty_cycle1 = 512;
float pwm_duty_cycle2 = 100;
float period_freq = 120000;
void setup()
{
Timer1.initialize(period_freq);
Timer1.pwm(11, pwm_duty_cycle1);
Timer1.pwm(12, pwm_duty_cycle2);
}
void loop()
{
static float val = 115000;
Timer1.pwm(11, pwm_duty_cycle1);
Timer1.pwm(12, pwm_duty_cycle2);
period_freq = 1000000.0 / val;
Timer1.setPeriod(period_freq);
}
//////////////////////////////////////////////////////////////////////////////////
Here is part of the TimerOne.h file that I think is relevant.
I can post the whole thing if needed.
This is not part of my test code. Just posting a part of it for easy access.
#ifndef TimerOne_h_
#define TimerOne_h_
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "config/known_16bit_timers.h"
#define TIMER1_RESOLUTION 65536UL // Timer1 is 16 bit
// Placing nearly all the code in this .h file allows the functions to be
// inlined by the compiler. In the very common case with constant values
// the compiler will perform all calculations and simply write constants
// to the hardware registers (for example, setPeriod).
class TimerOne
{
#if defined(__AVR__)
public:
//****************************
// Configuration
//****************************
void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
TCCR1B = _BV(WGM13); // set mode as phase and frequency correct pwm, stop the timer
TCCR1A = 0; // clear control register A
setPeriod(microseconds);
}
void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
const unsigned long cycles = (F_CPU / 2000000) * microseconds;
if (cycles < TIMER1_RESOLUTION) {
clockSelectBits = _BV(CS10);
pwmPeriod = cycles;
} else
if (cycles < TIMER1_RESOLUTION * 8) {
clockSelectBits = _BV(CS11);
pwmPeriod = cycles / 8;
} else
if (cycles < TIMER1_RESOLUTION * 64) {
clockSelectBits = _BV(CS11) | _BV(CS10);
pwmPeriod = cycles / 64;
} else
if (cycles < TIMER1_RESOLUTION * 256) {
clockSelectBits = _BV(CS12);
pwmPeriod = cycles / 256;
} else
if (cycles < TIMER1_RESOLUTION * 1024) {
clockSelectBits = _BV(CS12) | _BV(CS10);
pwmPeriod = cycles / 1024;
} else {
clockSelectBits = _BV(CS12) | _BV(CS10);
pwmPeriod = TIMER1_RESOLUTION - 1;
}
ICR1 = pwmPeriod;
TCCR1B = _BV(WGM13) | clockSelectBits;
}