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

Interrupt / seconds limit? on 18f242

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



Joined: 02 Jan 2006
Posts: 75
Location: Neeroeteren, Limburg, Belgium

View user's profile Send private message

Interrupt / seconds limit? on 18f242
PostPosted: Tue Apr 29, 2008 7:56 am     Reply with quote

Hello,

I am using a pic 18f242 and a 20MHz Xtal.

I have to measure the rotation speed of a wheel with 18 thooths on it.

Each tooth gives an interrupt.

This seems to go very well till 11600 RPM

example 10 000 rpm:

166.666 r/sec

18 pulses/rotation

3000 pulses/sec

1 pulse every 0.33 ms.


I wrote a finite state machine

so my interrupt code only does an increment of a variable position.

Code:

position++;
if (position == 18)
position =0;


I'm sure there is a limit to the interrupts i can capture each second,
but how to calculate it, or where can i find it?

Thanks in advance![/code]
Matro
Guest







PostPosted: Tue Apr 29, 2008 8:02 am     Reply with quote

2 solutions :
- The limit comes from the hardware (for example your sensor is out of range or the signal is over and eventual filter bandwidth)
- The limit comes from your code, but here you need to look carefully at your code. The length of the ISR is something, but there is other limiting things. For instance some built-in functions that disable the interrupts.

But we can't give a value or a calculation method with the information that you gave.

Matro.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: Interrupt / seconds limit? on 18f242
PostPosted: Tue Apr 29, 2008 8:21 am     Reply with quote

For complete control over a time-critical interrupt, use #INT_GLOBAL and write you entire ISR using in-line assembly. That way you can count instruction cycles and know exactly how much time your interrupt code takes.

Robert Scott
Real-Time Specialties
Blob



Joined: 02 Jan 2006
Posts: 75
Location: Neeroeteren, Limburg, Belgium

View user's profile Send private message

PostPosted: Tue Apr 29, 2008 8:47 am     Reply with quote

Hello, some more information,

the sensor is a magnetic pickup. giving a sinus wave.

this is digitalised with some diodes and a flipflop.

I measured this pulse with the scope, it stays ok also at high rpm.

at certain points in a rotation i have to perform some actions depending on the RPM.

there is one tooth different from the others. so i determine my 0 position there.



for example i have to flash a light at 25° at 5000 RPM

Code:

#int_ext               
void EXT_ISR()   
{
   if (start)      //start cycle                                           //determines where my 0 position
                                  //this code is performed only on the first rotation
   {   
      setup_timer_1(T1_DISABLED);                        
      tNow = get_timer1();                           
      set_timer1(0);                              
      setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);                                             
      t6 = t5;
      t5 = t4;
      t4 = t3;                                    
      t3 = t2;                                    
      t2 = t1;                                    
      t1 = tNow;                                    
      if(t4 < t5-t5/5 && t4 < t6-t6/5 && t3 > t1-t1/5 && t3 > t2-t2/5)
      {
         pos = 2;                                 
         start = false;                              
         setup_timer_1(T1_DISABLED);                     
         set_timer1(0);                              
         digi = false;
         first = true;
      }      
   }
   else
   {
      
      pos++;   
                if(pos == 19)   //reset position
                     pos = 1;
      bl_interupt=true;   
   }
}




in my eeprom i store some values, on which rpm and what angle my light must flash

Code:

