View previous topic :: View next topic |
Author |
Message |
Will Reeve
Joined: 30 Oct 2003 Posts: 209 Location: Norfolk, England
|
PWM period (freq) tweaking? |
Posted: Mon Aug 02, 2004 9:37 am |
|
|
Hi,
I need to generate a fast low (processor) overhead square wave. I am thinking PWM is ideal, with the duty cycle set at 50%.
Is there any tweeks to change the PWM period? I have the presale and PR2 to play with (I assume I can adjust these on the fly) but I may need a little bit finer control. I need about 600kHz and don’t want to tie up the PIC in generating it!
Your advice and ideas, as always, are most welcome!
Keep well,
Will |
|
|
valemike Guest
|
|
Posted: Mon Aug 02, 2004 9:52 am |
|
|
What crystal frequency are you using?
Look at EX_PWM.c
The formula is:
// The cycle time will be (1/clock)*4*t2div*(period+1)
clock = Crystal Frequency
t2div = Let's keep it at 1
First state your crystal frequency, then I or someone will give you the values you need for PR2 and timer2 setup.
-Mike |
|
|
Will Reeve
Joined: 30 Oct 2003 Posts: 209 Location: Norfolk, England
|
|
Posted: Mon Aug 02, 2004 10:09 am |
|
|
Hi,
I am using 40MHz. I found the formula you state in the datasheet, but thanks for supplying it. I think I didn't word my initial question very well, what I need is a little bit more resolution, for instance the difference between a PR2 of 0x02 and 0x03 is 625kHz and 833kHz. Any ideas how I could get 700kHz for instance?
Will |
|
|
Ttelmah Guest
|
|
Posted: Mon Aug 02, 2004 10:24 am |
|
|
Will Reeve wrote: | Hi,
I am using 40MHz. I found the formula you state in the datasheet, but thanks for supplying it. I think I didn't word my initial question very well, what I need is a little bit more resolution, for instance the difference between a PR2 of 0x02 and 0x03 is 625kHz and 833kHz. Any ideas how I could get 700kHz for instance?
Will |
You get the best resolution, by using the lowest possible prescaler. With a prescaler of 1, you get frequencies of 714285Hz, with 14, and 666666Hz with 15 in PR2.
You can get 700KHz, by chosing a crystal that is a suitable multiple of this frequency (39.2MHz), but the step size for such a high frequency will remain large. If you need really fine resolution at this sort of frequency, look at using one of the programmable frequency synthesiser chips.
Best Wishes |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Aug 02, 2004 10:54 am |
|
|
Take a look at the compare module on the PIC (if you have one). You can get the best resolution with this method of generating the signal. |
|
|
Will Reeve
Joined: 30 Oct 2003 Posts: 209 Location: Norfolk, England
|
|
Posted: Tue Aug 03, 2004 9:15 am |
|
|
Thanks guys. I had not looked at the compare module in detail, it is very useful. It’s a shame the special function doesn’t toggle the pin as well as re-set the timer but you can’t have everything I guess! This will be a very useful module for this project!
Keep well,
Will |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Aug 03, 2004 10:24 am |
|
|
You can setup to toggle the pin and then add your CCP value to the CCP register. This will cancel out any latency from the ISR handler. So lets say your 1/2 period value is 0x100. Load that value into the CCP register. When the timer hits 0x100 the pin will toggle and an interrupt will occur. By the time you handle the interrupt, the value will not be 0x100 but lets just say it's 0x120. Well just add the 0x100 to the CCP value which is 0x100 and the new CCP value will be 0x200. So long as the latency is never greater than your 1/2 period value it shouldn't miss a beat. I use this technique to control 6 software PWM's used for dimming. |
|
|
Will Reeve
Joined: 30 Oct 2003 Posts: 209 Location: Norfolk, England
|
|
Posted: Wed Aug 04, 2004 9:19 am |
|
|
That is fantastic. Just what I need. Now I thought I was being clever by coding the following (PIC18 here):
int16 ccp1reg;
#locate ccp1reg=0xFBE
#INT_CCP1
void ccp1_int() {
ccp1reg+=300;
}
Which generates the following:
0096: MOVLW 2C
0098: ADDWF FBE,F
009A: MOVLW 01
009C: ADDWFC FBF,F
Which doesn’t seem to do what I want. Adding values up to 255 work fine! So it’s the 16bit addition which is playing up. I must be being thick here but don’t you need to handle the carry if the low byte rolls over 0xFF by the addition of 0x2C to it? I would have thought that the compiler would do this for me as that’s what I have asked for?
Is this a bug? Is there a good and fast way to do this?
Keep well,
Will |
|
|
Will Reeve
Joined: 30 Oct 2003 Posts: 209 Location: Norfolk, England
|
|
Posted: Wed Aug 04, 2004 9:27 am |
|
|
I am blind, didn’t notice the ADDWFC is the second line! It’s strange that it doesn’t seem to do what I ask of it? I get a very strange square wave pattern with variable frequencies, just like a rollover problem.
Will |
|
|
Will Reeve
Joined: 30 Oct 2003 Posts: 209 Location: Norfolk, England
|
|
Posted: Wed Aug 04, 2004 10:13 am |
|
|
Now this is REALLY strange, values up to 299 work perfectly. If I use 300 everything goes to pot, 301, doesn’t work but 302 does work. It’s beyond me this! Other random values I have chosen seem to work of 500, 1200 etc and even generate the expected frequencies! But go back to 301 and its broken! Help! |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Wed Aug 04, 2004 12:12 pm |
|
|
Try this out. The problem has to do with the number of instructions the interrupt handler takes being the same as the low byte of the value being added to the CCP register. Timer1's value just happens to be at that value (CCP1 + low byte of value) and a false compare happens. This method seems to work better.
Code: |
#if defined(__PCM__)
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=57600, xmit=PIN_C6, rcv=PIN_C7)
#elif defined(__PCH__)
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=57600, xmit=PIN_C6, rcv=PIN_C7)
#endif
#include <stdlib.h>
#include "input.c"
long CCP1;
#locate CCP1=0xFBE
long period;
#int_ccp1
void isr()
{
long dummy;
dummy = CCP1;
dummy += period;
CCP1 = dummy;
}
void main()
{
period = 300;
setup_ccp1(CCP_COMPARE_INT_AND_TOGGLE);
setup_timer_1(T1_INTERNAL); // Start timer 1
enable_interrupts(INT_CCP1); // Setup interrupt on falling edge
enable_interrupts(GLOBAL);
while(TRUE)
{
printf("\n\rEnter period: ");
period = get_long();
}
}
|
|
|
|
Will Reeve
Joined: 30 Oct 2003 Posts: 209 Location: Norfolk, England
|
|
Posted: Thu Aug 05, 2004 10:35 am |
|
|
Thanks, that works much better. I guess it takes just the two commands to get the CCP1 register set using this method.
Keep well,
Will |
|
|
|