|
|
View previous topic :: View next topic |
Author |
Message |
foxOnTheRun
Joined: 17 Apr 2010 Posts: 43
|
generating PWM from timers --> debugging generated freque |
Posted: Fri Jul 01, 2011 5:13 pm |
|
|
Ok, I was reclutant to post this, but untill now I haven't found an explanation.
I'm using timer0 (or timer1), every overflow I just toggle the value of a pin, so I can generate a pwm signal, nothing fancy (PIC16F690).
I'm expecting to see:
Starting value: set_timer1(65436);
100 counts to overflow; 8mhz, 1 increments every 4 clock.
So, one effective timer increment every 4/8000000 --> 0.5us
pwm is set at 50%, so 100 ticks UP, 100 ticks DOWN ==> 200 ticks_period * 0.5us = 100us duration
F = 1/100us = 10kHz square wave - correct assumptions up to here?
But I'm getting 7.03 kHz using timer 1, and 6,98kHz using timer0 (measured by a multimeter with freq mode). As a check, if I setup the internal pwm generator to whatever freq, I can get a matching reading.
I know, writing a post about pwm+timer+settings is as dangerous as getting hit by a bullet train carrying a backpack full of knives.. but.. Clearly, I'm missing something :\ - but what? :roll:
This is the minimum, compilable code which reproduce the issue:
Code: | #include <main.h>
#define dis_ctrl PIN_A5
#use FAST_IO (A)
int1 state;
#int_TIMER1
void TIMER1_isr(void)
{
if (state == 0) {
set_timer1(65436);
output_high(dis_ctrl);
state = 1;
} else {
set_timer1(65436);
output_low(dis_ctrl);
state = 0;
}
}
void main()
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_comparator(NC_NC_NC_NC);
set_tris_a(0b00010111);
enable_interrupts(GLOBAL);
setup_oscillator(OSC_8MHZ);
set_timer1(65436);
enable_interrupts(int_TIMER1);
while(true);
} |
This is the main.h
Code: | #include <16F690.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES PUT //Power Up Timer
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOIESO //Internal External Switch Over mode disabled
#use delay(int=8000000) |
_________________ Listen, why don't you relax? Take a pill, bake a cake or go and read the encyclopedia. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 01, 2011 7:15 pm |
|
|
Look at the #int_timer1 routine in the following link, and notice how it
compensates for interrupt latency by reading the current timer value
and adding it to the preload value.
http://www.ccsinfo.com/forum/viewtopic.php?t=45554&start=1
Remember, before the program gets to the isr, it has to go through the
first half of the CCS interrupt handler, and this may take 25 to 30
instructions (at 1/2 usec each for an 8 MHz oscillator). So about 12 to 15
usec passes before you can reload the timer in the isr. So by reading
the timer in the isr, you find the amount of time that has already passed
after the interrupt fired, and in effect, subtract it from the time before the
next interrupt fires.
Also notice how this is done at the very beginning of the isr. Your code
loads Timer1 within the isr in two places. There is no need for this.
You can move it to the top of the isr as shown in the example. |
|
|
foxOnTheRun
Joined: 17 Apr 2010 Posts: 43
|
|
Posted: Sat Jul 02, 2011 2:44 am |
|
|
Oh my!
You were.. ARE right!
To tell the truth, before posting I tried a slower PWM, like having an int after a full count of timer0, and it was interrupting/overflowing correctly every 32ms.. but I didn't persisted :\
To get a nice 10kHz pwm I use:
Code: | set_timer1(65436 + get_timer1() +22); |
And I'm setting timer1() in two places because I'm modifying the ON and OFF period.
I'm still tweaking the time base, I can tune the frequency now, but I'm not getting good timings overall.
Working on.
Tnx! _________________ Listen, why don't you relax? Take a pill, bake a cake or go and read the encyclopedia. |
|
|
|
|
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
|