void main(void)
{
   // Set port directions, set PIC to safe analog mode and disable valve
   set_tris_a(63);
   set_tris_b(5);
   set_tris_c(129);
   output_low(Valve_A);               // zet power jet af
   output_low(Valve_B);               // zet power jet af
   output_low(DigitalOutput);            // zet ignition op 0

   disable_interrupts(int_EXT);

   curve = 0;
   step = 0;

   t1 = 0;
   t2 = 0;
   t3 = 0;
   t4 = 0;
   t5 = 0;
   t6 = 0;
   digi = 0;
   start = 1;
   limit = 0;
   pos = 0;
   overflow = 0;
   first = true;

   setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
   setup_timer_3(T3_INTERNAL | T1_DIV_BY_8);
   ext_int_edge(L_TO_H);
   enable_interrupts(global);
   enable_interrupts(int_rda);
   bl_interupt=false;
      
   disable_interrupts(int_rda);
   
   enable_interrupts(int_timer1);   
   enable_interrupts(int_timer3);
   setup_timer_3(T3_DISABLED);   
   
   if(input(DigitalInput))
   {
      enable_interrupts(int_EXT);
      while(true)
      {
   
         if(bl_interupt)
         {
            bl_interupt=false;
            if (pos == 18)                                    {                                             if(!digi)
                  flash();
                        
                                       
            }
            else if (pos == 15)                        
            {
            
               timed_flash();                     
            }
            
         }   
      }
   }

}



in the timed_flash function, i read the rpm, and calculate when the light should flash. i use 2 timers for this, one for determing the rpm and one that will activate the light flash.

Code:

#separate
void timed_flash()
{

   setup_timer_1(T1_DISABLED);
   tNow = get_timer1();
   set_timer1(0);
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);   
   tNow_copy = tNow;
   tNow = tNow / 16;
   adr = (int16)(46875 / tNow) - 11;
   adr = (adr > 309 ? 0 : adr);
   
   if ((adr >= start_digi || tNow_copy < 10000) && overflow == 0 && !first)
   {
      
      digi = true;
      
   
      if ( tNow_copy > 2360 )
         wait = read_program_eeprom(2*(start_tabel+adr));
      else
         wait = tNow_copy/128*end_angle;
      
      
         wait = 65535 - wait;
         ign = true;
   
         setup_timer_3(T3_DISABLED);
         set_timer3(wait);
         setup_timer_3(T3_INTERNAL | T3_DIV_BY_8);   
      
      
   }
   else
   {   
      setup_timer_3(T3_DISABLED);
      digi = false;
   }
   overflow = 0;
   first = false;
}




In my isr, i only set my position in that way it is not depending on the timing of the other functions.

The light flashes ok till 11600 rpm.

The problem is not the light system, this works up to 25000 rpm in a one tooth application.

if i let the ligt flash at a fix degree, f.e. 25°

then it looks like the wheel is not turning, because the light will flash every rotation at the same point.

if rpm becomes higher then 11600 the wheel seems to turn very unstable (in the light, in reality it runs ok)

if i then drop the rpm, i becomes stable again, but at an other position...

Thanks in advance
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Apr 29, 2008 9:43 am     Reply with quote

Executing interrupts takes more time than most beginners are aware of. To check if you are here running into the processor's speed limit I did a simple calculation.
    - On a PIC18 the interrupt handler has to store all registers and restore them on exit, this takes about 75 instruction cycles.
    - Your interrupt routine is nice small, about 10 instruction cycles.
    - Your processor runs at 20MHz
    Max. number of interrupts per second: (20MHz / 4) / (75 +10) = 58,823
From this it seems very unlikely that the timer1 interrupt is limited by processor speed.


What is the interrupt for timer3 doing?
Maybe this is conflicting with the time measurement in the Timer1 isr?
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Tue Apr 29, 2008 2:01 pm     Reply with quote

ckielstra wrote:
..On a PIC18 the interrupt handler has to store all registers and restore them on exit, this takes about 75 instruction cycles.

- Your interrupt routine is nice small, about 10 instruction cycles.

Do you mean his EXT_ISR()? I don't think so.:
Code:

#int_ext               
void EXT_ISR()   
{
   if (start)      //start cycle                                           //determines where my 0 position
                                  //this code is performed only on the first rotation
   {   
      setup_timer_1(T1_DISABLED);                         
      tNow = get_timer1();                           
      set_timer1(0);                               
      setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);                                             
      t6 = t5;
      t5 = t4;
      t4 = t3;                                     
      t3 = t2;                                     
      t2 = t1;                                     
      t1 = tNow;                                     
      if(t4 < t5-t5/5 && t4 < t6-t6/5 && t3 > t1-t1/5 && t3 > t2-t2/5)
      {
         pos = 2;                                 
         start = false;                               
         setup_timer_1(T1_DISABLED);                     
         set_timer1(0);                               
         digi = false;
         first = true;
      }       
   }
   else
   {
       
      pos++;   
                if(pos == 19)   //reset position
                     pos = 1;
      bl_interupt=true;   
   }
}


