View previous topic :: View next topic |
Author |
Message |
bmoore
Joined: 11 Feb 2008 Posts: 13
|
efficient code for multiple PWM signals? |
Posted: Tue Feb 09, 2010 1:56 pm |
|
|
I'm trying to implement multiple PWM outputs in software with a different period and duty cycle for each signal, but am having trouble getting the code to run fast enough. I have the values for the period and duty cycle stored in arrays, but accessing them this way just takes up more time than I have between timer overflows for my interrupt routine. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 09, 2010 3:34 pm |
|
|
How many PWM signals do you need ?
What are the frequencies of the PWM signals ?
What resolution do you need on the duty cycles ?
What PIC are you using ? What is the oscillator frequency ? |
|
|
bmoore
Joined: 11 Feb 2008 Posts: 13
|
|
Posted: Mon Feb 15, 2010 10:51 am |
|
|
I like at least eight PWM signals
PWM frequency probably needs to be around 100 Hz
Resolution will vary from 1/32 to 1/64 (length of a "tick" will remain the same, but number of ticks in a duty cycle will vary from 32 to 64).
Currently using a 16F887 with the internal oscillator (8Mz) |
|
|
SimpleAsPossible
Joined: 19 Jun 2004 Posts: 21
|
Will this get you where you want to go? |
Posted: Fri Feb 19, 2010 2:44 pm |
|
|
How about you use a 6400 Hz interrupt and get rid of the arrays (for speed in the interrupt service routine)?
Code: | #INT_TIMER0
void timer0( void )
{
TMR0 = 100; // or whatever you need to do to overflow at 6400 Hz
PeriodCounter1++;
if ( PeriodCounter1 > Period1 )
{
PeriodCounter1 = 0;
Output1 = 0;
}
if ( PeriodCounter1 > DutyCycle1 )
Output1 = 1;
// repeat for PeriodCounter2, etc.
} |
This only works if your other periods and duty cycles fit into the 6400 Hz scheme. And there will be some cycles of jitter, which will be worse on the outputs you set later in the interrupt routine, because of variation in the earlier ones. (You can eliminate that with NOPs in assembly code -- I've done that before, to ensure that every path through a certain section of code took the same amount of time. I didn't get the impression you would be that particular.)
The easiest solution is to throw more hardware at the problem. Add more PICs with hardware PWMs, with settings provided by your master PIC. Add a CPLD or FPGA with multiple PWMs. Add dedicated motion-controller ICs that have PWMs. |
|
|
Ttelmah Guest
|
|
Posted: Fri Feb 19, 2010 3:46 pm |
|
|
Funnily enough, look for code for something completely different!.
Search here for RTC code.
There was a basic algorithm posted here some time ago, for generating an accurate RTC, based upon simple integer arithmetic, to generate a rolling count, which then gave 'long term', an accurate output, from a very fast integer addition and test. The same algorithm can be used in a tick interrupt to control the setting of a PWM bit. Repeat for multple bits, and you have the basis of what is required.
Best Wishes |
|
|
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Sat Feb 20, 2010 8:37 am |
|
|
I think SimpleAsPossible has it backward--a higher duty cycle would actually lead to a smaller pulse width. To deal with that, and synchronization, and add a test for a duty cycle of 0 or >= 100% (assuming the outputs appear on Port D):
Code: |
#INT_TIMER0
void timer0( void )
{
static int8 hold_output;
portd = hold_output; // Do this first, before any variations occur
// Results calculated in previous cycle
TMR0 = 100; // or whatever you need to do to overflow at 6400 Hz
// but this wouldn't be necessary if you use TMR2
PeriodCounter1++;
if ( PeriodCounter1 > Period1 )
{
PeriodCounter1 = 0;
if (DutyCycle1 != 0)
bit_set(hold_output, 0);
}
if (( PeriodCounter1 > DutyCycle1 ) && (DutyCycle1 < Period1))
bit_clear(hold_output, 0);
// repeat for PeriodCounter2, etc.
}
|
|
|
|
|