![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Datman Guest
|
Software PWM frequency |
Posted: Tue May 13, 2008 9:06 pm |
|
|
Hi all. I am trying to design a 4 channel PWM controller, variable duty cycle, and also variable frequency from 30Hz to 2kHz. The reason for doing so is that the product will be used to drive valves from many different manufacturers, all with different PWM frequency requirements.
I have tried several approaches to get the full range i need. I'm using PIC16F690, currently with 20Mhz crystal. Firstly i have a method where an 8 bit timer just runs without using interrupt. The value of the desired PWM duty is compared with the current value in the timer buffer to produce the square output. Thus the frequency is determined by how fast the timer increments its buffer. So I am limited here to a set few frequencies as determined by the prescaler, and not the frequencies in between.
Code: | tmr0_buffer = get_timer0();
if( tmr0_buffer < pwm_xa_compare )
PWM_XA_OUT_ON;
else PWM_XA_OUT_OFF; |
the other method is to use the isr, with a variable incrementing each isr call, and then comparing again with the desired duty value. So the frequency can be set via the timer reload value to make the interrupt occur faster. Problem here... using 20Mhz crystal and reload value FFFE i can only get 1.3kHz frequency... impossible to go faster.
Code: | void timer1_isr()
{
if(PwmCounter==0)
{
output_low(PIN_C0);
}
if(PwmCounter==50)
{
output_high(PIN_C0);
}
PwmCounter++;
if(PwmCounter>=100)
{
PwmCounter=0;
}
set_timer1(0xFFFE);
} |
Does anyone have any other ideas as to how i can achieve the full range i need, 30Hz - 2kHz? I can handle having the frequency in like 200Hz steps rather than being completely scalable. |
|
![](templates/subSilver/images/spacer.gif) |
RLScott
Joined: 10 Jul 2007 Posts: 465
|
Re: Software PWM frequency |
Posted: Wed May 14, 2008 8:24 am |
|
|
You could sacrifice duty-cycle resolution for an increase in PWM frequency. For example, instead of counting 0,1,2,3,...99,100 count 0,2,4,6,...,98,100. This will give you double the PWM speed.
Another solution is to using instruction times instead of a timer. Your loop would look something like this:
Code: |
while(1)
{
i = 100;
PortC=0x00; //clear all 4 at once
do
{
if(i<dutycyle0)
output_high(PIN_C0);
if(i<dutycycle1)
output_high(PIN_C1);
if(i<dutycyle2)
output_high(PIN_C2);
if(i<dutycycle3)
output_high(PIN_C3);
j = PeriodValue;
do {} while(--j);
}while(--i);
}
|
Use fast I/O so that you don't waste time setting the TRIS register. Count instruction cycles in the disassembly listing to see what your loop time is and what value of PeriodValue you need to set to achieve the desired frequency. The 4 conditional pin settings should each get optimized into 5 instructions with no gotos.
However even this has problems meeting your 2KHz requirement. The "i" loop would have to complete in 5 usec. Even with your 20 MHz crystal, that is still only 25 instruction times total. It takes at least 20 instruction times just to manage the conditional pin setting. That only leaves 5 instrucitons to manage the loop and the variable delay. I think you may still have to go with a resolution of 2% instead of 1%.
Robert Scott
Real-Time Specialties |
|
![](templates/subSilver/images/spacer.gif) |
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Wed May 14, 2008 1:02 pm |
|
|
I'd find it easier to work in terms of elapsed time rather than frequency. And what resolution do you need for the PWM duty cycles? What I see as the major problem is that you'd need to subdivide a 2KHz rate (= 500usec/cycle) into as many segments as possible to get any reasonable choice of duty cycles at the maximum frequency.
Suppose you had a basic clock running at 20KHz, or 50usec per cycle. Could you do everything you need to do with increments of 50usec? If so, then I think the project can work. If these valves just dumb old solenoids, they shouldn't be too fussy about niceties like exact frequency, because they're so highly inductive that they even out the current all by themselves. |
|
![](templates/subSilver/images/spacer.gif) |
Datman Guest
|
Re: Software PWM frequency |
Posted: Wed May 14, 2008 1:51 pm |
|
|
RLScott wrote: | I think you may still have to go with a resolution of 2% instead of 1%.
|
yes i see your point, the other problem is that i have an SSI interrupt working, taking in an SSI signal from another micro which actually tells this micro what its output duty should be. So more time taken here to process this signal..
Normally we would want 1% duty resolution. But i guess at worst i can chop this down to 2% for higher frequencies. Its all very frustrating for me, we have developed the product and now a client says "how bout this" so i have to try and make it work with as much of the current hardware as i can, although a change in micro is not completely out of the question.
Are there any devices on the market that do SSI to PWM with variable frequency? I haven't been able to find any at all, which is why i went down this path in the first place. |
|
![](templates/subSilver/images/spacer.gif) |
RLScott
Joined: 10 Jul 2007 Posts: 465
|
Re: Software PWM frequency |
Posted: Wed May 14, 2008 2:13 pm |
|
|
If you insist on a software PWM, then it is going to be pretty compute-intensive. Any interrupt from the SPI port is going to corrupt one cycle of the duty cycle being generated. If it is allowed to stop all PWM output whenever a new duty-cycle is commanded, then the SPI interrupt would not be a problem. But if you have to change duty-cycle by SPI command smoothly on-the-fly, then I think you are screwed.
I made a duty-cycle generator with a 12F675 running at 4 MHz. It took in an analog command instead of a SPI command, and it only needed to generate one channel of PWM. Also, I used Timer 0 interrupts and the frequency was fixed at power-up. What you are trying to do is much harder.
Are there any regularities in the 4 duty-cycles that you could take advantage of to simplify the design? Or do you really need 4 duty cycles that vary independently over the 0-100% range?
Robert Scott
Real-Time Specialties |
|
![](templates/subSilver/images/spacer.gif) |
Datman Guest
|
|
Posted: Wed May 14, 2008 2:21 pm |
|
|
unfortunately, 4 that vary over the full 0 - 100% range is what is required. Its a tough one, I think I may have to try and talk the client into a 30Hz - 1.2kHz spec lol. This i can achieve using interrupts. Its hard to know what most solenoids require, they are trying to cover their asses i guess, but generally the ones i have come across are lower frequency ![Question](images/smiles/icon_question.gif) |
|
![](templates/subSilver/images/spacer.gif) |
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Wed May 14, 2008 3:07 pm |
|
|
It seems to me that 1.2KHz with 2% resolution leads to a basic clock rate of 60KHz. That's 16.7usec per cycle, or just over 80 instructions with a 20MHz crystal. And in that time, the interrupt has to be properly set up and ended, I mean registers saved etc. Can it work?
In another thread someone proposed not actually responding to interrupts at all, but just checking the flag in the main routine. That might be worth a look. You could poll the flag for incoming communication, too. I do that all the time when I need an incorruptible timer interrupt, and it works OK. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|