View previous topic :: View next topic |
Author |
Message |
picer
Joined: 25 Jan 2005 Posts: 28 Location: Taxahoma
|
Help with software PWM |
Posted: Sun Feb 06, 2005 12:49 am |
|
|
I got it to work but I'm probably leaving alot on the table as far as processing power or maybe I'm not?
20MHz crystal
16F819
this seems to put out about a 500Hz PWM 50% duty on 3 channels, I want to have full duty cycle control and selectable freq from say 50Hz - 600Hz. 500Hz is all I can get, I put a simple serial code at the end just to see if it effects the freq and it doesn't seem to so that leads me to believe I still have some room left and maybe can make some routines that will accept the desired freq/duty via serial. Am I doing this right? Trying without interupts, with interupts I can only get around 300Hz for two channels so this is obviously much quicker. Seems as tho I need to break out of the loop somehow because I'm wasting alot of clocks counting when I no longer need to be but nothing I do makes it work right. Ideas? Just seeing how fast I can make the PWM and how many channels I can do, want at least 600Hz but 3 channels already zaps that. Just counting to 255 doesn't allow me to go to 50Hz which I'd like to be able to do so I'm using timer1 which can go 65K. I thought setting set_timer1(xxx) to a high number would do this for me but it doesn't affect the freq one bit, guess I don't understand it's function.
Thanks, hope this makes sense.
Code: |
void main()
{
int status;
char value;
long OnTime = 100;
long OnTime1 = 50;
long OnTime2 = 100;
long OffTime = 100;
long OffTime1 = 50;
long OffTime2 = 50;
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
set_timer1(0);
while (true)
{
while ( get_timer2() < 65536 )
{
if (OnTime > 0)
{
output_high(PIN_B3);
OnTime--;
}
else
if (OnTime == 0 && OffTime > 0)
{
output_low(PIN_B3);
OffTime--;
}
else
if (OnTime == 0 && OffTime == 0)
{
OnTime = 100;
OffTime = 50;
}
if (OnTime1 > 0)
{
output_high(PIN_B0);
OnTime1--;
}
else
if (OnTime1 == 0 && OffTime1 > 0)
{
output_low(PIN_B0);
OffTime1--;
}
else
if (OnTime1 == 0 && OffTime1 == 0)
{
OnTime1 = 100;
OffTime1 = 50;
}
if (OnTime2 > 0)
{
output_high(PIN_B1);
OnTime2--;
}
else
if (OnTime2 == 0 && OffTime2 > 0)
{
output_low(PIN_B1);
OffTime2--;
}
else
if (OnTime2 == 0 && OffTime2 == 0)
{
OnTime2 = 100;
OffTime2 = 50;
}
}
status=1;
printf("\r\nStart typing:\r\n");
printf("Hello");
printf("Hello");
while(!kbhit());
while(status==1)
{
value=timed_getc();
if(value==0)
status=0;
else
{
status=1;
putc(value);
}
}
printf("\r\nToo slow!\r\n");
}
}
|
|
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
Re: Help with software PWM |
Posted: Sun Feb 06, 2005 1:32 am |
|
|
First,
Let me suggest the 16F628 as it has a hardware UART onboard... when you write/read RS232, it won't suck horrible amounts of time bit-banging data in and out of your PIC.
As for your routine, you could make it an ISR which would help a bunch as you would only jump to do something on intervals accordingly.
I don't know if one way compiles better than the other, but look at the timer0 code included with PIC-C. It uses a global var and a constant for "INTS_PER_SECOND" (which you divide CLK/4/prescalr and so on) and then has an ISR (could be timer0 or timer1, whichever) that auto-counts down to zer0 then resets. You could easy have:
Code: |
void timer1_isr() {
if (!counter--) {
output_low(PIN_B0);
output_low(PIN_B1);
output_low(PIN_B2);
counter = INTS_PER_SECOND;
} else {
if (counter == duty1) {
output_hi(PIN_B0);
}
if (counter == duty2) {
output_hi(PIN_B1);
}
if (counter == duty3) {
output_hi(PIN_B2);
}
}
}
|
What's nice about this is that you don't need the both ON and OFF constants. This is PWM, which typically isn't symmetrical.
Make sure your ISR's are as short as they can be.
You could even write this in a struct kinda way to make all PWM's go to 0 at the same time (now they're an instruction apart)... making them synchronous. Might be handy. For the frequency you want, this might work ok... this is what I would shoot for first. Interrupts are fun. ;)
Then again, I'm writing this as 1:26amCST. I could be crazy. |
|
|
picer
Joined: 25 Jan 2005 Posts: 28 Location: Taxahoma
|
|
Posted: Sun Feb 06, 2005 10:19 am |
|
|
Doing interupts simply isn't fast enough, I've tried everything I can and simply can't even get two pwm greater than 300Hz and actually can't even get > 600Hz with 8bit resolution with one pwm either hense trying without interupts. I've certainly learned alot about interupts trying all this, I admit I need to know more about how a pic works and this is getting me there pretty fast, just wondering if I'm missing something with how i'm doing it now (non interupts). |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sun Feb 06, 2005 2:21 pm |
|
|
picer wrote: | Doing interupts simply isn't fast enough, I've tried everything I can and simply can't even get two pwm greater than 300Hz and actually can't even get > 600Hz with 8bit resolution with one pwm either hense trying without interupts. I've certainly learned alot about interupts trying all this, I admit I need to know more about how a pic works and this is getting me there pretty fast, just wondering if I'm missing something with how i'm doing it now (non interupts). |
Er, ok...
Have you consider some of the multi-output I2C based PWM drivers from folks like Maxim IC?
If you told us more about your application, perhaps we could make some alternate suggestions?
-Ben |
|
|
picer
Joined: 25 Jan 2005 Posts: 28 Location: Taxahoma
|
|
Posted: Sun Feb 06, 2005 2:33 pm |
|
|
I've yet to find any that will go down to 50Hz but maybe I've missed a few, been looking. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sun Feb 06, 2005 3:08 pm |
|
|
picer wrote: | I've yet to find any that will go down to 50Hz but maybe I've missed a few, been looking. |
The fact that you say 50Hz leads me to believe you want a signal generator - not a PWM.
PWM is constant freq w/adj duty cycle.
DDS is constant duty cycle with adjustable frequency.
If you want a DDS, look on Analog Devices website. They have DDS's that work down to millihertz if you need it.
I just recently finished designing a 200MHz DDS with a PIC controlling it via SPI. Works great.
This one looks like a good fit and it's only $4 (in quantity - I'm sure you could get a sample or two)
http://www.analog.com/en/prod/0,,770_843_AD9833%2C00.html
Might be overkill - but boy it'd work! |
|
|
picer
Joined: 25 Jan 2005 Posts: 28 Location: Taxahoma
|
|
Posted: Sun Feb 06, 2005 4:59 pm |
|
|
No, constant freq but selectable with variable duty. I had it in another thread but since this was a software (non interupt) solution I seperated it. I would love a hardware solution but like I said have yet to find a chip that will do what I need, 50Hz-650Hz (selectable) with precision duty cycle (0-100). Like i said i can do two channels but that seems to be the limit for 20MHz. I found one but you set freq with a res/cap and hense it's not software selectable. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sun Feb 06, 2005 7:32 pm |
|
|
picer wrote: | No, constant freq but selectable with variable duty. I had it in another thread but since this was a software (non interupt) solution I seperated it. I would love a hardware solution but like I said have yet to find a chip that will do what I need, 50Hz-650Hz (selectable) with precision duty cycle (0-100). Like i said i can do two channels but that seems to be the limit for 20MHz. I found one but you set freq with a res/cap and hense it's not software selectable. |
Ok, you are now saying opposing things. "Constant frequency", "but selectable" and "(50-650Hz)"
That's not constant frequency.
As for the precision duty cycle, how precision??
Better details would help us help you... |
|
|
picer
Joined: 25 Jan 2005 Posts: 28 Location: Taxahoma
|
|
Posted: Sun Feb 06, 2005 7:56 pm |
|
|
Not opposing in my mind, of course you can't read my mind Range is 50Hz to 650Hz, user selectable, 1% duty increments. So I want to select 50Hz (0-100% duty) on one channel, 100Hz (0-100% duty) on another, etc. As many channels as i can get out of one pic which to date has only been two channels because if I go 3 channels the max freq only makes it to around 400Hz then. I could do probably 4-5 50Hz channels pretty easy but want to at least be able to do one at 650Hz. clear as mud? I might just be at the limit of the pic at this point. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sun Feb 06, 2005 8:07 pm |
|
|
Any frequency between 50 and 650Hz? |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sun Feb 06, 2005 8:08 pm |
|
|
picer wrote: | Not opposing in my mind, of course you can't read my mind Range is 50Hz to 600Hz, user selectable, 1% duty increments. So I want to select 50Hz (0-100% duty) on one channel, 100Hz (0-100% duty) on another, etc. As many channels as i can get out of one pic which to date has only been two channels because if I go 3 channels the max freq only makes it to around 400Hz then. I could do probably 4-5 50Hz channels pretty easy but want to at least be able to do one at 600Hz. clear as mud? I might just be at the limit of the pic at this point. |
Ok.. gotcha... Now it's clear.
Hmmm.. 20MHz. is a 200nS instruction. If it was coded right, I think it could be done... but I'd have to dig into it with you.
I think it could be done. Make sure you're using fast_io. Looks at the .ASM to see how efficient what you're doing is...
I wouldn't bother using the hardware timers.. just run your code flat out. Check the instructions you're using for the IO high/low. I've found structures mapped onto IO ports like the examples in the PIC-C code are nice and fast.
That might help ya...
-Ben |
|
|
picer
Joined: 25 Jan 2005 Posts: 28 Location: Taxahoma
|
|
Posted: Sun Feb 06, 2005 10:09 pm |
|
|
I've tried fast_io and when I do the pic does absolutly nothing but suck up 5 volts. Not sure if the 819 or the compiler is at fault but that doesn't work. Trying to drive some solenoids that call for certain freqs but figured why stop there and make it user selectable and learn something in the process. My first real venture into pics, done some led flashing before but that's about it. Also finding C is just a little different in the pic world. wish I knew assembly well enough, I can somewhat read and follow it but can't program in it. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Feb 07, 2005 12:20 am |
|
|
picer wrote: | I've tried fast_io and when I do the pic does absolutly nothing but suck up 5 volts. Not sure if the 819 or the compiler is at fault but that doesn't work. Trying to drive some solenoids that call for certain freqs but figured why stop there and make it user selectable and learn something in the process. My first real venture into pics, done some led flashing before but that's about it. Also finding C is just a little different in the pic world. wish I knew assembly well enough, I can somewhat read and follow it but can't program in it. |
fast_io works, but it makes assumptions that the programmer is in control of everything and thus if you don't set everything up properly, it does nothing.
So, it's neither the 819 or the compiler. It's how you're doing it. Look at the PIC-C docs for better detail. I use it all the time.
Actually, C for a lot of micro's is the same way. Programmers coming from OS's like Windows or Linux think it's going to be the same. It is not. Not by a long shot.
I would say that PIC-C is the best I've seen. The others are pretty much no fun. But then again, I'm a hardware guy.. I just program cause I'm the one designing the circuits.
Assembly is good for hand-tuning critical stuff... but for the most part, with PIC-C, unnecessary.
Just keep at it... the more one practices anything, the better they get at it.
-Ben |
|
|
picer
Joined: 25 Jan 2005 Posts: 28 Location: Taxahoma
|
|
Posted: Tue Feb 08, 2005 9:09 am |
|
|
I've tried every example I could with fast_io and everytime I try it the pic does nothing, must be a bug. I've optimized my routines a little and now have it faster but guess I'm stuck with one pic per PWM for what I want. I can use the very little time left to do some i2c reads and a/d so guess that will work. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Feb 08, 2005 9:39 pm |
|
|
picer wrote: | I've tried every example I could with fast_io and everytime I try it the pic does nothing, must be a bug. I've optimized my routines a little and now have it faster but guess I'm stuck with one pic per PWM for what I want. I can use the very little time left to do some i2c reads and a/d so guess that will work. |
Did you set the tris register? Must be a bug doesn't cut it! Look at the LST file to see what is going on. Keep it simple, that will make it easier. |
|
|
|