Phase Correct PWM library?

Im very new to Arduino, not micros or C though. Im currently building a robot with the brain based on a 32 bit 8 core Propeller and a Rasberry Pi. At this point ive got my mechanical platform running and I need to slam out a serial controlled motor controller and voltage and current monitoring system. I chose the ardruino for this part becuase after i watched jeremy blumbs video tutorials on arduino i was sold on its ease of use for processing tasks that dont need a ton of speed, i use to use the basic stamp for this but its to limited an atmega128 with the internal oscillator can do everything i need with no other chips thanks to its analog pins and interupts.

right now im just trying to get my motor control running quick without learning much. ive got the hbridge connected to an atmega328 bread board based arduino. i did some reading and want to set up 2 phase correct pwm channels. being new to avr/arduino im not understanding the registers and things very much and just want to get the bot running to find any mechanical issues. i was wondering if theres a pwm library that can easily set up a 100khz phase correct pwm for me with just a function call or something. i plan to get running now and read books later, the basics of arduino seem very easy i just really need to learn more about the acuall chip architecture

i did some reading and want to set up 2 phase correct pwm channels.

To control electric motors, which wouldn't know phase correct PWM if it bit them in the ass?

100khz phase correct pwm

Do you mean you want the PWM to be synchronised / phased correctly with respect to some external event? (Are you trying to build your own brushless motor controller?)

Im sorry I should have been more clear on what im acually trying to do and what im talking about.

Yes i am making a serial based motor controller along with battery managment sytem using an Arduino and STM l293E. The plan is to connect the l293E to an atmega168 running on an internal 8mhz oscillator, the atmega168 will be handeling battery managment via its analog pins. For motor control the plan is to have the atmega except commands from any serial communication source such as, Forward, Reverse, 45degree turn etc etc. When the arduino recives a serial command via a PC/Propeller Micro/Bluetooth module whatever, it should call a function using an interput. The motors im using also have encoders so I want to be able to have the option to use a closed loop feedback system to do a PID loop on the motors, or switch modes to open control with no error detection or speed compensation on the motors. All this stuff is a little down the line though...

Right now I have an arduino rbbk connected to my h bridge which is connected to two motors. Obviously changing the direction of the motors is no big deal thats just setting certain pins on the arduino Hi and Low which, which are connected to the hbridge chips inputs. Right now all im trying to do is generate two different PWM signal lines using timer zeron, pins 5 and 6 correct? Bit banging PWM is fairly straight forward but one PWM locks up the whole micro to the task, so I obviously wont be able to generate two simaltanous PWM lines while monitoring batteries and serial and all that good stuff.

I googled around about how to use the arduinos timers for PWM generation and found this article It goes over three different way of using arduino for PWM, there is bit banging, Counter Based Fast PWM, and finally counter based Phase Correct PWM. Being farily new to the Arduino I dont understand the examples it looks as if there or'ing some flags to set a register or something... Im not real sure how to set the PWM frequency either.. I was hoping maybe there is a library using the fast pwm or phase correct pwm methods descrided in that article to dumb it down to something like this

startPWM(pin, frequency, duty cycle);

My hbridge is capable of 100khz signals, from what I know about motor control 200Khz is going to be a really nice PWM ramp for DC motor applications, if I cant use the Arduino to generate pwm frequency this hi thats OK, but I dont see why not, A propeller can do clock lines up to 125mhz and its only an 80mhz chip, so im assuming 100khz should be failry easy for a 16 or even 8mhz chip

I would guess you need to use an external interrupt handler to start the output pulse and start a hardware timer which will trigger an interrupt handler to end the pulse. I can follow the general principles well enough to feel that it ought to be possible, but it'd require direct configuration of the hardware timers which I have no experience of. Given that you've found an article explaining how to do this sort of thing, I'm sure you'll figure it out with perseverance.

Acually I just opend some book about robitcs and arduino it explained alot of this in a simpler fashion so I could just get it going. One thing im not understanding is there are certain flags for the timers to set the PWM frequency the highest one is only 62khz.... Do these chips max out there, is there no flexablitiy to set custom frequencys. Im starting to wonder if ive made a bad choice here it will get the job done just not as well as I hoped.

Im really not understanding why I cant flip a pin at 100khz and then set a duty cycle...

The Atmega328 has 3 timers all of which are capable of phase-correct PWM. Two are 8-bit timers, one is 16-bit.

I have some logic analyzer images of all the modes on Timer 0 here:

You can get very high frequency phase-correct PWM. It is just a trade-off between frequency and duty cycle resolution.

This image, for example shows 40 KHz:

Code to generate that:

#include <TimerHelpers.h>
// Timer 0
// output    OC0A   pin 12  (D6)
// output    OC0B   pin 11  (D5)

