Go Down

Topic: PWM frequency library (Read 73 times) previous topic - next topic

runnerup

The code is now up. There are three new functions and an example sketch to explain how they work.
To be consistent with analogWrite(), pwmWrite() will always perform 8 bit pwm. If a higher resolution is necessary, use pwmWriteHR() instead.

void pwmWrite(uint8_t pin, uint8_t duty) 8-bit, 0 - 255
void pwmWriteHR(uint8_t pin, uint16_t duty) 16-bit, 0 - 65535

Unfortunately, resolution control is not that simple once custom frequencies come into play. If you modify the frequency on a timer, the resolution will change. The general rule of thumb is that the higher the frequency the lower the resolution. There are several variables that the SetFrequency functions wrap. They are aware of them and will mathematically determine the highest possible resolution at that given frequency. Although pwmWriteHR() accepts a 16 bit integer, it will automatically map to any timer resolution. To know whether the resolution is too low for your tolerances at a particular frequency, I have added two functions.

float GetPinResolution(uint8_t pin)
float TimerX_GetResolution() (replace X with a timer number)

These functions find the resolution in base 2/the number bits required to represent the resolution. Please note that both return floats, not ints; that is intentional. If you prefer to find the number of possible values instead of messing with binary, use TimerX_GetTop() and add 1 (which is the same thing but in base 10).

I added a sketch called PWM_lib_resolution_example to the project to demonstrate these functions and the relationship between timer frequency and resolution.
I have not been able to find enough time to exhaustively check this code for bugs, so if you find any please speak up.

ksshhs

Awesome library runnerup!

ksshhs

Wait, I can't verify my sketch as it says 'prescaler' has not been declared in the following line:

Code: [Select]
extern void SetPrescaler_8(const int16_t timerOffset, prescaler psc);

What should I do?

Many thanks

ksshhs

#13
Aug 20, 2012, 05:40 pm Last Edit: Aug 20, 2012, 05:42 pm by ksshhs Reason: 1
I mean, I tried using the psalt and then it says that prescaler_alt hasn't been declared either? Am I modifying it incorrectly by just simply deleting ps_... values and the line of code in the previous reply?

runnerup

Good work Ksshhs, you found a bug for me XD... but no, it was not the cause of your problem.
The library currently has a bug in the preprocessor directives. It calls the wrong internal SetPrescaller function for timer 2. I will publish version .04 to fix that right away.

I have no way of knowing what your problem is. For future reference, you should post the source you are working with, along with the type of board you are compiling for.
My guess is that you are trying to call either Timer0_SetPrescaler() or Timer2_SetPrescaler() explicitly and using the wrong syntax for the parameter.

Here is an example of setting the prescaller to 1024 on all of the mega's timers:

Code: [Select]

void setup()
{
        Timer0_SetPrescaler(ps_1024);
Timer1_SetPrescaler(ps_1024);
Timer2_SetPrescaler(psalt_1024);
Timer3_SetPrescaler(ps_1024);
Timer4_SetPrescaler(ps_1024);
Timer5_SetPrescaler(ps_1024);
}


Same deal on the Uno and most other non megas except there are only 3 timers (0, 1, and 2) available. Attempting to use the others will give you a compiler error

For all possible prescaler parameters, look at how it it is defined in the header (you can also look at the first post in this thread):
Code: [Select]

enum prescaler
{
ps_1 = 1,
ps_8 = 2,
ps_64 = 3,
ps_256 = 4,
ps_1024 = 5
};

//certain 8 bit timers read the CSn register differently
enum prescaler_alt
{
psalt_1 = 1,
psalt_8 = 2,
psalt_32 = 3,
psalt_64 = 4,
psalt_128 = 5,
psalt_256 = 6,
psalt_1024 = 7
};


Don't worry about the values the enum elements are set to, they are used as bit masks and can only confuse humans.
Oh, and be sure to download the newest version of the library before you mess with timer 2.

Go Up