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 support@ccsinfo.com

Timer2 calculator runtime

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



Joined: 14 Jan 2007
Posts: 20
Location: Hungary

View user's profile Send private message

Timer2 calculator runtime
PostPosted: Sun Jun 23, 2013 12:03 pm     Reply with quote

Hi all,
I need to change timer2 interrupt frequency in runtime. The range is between 50Hz to 20 kHz. I quickly wrote this code which is actually working.
Due to lack of math backgound it is simple but terribly slow.
May be I did not use the right keywords hence I did not find any better example how experts do it.
Here it is a test code how I did:
Code:

#include <16F1519.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES WDT_SW                   //No Watch Dog Timer, enabled in Software
#FUSES PUT                      //Power Up Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#define crystal 11059200
#use delay(clock=crystal)

#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors)
#define freq_pin PIN_C1

#int_TIMER2
void  TIMER2_isr(void)
{
output_toggle(freq_pin);
}


void calculate_divisors(int32 desired_freq)
{
int1 not_found;
int32 calc_divider,t2_clock;
signed int32 freq_error;
int16 prsc,prescaler,div,divider,posc,postscaler;
int16 smallest_error,actual_error;
int16 best_divider,actual_divider;


t2_clock=crystal/8; //T2 clock is fosc/4, toggle divides by 2
calc_divider=t2_clock/desired_freq;
if(calc_divider>65536)
   {
   printf("freq is out of range\r\n");
   return;
   }
best_divider=t2_clock/desired_freq;   
smallest_error=best_divider-1; //initializing smallest error found
       if(best_divider<2)
         {
         prsc=1;
         div=1;
         posc=1;
         }
        else
         {
         prescaler=1;
         not_found=1;
         while(prescaler<17&&not_found) //prescaler max value is 16
            {
            postscaler=1;
            while(postscaler<17&&not_found) //postscaler max value is 16
               {
               divider=1;
               while(divider<257&&not_found) //divider max value is 256
                  {
                  actual_divider=prescaler*postscaler*divider;
                  if(actual_divider>best_divider) //to avoid abs() function in stdlib!
                     actual_error=actual_divider-best_divider;
                   else
                     actual_error=best_divider-actual_divider;
                     
                  if(actual_error<smallest_error)
                     {
                     smallest_error=actual_error; //maintaining smallest error so far
                     prsc=prescaler;   //preserving actual figures
                     div=divider;
                     posc=postscaler;
                     
                     }
                  if(!actual_error) //test if error is 0 ->no need to continue
                     {
                     not_found=FALSE; //exiting from all three loops
                     }
                  divider++; //next divider value to try
                  }
               postscaler++; //next postscaler value to try
               }
            prescaler*=4; //next prescaler value to try, only 1,4,16 allowed
            }
         
         }
switch(prsc)
   {
      case 1 : setup_timer_2(T2_DIV_BY_1,(div-1),posc); //div value must be decremented
               break;
      case 4 : setup_timer_2(T2_DIV_BY_4,(div-1),posc);
               break;
      default: setup_timer_2(T2_DIV_BY_16,(div-1),posc);
               break;
   }

freq_error=desired_freq-t2_clock/(prsc*(div)*posc);
//printing out the result
printf("d: %5LuHz a: %5LuHz presc %2Lu, div %3Lu, postsc %2Lu freq_error %5LdHz\r\n",desired_freq,t2_clock/(prsc*(div)*posc),prsc,div,posc,freq_error);

}



void main()
{
int32 freq=100;

char karcsi=0x55;


   setup_timer_2(T2_DIV_BY_16,255,16);      //1.4 ms overflow, 23.7 ms interrupt
   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);
   setup_adc_ports(NO_ANALOGS);
   setup_wdt(WDT_OFF);
delay_ms(1000);
printf(__filename__);
printf(__date__);
printf("\r\n");

while(1)
{
   calculate_divisors(freq+=100);
   if(freq>20000) freq=100;
}
}

Do you have any idea to speed up this function?
_________________
The computer helps solving the problems which would have never arised without computers
Ttelmah



Joined: 11 Mar 2010
Posts: 19252

View user's profile Send private message

PostPosted: Sun Jun 23, 2013 1:22 pm     Reply with quote

You are probably not going to get there. 20KHz, would require 40Kips. Each interrupt takes typically a minimum of about 60 instruction times to execute, so at your 11MHz (2.7mips), you have no time left to do anything else at all....

'Experts', don't do this.
They either use a PWM, or an external programmable frequency source (best solution).

Best Wishes
tojape



Joined: 14 Jan 2007
Posts: 20
Location: Hungary

View user's profile Send private message

PostPosted: Sun Jun 23, 2013 3:09 pm     Reply with quote

Ttelmah wrote:
You are probably not going to get there. 20KHz, would require 40Kips. Each interrupt takes typically a minimum of about 60 instruction times to execute, so at your 11MHz (2.7mips), you have no time left to do anything else at all....

'Experts', don't do this.
They either use a PWM, or an external programmable frequency source (best solution).

Best Wishes

Thank you for your reply.
Experts don't do this - this might be the reason why I did not find what I looked for :-)
Using the pwm the lowest frequency seems to be 675Hz (the postscaler is not used in pwm mode) which is too high for me. (@Fosc=11059200Hz)
At 20KHz it's still able to get and calculate the next frequency setting and fortunately there's nothing else to do. Maybe I'll switch to using the internal 16MHz osc.
The whole thing isn't worth an external programmable frequency source. What can I get for less than $2 which is the price of a pic16f1519 micro?
Being just a hobbist I decided not to look for a better solution while this poor quality but still usable code works.
Thank you again :-)
Best wishes
_________________
The computer helps solving the problems which would have never arised without computers
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Sun Jun 23, 2013 3:25 pm     Reply with quote

what you want is the NCO feature of the 16f1509
so
unless you want 1 hzfreq set resolution -
it will do what you want-
and
if you pick the right external frequency crystal
-with real simplicity

see my earlier post on this capability

http://www.ccsinfo.com/forum/viewtopic.php?t=50121
tojape



Joined: 14 Jan 2007
Posts: 20
Location: Hungary

View user's profile Send private message

PostPosted: Sun Jun 23, 2013 3:51 pm     Reply with quote

asmboy wrote:
what you want is the NCO feature of the 16f1509
so
unless you want 1 hzfreq set resolution -
it will do what you want-
and
if you pick the right external frequency crystal
-with real simplicity

see my earlier post on this capability

http://www.ccsinfo.com/forum/viewtopic.php?t=50121


Thank you very much Very Happy
this is exactly the feature I need. Cheap, simple, much better than my poor attempt with 16F1519. I am going to order several pieces of them.
Your posting is highly appreciated.
_________________
The computer helps solving the problems which would have never arised without computers
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