const byte timer0OutputA = 6;
const byte timer0OutputB = 5;
void setup() {
   pinMode (timer0OutputA, OUTPUT); 
   pinMode (timer0OutputB, OUTPUT); 
   TIMSK0 = 0;  // no interrupts
   Timer0::setMode (5, Timer0::PRESCALE_1, Timer0::CLEAR_A_ON_COMPARE | Timer0::CLEAR_B_ON_COMPARE);
   OCR0A = 200;    // number of counts for a cycle
   OCR0B = 150;    // duty cycle within OCR0A
}  // end of setup

void loop() {}

The 40 KHz is because of the frequency counter being 200, so with a clock period of 62.5 nS the frequency will be:

1 / (62.5e-9 * 200) / 2 = 40000

Just reduce the counter to get a higher frequency. eg. 75 would give approx 106 KHz. You divide by 2 because that is the way phase-correct works. It counts up and then counts down again.

The only drawback here is that since the “top” is 75, you only have 75 units of duty cycle. In other words, the duty cycle can be 1/75, 2/75 and so on. That is, increments of 1.33% each time.

I strongly recommend the hardware PWM. It will give jitter-free pulses without relying on interrupts or anything else, and you can have up to three of them at once (although you usually reserve Timer 0 for timing, like counting milliseconds).

You can change the duty cycle on-the-fly by merely writing a different number fo OCR0B (the duty cycle register).

Just to amplify on my previous answer, you can actually have six PWM outputs if you are prepared to sacrifice flexibility of choice of frequency. If you are prepared to accept the "top" as being 256 (0xFF since it is zero-relative) then you can use both "sides" of the counter for PWM output (with different duty cycles).

Since you are committed to a count of 256 then the maximum frequency will be:

1 / (62.5e-9 * 256) / 2 = 31250

That is 31.25 KHz in phase-correct mode, or double that (62.5 KHz) in fast PWM mode. That is probably where you heard of a maximum of 62 KHz.

So it's all about choice. You choose if you want 3 outputs or 6, and you choose if you want a high PWM frequency, or a fine resolution of duty cycle.

Also if you use Timer 1 you have more resolution up your sleeve because that can count up to 16 bits, not 8.

Right now all im trying to do is generate two different PWM signal lines using timer zeron, pins 5 and 6 correct?

Yes they are the output for that timer. However as mentioned above you need to use a second timer (eg. Timer 2) if you want to have the extra control over the frequency.

When specifying your own frequency the "A" side of the timer counts up to the requested top, and the "B" side of the timer counts up to the duty cycle.

ok so i had to rewire my breadboard i was mistaken how each input works, i guess the forward and reverse pins of each motor need a pwm signal, this means i need two timers one for each motor, then i need to be able to control 4 seperate pins. im assuming if im using the timer on pins 10, 11 i can shut pin 11 off right?

the next question is, is there any reason to use phase correct over fast pwm? like i said i need to be able to convert this to work with an 8mhz setup easily. what is the fastest frequency with the best resalution i can generate at 8mhz on a 168? See this is why i was hoping for a library im gratefull for the code i just dont know enough about the atmegas to understand how this all works beyond coppy an pasting your code and fiddling with the timers

First, let me say thank you very much for your Code and Help! :slight_smile:

What do I need to change to use this Code (PWM Phase correct) on at ATiny85? Are the registers the same?

So if I would only count up to 50 (having a DutyCycle resolution of 2%) it would run at 160kHz (at 16MHz main clock)?

Is it right, that the ATiny85 can run with more… up to 64MHz? Thus the PWM Frequency in phasecorrect Mode would go up to 640kHz at 50 Steps or 320kHz at 100 Steps?

Thank you ver much again!!
Cheers Jim

What do I need to change to use this Code (PWM Phase correct) on at ATiny85? Are the registers the same?

No, they won't be.

So if I would only count up to 50 (having a DutyCycle resolution of 2%) it would run at 160kHz (at 16MHz main clock)?

That sounds right.

 1 / (62.5e-9 * 50) / 2  = 160000 Hz

Is it right, that the ATiny85 can run with more... up to 64MHz?

I believe it can run faster, I haven't played with the PLL clock much on that chip.


And on a Mega 2560? I just tried the above Code with changing the ports

// Mega: Pin 13 and 4

const byte timer0OutputA = 13;
const byte timer0OutputB = 4;

But it did not work?

And to change the Timer from 0 to 1, simply change all "0" to "1" in the Code? (an the Pins to 12,11 on Mega)?

Thanks alot!

I got an output on pin 4 using your changed code. I don't think you get an output on OC0A because it is using that as the phase-correct counter. Compare the image on my original post about timers:

Notice that the "A" output does not change.

And to change the Timer from 0 to 1, simply change all "0" to "1" in the Code? (an the Pins to 12,11 on Mega)?

Try it and see. Sounds about right.

Great it works!
Even with Timer1 on the Mega.

Your Code and Information are very helpfull. Thank you very much again!

Next step will be the ATiny85 with the internal PLL and 64MHz PWM. Got some promising information: