View previous topic :: View next topic |
Author |
Message |
Jody
Joined: 08 Sep 2006 Posts: 182
|
PIC18F87J50 2# PWM at different frequencies |
Posted: Wed Jul 31, 2013 4:25 am |
|
|
Hello,
At this moment I want to use 2# PWM outputs...(PIC18F87j50)
So far so good.. But what I want is that one PWM output is running at i.e. 20.000Hz. and the other at 5.000Hz but that they start at the same moment.
What I read in the datasheet is that there are two timers involved with the PWM, Timer2 and Timer4.
But I can't figure out how they are related to the specific PWM output.
So what do I have to put in which timer to let the correct PWM output run at the frequency I want.....
anybody an idea???
Regards,
Jody |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Wed Jul 31, 2013 5:20 am |
|
|
Hmmm.. could you clarify the frequencies please?
When you typed in 20.000 Hz did you mean 20KHz ?
Being in Canada I'd type 20,000 Hz or 20 KHz..but I think the 'European' way is to use the decicmal point not the comma.
Just so we start off on the right foot !!
jay |
|
|
Jody
Joined: 08 Sep 2006 Posts: 182
|
|
Posted: Wed Jul 31, 2013 5:45 am |
|
|
Yep I mean 20kHz....
And it is not that I need 20kHz it is just an example...
Different frequencies starting at the same moment....
And the one slower than the other...
Jody |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Jul 31, 2013 12:13 pm |
|
|
You are not going to get perfect alignment. You can get it within a very few clock cycles.
The key is the two master clocks.
Forget about the PWM at first, just think about the two timers.
If you setup the two timers, one using perhaps /200, and div_by_1, and the other /200 and div_by_4, then they will generate two clocks at 1/4 the rate of each other.
All you do, is setup the PWM's as 'normal', but ensure one uses the second timer. Table 17-3, shows how to select example clock rates. The values needed will depend on your master clock. Then just clear each timer as quickly as possible after one another. This 'aligns' the timers.
Code: |
set_timer2(0);
set_timer4(0);
|
The syntax needed to select the second timer, depends on the age of your compiler.
When a timer is set, it also clears the prescaler, and the setting occurs at the end of the value being written, so the clocks will be misaligned by the time taken to write the second number only. Since these timers run in 8bit mode for the PWM, just a couple of CPU instructions. This is as close as you can get.
Best Wishes |
|
|
Jody
Joined: 08 Sep 2006 Posts: 182
|
|
Posted: Wed Jul 31, 2013 1:04 pm |
|
|
hello,
as soon I am back in the office I will give it a go....
Keep you informed......
Thanks,
Jody |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed Jul 31, 2013 3:37 pm |
|
|
do you need a TRUE PWM frequency source ?
or
do you need arbitrary frequencies with a fixed duty cycle?
or
arbitrary frequency with a fixed non-50% duty cycle- say pulse train??
your question needs clarification.
more simply:
what frequencies or Range of freqs do you need
and what duty cycle ??
AND
Quote: |
start at the same moment. |
phase locked or arbitrary phase ?? |
|
|
Jody
Joined: 08 Sep 2006 Posts: 182
|
|
Posted: Tue Sep 17, 2013 5:07 am |
|
|
What I need is:
1 output at a (fixed) frequency say 8kHz.(jumper selectable 8kHz or 10kHz or 16kHz)
1 output which starts at the same moment (1~2mS different is no problem) but with a factor 2 or 4 or 8 slower..(output is 4kHz or 2kHz or 1kHz) but the rising edges must start at the same moment...
It this possible to do with the PWM outputs???
Regards,
Jody |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Sep 17, 2013 5:25 am |
|
|
To get rising edges precisely at the same moment is not possible even with hardware. There is always going to be some amount of misalignment, even if its picoseconds or less. So, what amount of misalignment is acceptable in this application? Just how close to "aligned" do they really need to be? |
|
|
Jody
Joined: 08 Sep 2006 Posts: 182
|
|
Posted: Tue Sep 17, 2013 5:35 am |
|
|
(1~2mS different is no problem) |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Tue Sep 17, 2013 1:42 pm |
|
|
Yes. Fairly easily.
What compiler version?.
What clock rate is your CPU running?.
Remember that if you change the clock rate using anything other than the prescaler, the numbers needed for each duty cycle will also have to change. |
|
|
Jody
Joined: 08 Sep 2006 Posts: 182
|
|
Posted: Wed Sep 18, 2013 12:58 am |
|
|
Hi,
Compiler version in 4.119
CPU clock rate is the internal 8MHz. (40MHz Oscillator available).
and..... how is it fairly easily??
Regards,
Jody |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Sep 18, 2013 4:02 am |
|
|
No guarantees. Haven't got that chip to try. However this should give two synchronised CCP's at a factor of 4 in frequency, on ECCP1/2 (Port C1, and C2), controlled by a two bit jumper pattern on B0, and B1.
Code: |
#include <18F87J50.h>
#FUSES NOWDT, WDT128, NOXINST, INTRC, NOFCMEN, NOIESO
#use delay(clock=8000000)
#use rs232(baud=9600,parity=N,ERRORS,bits=8,stream=PORT1,errors)
int8 old_b;
int8 current_b=0xFF; //ensure pattern update on first call
int16 max_duty=0; //set this to allow the duty cycle to be controlled sensibly
//Check if input pattern on jumpers has changed
int1 pattern_changed(void)
{
current_b=input_b() & 3;
if (current_b==old_b)
return(FALSE);
return(TRUE);
}
void set_dutys(int8 duty)
{
int32 temp;
//Now because the PR2 value changes with the rate, need to use different
//values for the same duty cycle.
//This allows 'duty' in percent to be sent and automatically set the right
//factor.
if (max_duty==0 || duty==0) //avoid possible division by zero...
{
set_pwm1_duty(0L);
set_pwm2_duty(0L);
return;
}
//Now have 'max_duty' for 100%, and need to work out what has to go to the
//timing registers from this.
//Use int32 as fastest way.
temp=(int32)duty*max_duty;
temp/=100;
set_pwm1_duty(temp);
set_pwm2_duty(temp);
}
//set PWM's according to the jumper pattern
//using (two bits):
// 0 = both off
// 1 = 8KHz/2KHz
// 2 = 10KHz/2.5KHz
// 3 = 16KHz/4KHz
void set_pwms(void)
{
//now need to switch according to the current two bit pattern on B0/B1
//This is in 'current_b' if pattern_changed has been called
if (current_b>3)
pattern_changed(); //here if it hasn't been called. - first time.
//Now stop PWM, momentarily
set_pwm1_duty(0L);
set_pwm2_duty(0L);
switch (current_b)
{
case 0b00:
//Here both jumpers make = both PWM's off
//Since already done ready for chaqnge, only have to set max_duty
max_duty=0;
break;
case 0b01:
//Now want the slowest rate.
//Setup two timers
setup_timer_2(T2_DIV_BY_1, 249, 1); //8KHz
setup_timer_4(T4_DIV_BY_4, 249, 1); //2KHz
max_duty=1000;
break;
case 0b10:
//10K rate
setup_timer_2(T2_DIV_BY_1, 199, 1); //10KHz
setup_timer_4(T4_DIV_BY_4, 199, 1); //2.5KHz
max_duty=800;
break;
case 0b11:
//16K rate
setup_timer_2(T2_DIV_BY_1, 124, 1); //16KHz
setup_timer_4(T4_DIV_BY_4, 124, 1); //4KHz
max_duty=500;
break;
}
set_dutys(50); //start PWM's at 50% duty
old_b=current_b;
}
void main()
{
setup_comparator(NC_NC_NC_NC);
//Now assume jumpers are on two low portB pins, using internal pullups
port_b_pullups(TRUE);
delay_us(50); //allow pins time to settle
setup_ccp1(CCP_PWM);
setup_ccp2(CCP_PWM);
//Your compiler does not correctly set the T3CCP1 bit, as documented.
//Have to use:
setup_timer_3(T3_DISABLED | T3_CCP2_TO_5);
//second timer for second CCP
//This is confusing. The bit to select the 'alternative' timer, selects
//T3, for 'compare', and 'capture', so CCS refer to T3, but selects T4
//for PWM.....
//Now force the PWM's to the current pattern
set_pwms();
do
{
//Now your main code
//At some point check the pins if you want the PWM's to be able to
//update 'live'.
if (pattern_changed())
set_pwms(); //will only be called if the jumpers change
}
while (TRUE);
}
|
The synchronisation will be a few CPU clocks apart, as already explained.
I set the duty cycles at 50%, with a function that can correctly set this for the different rates.
Best Wishes |
|
|
Jody
Joined: 08 Sep 2006 Posts: 182
|
|
Posted: Wed Sep 18, 2013 5:09 am |
|
|
Hi Ttelmah,
Output C2 is not working...you wrote in the code that there was something confusing about the T3 timer and selecting the T4 timer.....
Output C1 is exactly as you wrote down....
So I am almost there..
I will try and (a lot) error.. keep you informed..
BUT Great that you want to help!!!
Regards,
Jody |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Sep 18, 2013 7:19 am |
|
|
Both timers are running, and the PWM's as well (in MPLAB). Try using 'output_drive(PIN_C2);' in the setup. CCS may not be setting the tris. Didn't check for that.
I was just saying that the CCS nomenclature is confusing....
The 'point' about the timer setting, is that there are two bits in the timer3 config register, which sets various CCP's to use the alternate timer. When using the PWM, the alternate timer is timer4... CCS, also say in the 'include' file that you can or the configuration with the CCP setup, but on this compiler version this does not work. You have to setup timer3, to select the alternate timer, then use timer4.....
Best Wishes |
|
|
Jody
Joined: 08 Sep 2006 Posts: 182
|
|
Posted: Wed Sep 18, 2013 9:17 am |
|
|
YES got it working!!!!!
My C2 pin is broken... so was looking for a solution which never came...
But now I am using C1 and G0 and it is working like you said!!
I changed the T3 setting:
Code: | setup_timer_3(T3_DISABLED | T3_CCP3_TO_5); |
Ttelmah THANK!!!!!!!!!!!!!!!!!!!!!
Regards,
Jody |
|
|
|