I know the comment says that the big block is performed only on the first cycle, but if you look at what it does, it seems to rely on a FIFO of previous readings. So that block must be executed more than once. And if you count that block, then you are probably are more like 200 instruction times, not 10. Unless perhaps the first revolution takes place at reduced speed?

If that missing tooth code needs to execute faster, then I would rewrite it to avoid all those divisions. Or perhaps the entire missing tooth detection algorithm can be re-evaluated to come up with something simpler.

Robert Scott
Real-Time Specialties
Blob



Joined: 02 Jan 2006
Posts: 75
Location: Neeroeteren, Limburg, Belgium

View user's profile Send private message

PostPosted: Wed Apr 30, 2008 1:27 am     Reply with quote

Hello,

the "start" cycle is indeed only executed at startup of the system.

This is in low rpm.

timer_3 interrupt is just for flashing the light:





Code:
#INT_TIMER3
void timer3_handler()
{
   setup_timer_3(T3_DISABLED);
   if (ign)                  
   {
      output_high(DigitalOutput);   

      ign = false;
      set_timer3(65500);         
      setup_timer_3(T3_INTERNAL | T3_DIV_BY_8);
   }
   else
   {
      output_low(DigitalOutput);

   }
}


nothing exotic here i think...
SuperDave



Joined: 22 May 2008
Posts: 63
Location: Madison, TN

View user's profile Send private message Visit poster's website

Interrupt / seconds limit? on 18f242
PostPosted: Thu May 22, 2008 8:35 am     Reply with quote

Assuming you have not yet jumped off a bridge here's an angle I haven't seen discussed.

From your code:
Quote:

enable_interrupts(int_timer1);
enable_interrupts(int_timer3);


I suspect that the problem is that one interrupt is being processed when another occurs and is thus ignored. Two timing sensitive interrupts will automatically clash at some point (eg. the product of their times) especially since any interrupt other than int_global uses the default handler which as noted elsewhere has a minimum process time of about 15uS (75 instruction cycles).

I was trying to create a 13uS interrupt and a 100uS interrupt, boy was that nuts. Now I do a 13uS using Int_global (so I don't have the 15uS minimum) and that code does its thing then increments a counter which is interrogated by a loop. When the counter reaches 7 (91uS), I do my 100uS thing, fix it for the 9% error and subtract 7 from the counter just in case I got there a little late. Not perfect but no clash.
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Thu May 22, 2008 9:54 am     Reply with quote

Could you write a test version of the code that polls instead of using interrupts? With no interrupt overhead it would be faster and would help you understand the limits.
_________________
The search for better is endless. Instead simply find very good and get the job done.
Blob



Joined: 02 Jan 2006
Posts: 75
Location: Neeroeteren, Limburg, Belgium

View user's profile Send private message

PostPosted: Fri May 23, 2008 12:38 am     Reply with quote

Don't worry about the timer_1 and timer_3 collision.

timer_1 will be a slow (div_by_8) timer and is not used for interrupt, only for time measurement. in some cases it will have the chance to interrupt but those are fail safe:

timer_3 will be fast (div_by_2) and will generate an interrupt.

the timers start almost at the same time with their count

so interrupt 3 will always be way ahead interrupt 1

thanks anyway
Blob



Joined: 02 Jan 2006
Posts: 75
Location: Neeroeteren, Limburg, Belgium

View user's profile Send private message

PostPosted: Fri May 23, 2008 1:37 am     Reply with quote

by the way, the problem is solved.

I noticed the problem did not occur when i made over time.

so when all machinery here was down.

I assume there was some interference via the electrical net here.

adding some more ground connections to all components of the application fixed the problem when the machinery was back online

best regards
blob
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