CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

generating PWM from timers --> debugging generated freque

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
foxOnTheRun



Joined: 17 Apr 2010
Posts: 43

View user's profile Send private message

generating PWM from timers --> debugging generated freque
PostPosted: Fri Jul 01, 2011 5:13 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Jul 01, 2011 7:15 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Jul 02, 2011 2:44 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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