Pages: 1 2 [3] 4 5   Go Down
Author Topic: PWM frequency library  (Read 63627 times)
0 Members and 2 Guests are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

where can I look up which timer on the Mega 2560 is connected to which pin?
Also how can I turn PWM Pin 2 & 3 into phase correct mode?
[Edit]
I think it should work like this:
Code:
TCCR3A = _BV(COM3A1) | _BV(COM3B1) | _BV(WGM30);
 TCCR3B = _BV(CS32);
One last question how can I invert the signal?


Thank you
« Last Edit: January 26, 2013, 06:00:39 pm by Tenta » Logged

Offline Offline
Newbie
*
Karma: 7
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry, I haven't looked at this thread in a while. I updated the original post to explicitly say this library does not support the Due. I don't think I will add support because I don't own a Due, and it appears to have some built library support already.

Petit Jean:

Quote
Thank you runnerup for this nice piece of work!

I have some questions for you, since I really need to expand this library for the Micro/Leonardo.
So that is what I will do, but maybe you can help me in the right direction.

In your estimation, can I better build of of ATimerDefs or BTimerDefs?
Do you have any idea how I could implement the difference in structure of the new 8 - 10 - 16 bit pins and fast PWM?
I want to change some of the timer—pin assignments for my project. Is that something that you think will work correctly with the construction you used for the library?
I will find my way in the end, but can you give me some places to start looking for the registers and stuff?

Any hint is welcome.

ATimerDefs or BTimerDefs are simply files that the preprocessor will include depending on the avr architecture the user compiles his code for.
If you want to implement different PWM modes, look at the specs sheet (http://www.atmel.com/Images/doc2549.pdf). Table 17-2 on page 148 describes which bits to manipulate to set each of the modes for the 16 bit timers.


mxw8950:

Quote
Thank you so much for this library as it has been fantastic in helping me get a pump driver up and running.

I have a question regarding timers using the 328. I have noticed that the library functions do not allow you to set the frequency on TIMER2A and was wondering if there was a specific reason why the library would not allow you to set this timer as I can't really find a default use for TIMER2A that would interfere with any other arduino function.

Thanks,
-matt

You don't set the frequency on TIMER2A because that is a channel, not a timer. A single pin is attached to timer2a, multiple pins are wired to a timer. When you set a frequency, it sets the entire timer and all of the pins wired to that timer are affected. If channel A on timer 2 is not working, then channel B probably won't work either. Can you verify that?

MaxHeadroom:

Quote
I want to use your library to up the frequency of the PWM on my motor control project (motors are noisy) on a Uno. It is a twin motor control so I use pins 5, 6 for one and pins 9,10 for other.
Pins 5, 6 are timer0 and I don't want to mess with that timer.
So the next step would be to change it to pins 3, 11 to use the other timer. This would mean hacking my shield.
And that is why I don't understand the above. Does this mean I can map the PWM output to any pin?

No, my wording is just a little confusing. By that I meant the caller (of that specific function) does not need to have any knowledge about which timer that pin is connected to since the function will figure that out for them. The pins are hardwired to the respective timer and cannot be changed. If you aren't using your uno for anything that requires timing functions (such as delay() and millis()) then you can use timer 0 without any problems.

Tenta:

Quote
where can I look up which timer on the Mega 2560 is connected to which pin?
Also how can I turn PWM Pin 2 & 3 into phase correct mode?

you can look it up here:

timer# and channel   pin #
TIMER3B2
TIMER3C3
TIMER0B4
TIMER3A5
TIMER4A6
TIMER4B7
TIMER4C8
TIMER2B9
TIMER2A10
TIMER1A11
TIMER1B12
TIMER0A13
TIMER5C44
TIMER5B45
TIMER5A46

The library initializes timers to phase and frequency correct PWM. I do not know what you mean by phase correct because the timers have many 'phase correct' settings. I advise you to look at table 17-2 on page 148 and table 17-5 on page 160 in the specs sheet (http://www.atmel.com/Images/doc2549.pdf). The code you listed will not set the correct waveform generation mode. Com bits determine whether the pin is connected/how the pin is manipulated by the timer. Waveform generation mode is a timer setting, not a pin setting. You should manipulate the WGM bits instead.
Logged

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

Thank you so much for the fast answer and your great work!
If I understood you right, your library sets the timer in to a phase and frequency corret pwm instead of fast pwm?
Logged

Offline Offline
Newbie
*
Karma: 7
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
If I understood you right, your library sets the timer in to a phase and frequency corret pwm instead of fast pwm?
Yes. Arduino libraries use fast PWM, this library sets timers to phase and frequency correct PWM.
« Last Edit: January 29, 2013, 09:49:46 am by runnerup » Logged

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

I am new to arduino. So I do not fully understand the code.

The main point is I want to ask is these function can change the PWM frequency up to 2MHz by calling the function of "pwmWrite()" and "SetPinFrequencySafe()" ?

Then, what is the resoluation of this frequency, 8 bits or 16bits?

Thanks.
Logged

Belluno
Offline Offline
Jr. Member
**
Karma: 1
Posts: 60
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

HELLO!

I tried PWM.h with arduino uno, good work!

my code adjusts the speed of a fan by trimmer on in analog input.

The fan is driven by a MOSFET connected to pin3. Everything works fine!

a few questions:

on pin3: if I use a low frequency I hear a whistle.
if I raise the frequency does not whistle anymore, okay! (My frequency counter reads Hz that i set in my code)

if I run the same code on PIN11:
the fan does not whistle, even if imposed 490Hz, my frequency counter reads no value (0.00 Hz), but the fan works fine.



why there is this difference between pin3 and PIN11?

I double checked the code and connections in the shield, and everything is ok

I am Italian, I apologize for my English, many thanks

Walter
Logged

Belluno
Offline Offline
Jr. Member
**
Karma: 1
Posts: 60
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

sorry,

I double-checked,

pin3 on the frequency counter reads 490Hz like i set the code,

on PIN11 reads a value greater than 50,000 Hz, over the range of reading of my frequency counter

Why this difference between pin3 and pin11?
Logged

Northants - UK
Offline Offline
Sr. Member
****
Karma: 1
Posts: 258
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Can the PWM be turned on or off ? do i just set it to "0" ?
Logged


Wien Austria
Offline Offline
Newbie
*
Karma: 0
Posts: 46
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Code:
// simple move forward and backward one motor on the l298n using pins 12 13 9/ 9 being PWM
#include <PWM.h>
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();
}
« Last Edit: April 17, 2013, 07:36:17 am by carbon_adam » Logged

Toledo, OH
Offline Offline
God Member
*****
Karma: 35
Posts: 508
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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. This library should be compatible with all Arduinos except the Leonardo and Due. 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
« Last Edit: April 29, 2013, 12:21:45 pm by teckel » Logged

Arduino - Teensy - Raspberry Pi
My libraries: NewPing - LCDBitmap - toneAC - NewTone - TimerFreeTone

Northants - UK
Offline Offline
Sr. Member
****
Karma: 1
Posts: 258
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Offline Offline
Full Member
***
Karma: 0
Posts: 101
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Offline Offline
God Member
*****
Karma: 25
Posts: 508
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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?
Logged

Northants - UK
Offline Offline
Sr. Member
****
Karma: 1
Posts: 258
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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


Offline Offline
God Member
*****
Karma: 25
Posts: 508
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

3.21 Jigahertz!  Tom!
Logged

Pages: 1 2 [3] 4 5   Go Up
Jump to: