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

Interrupt Problems - AGAIN!

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



Joined: 07 May 2005
Posts: 28
Location: Campbell, CA

View user's profile Send private message

Interrupt Problems - AGAIN!
PostPosted: Tue May 24, 2005 4:37 pm     Reply with quote

First, I'm just a beginner with C, so please don't be too hard on me regarding my style!

The code below does try to work. The problem is that whenever I enter my RDA ISR, ** ALL ** interrupts are disabled.
As you can see, I toggle RB0 whenever I enter the 1mSec timer interrupt so that I can watch that with an oscilloscope.

My RDA ISR is entered whenever a key is hit. The routine is not exited until the buffer is full or an <ENTER> is pressed or the _100mSec_Counter has reached 100 (10 sec). Unfortunately the _100mSec_Counter never times out because the timer interrupt isn't running.

As soon as I leave the RDA ISR, the timer interrupt starts again.
The CCS manual states that there is no need to disable interrupts when in an ISR, because "interrupts are automatically disabled". They don't mean ALL interrupts are disabled when in an ISR, do they?

What could be causing this?


Code:


#include <18F452.h>
#device adc=10
#include <stdlib.h>
#fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=20000000) // 20MHz clock
#use rs232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7,ERRORS)
#use fast_io(b)
#define buffer_size 10
#priority RDA,rtcc,AD




  int1 Flg1,Flg2,Flg3,Flg4,Flg5,Flg6,Flg7,Flg8,ADC_Done_Flag,Key_Buffer_Flag,Key_Wait_Timeout_Error;
  int8 ToggleCounter2,ToggleCounter3,ToggleCounter4,ToggleCounter5,ToggleCounter6;
  int8 ToggleCounter7,ToggleCounter8;
  int8 NumFans,mSec_Counter,_100mSec_Counter,Old_100mSec_Counter;
  int8 i,t;
  int16 Sec,Intermed,RPM;
  int16 ToggleCounter1,ADvalue;
  float Vref;
  int8 RecdChar,next_in,next_out;
  int8 Keyin_buffer[buffer_size];


 void Clear_Keyboard_Buffer()
{
   int i;
   for (i=0;i<buffer_size;i++)
      Keyin_buffer[i] = 0;
}


#int_rtcc

//  Beginning of ISR, called when TMR0 (rtcc) rolls over
//  Every Millisecond

void rtcc_isr()
{
  output_toggle(PIN_B0);                        //Just to see if we are alive
  {set_rtcc(0x67);}

 if (NumFans == 0x08)
  {if (Input(Pin_D7) != Flg8)
    {Flg8 = Input(Pin_D7);
     ToggleCounter8++;}}

 ... stuff in here

 if (Input(Pin_D0) != Flg1)
     {Flg1 = Input(Pin_D0);
     ToggleCounter1++;}

   mSec_Counter++;

   If (mSec_Counter == 100)
     { _100mSec_Counter++;
        mSec_Counter = 0;}                                                       //Clear the millisecond counter

   return;
}

// END OF rtcc ISR

#int_AD

void AD_isr()

{
    ADvalue = Read_ADC(ADC_read_only);
    ADC_Done_Flag = 1;
}


#int_RDA

void RDA_ISR()
 {
   i=0;
    Key_Buffer_Flag = 1;
   Key_Wait_Timeout_Error = 0;
   _100mSec_Counter = 0;
   while (true)
    {
reenter:
     if (kbhit());
      {i = getc();
      if (i==13) return;
      if (i==0x08)
        {printf("\b");
         printf(" ");
         printf("\b");
         next_in--;
         goto reenter;}
         
      if (next_in > (Buffer_size -1)) return;
      printf ("%c",i);
       Keyin_buffer[next_in]= i;
       next_in++;
           
         }
         
         printf("100mSec_Counter = %i",_100mSec_Counter);
         
       if (_100mSec_Counter == 100)
         {Key_Wait_Timeout_Error = 1;}
       
    }

   
 }



void main()
{
  int8 a,MinCnt,FanNum;
  port_b_pullups(TRUE);

  setup_adc_ports(RA0_ANALOG);
  setup_adc( ADC_CLOCK_INTERNAL );
  set_adc_channel( 0 );

  setup_psp(PSP_DISABLED);
  setup_spi(FALSE);
  setup_wdt(WDT_OFF);
  setup_timer_0(rtcc_INTERNAL|rtcc_DIV_32|rtcc_8_bit);
  setup_timer_1(T1_DISABLED);
  setup_timer_2(T2_DISABLED,0,1);
  setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
  enable_interrupts(INT_rtcc);
  enable_interrupts(INT_AD);
  enable_interrupts(INT_RDA);
  enable_interrupts(GLOBAL);
  set_tris_b(0x00);                    //All bits output
  set_tris_a(0xF3);                    //One LSB input,
  set_tris_c(0x80);                    //Bit 3 input, rest output
  set_tris_d(0xFF);                    ///All input
  set_tris_e(0x07);                    //Three LSBs input, rest output

  NumFans = 0x07 & input_e();          //Read Port E, strip off 5 MSBs
  NumFans = NumFans + 1;

  NumFans = 1;                         //DEBUG ONLY

  a = 0;
  Sec = 0;
  mSec_Counter = 0;
  ADC_Done_Flag = 0;
  Vref = 5;
  MinCnt = 0x50;
  next_in = 0;

  ToggleCounter1 = 0;                   //Make certain that there is no error if fan
  ToggleCounter2 = 0;                   //Routine not called
  ToggleCounter3 = 0;
  ToggleCounter4 = 0;
  ToggleCounter5 = 0;
  ToggleCounter6 = 0;
  ToggleCounter7 = 0;
  ToggleCounter8 = 0;
 
  Clear_Keyboard_Buffer();


         
   i = 0;
   t = 0;



// Main Loop ---------------------------------------------------------------------------------------------

  while (a == 0) {                       //Forever for this pgm

     if (_100mSec_Counter >= 0x0A) {     //Every 1 second, go into this routine

 
        _100mSec_Counter = 0;
         FanNum = 0;                     //Clear the variables

       output_toggle(PIN_B1);            //Just an indication that something is happening


     if (NumFans == 0x08){
      if (ToggleCounter8 < MinCnt)       //Simplified code, realized that if FanNum > 0 that alone
         {FanNum = 8;
       }                                 //indicated that a fan had failed.
     }

    ... Stuff in here


     if (NumFans >= 0x02){
       if (ToggleCounter2 < MinCnt)
         {FanNum = 2;
         }
     }

        if (ToggleCounter1 <= MinCnt) {       //Check for too slow, set flag if # of toggles are too low
         FanNum = 1;
       }

        if (FanNum == 0)
              {output_high(PIN_A3);}         //Pin high if no error

        else
              {Output_low(PIN_A3);           //Bring a pin low if any fan is too slow

               for (i=0;i<FanNum;i++)        // Flash number of times corresponding to failed fan
                 {Output_low(Pin_A2);
                 delay_ms(20);
                 Output_high(Pin_A2);
                 delay_ms(500);}}


            RPM = ((ToggleCounter1 * 30)/2);

            printf("Fan 1 RPM = %lu\n\r",RPM);

            If (ADC_Done_Flag == 1)

             {printf("Voltage = %2.3f\n\r",(float)ADvalue*Vref/1023);}

            If (Key_Buffer_Flag == 1)
             {Key_Buffer_Flag = 0;

             printf("Input = ");
             for (i=0;i<Buffer_size;i++)
             {printf ("%c",Keyin_buffer[i]);
             }
             printf("\n\r");

             Clear_Keyboard_Buffer();
             next_in = 0;}

 
            ADC_Done_Flag=0;
            Read_ADC(ADC_Start_only);

            ToggleCounter1 = 0;               
            ToggleCounter2 = 0;               
            ToggleCounter3 = 0;
            ToggleCounter4 = 0;
            ToggleCounter5 = 0;
            ToggleCounter6 = 0;
            ToggleCounter7 = 0;
            ToggleCounter8 = 0;

     

     }



         }
         }
Ttelmah
Guest







PostPosted: Tue May 24, 2005 5:05 pm     Reply with quote

Yes, all interrupts are disabled in an ISR. More correctly, the global interrupt response is disabled, _and must be_. However the individual interrupt flags will still be set, so if (for instance), a 'timer' interrupt happens while you are in a receive data ISR, then when the RDA ISR is exited, the timer interrupt will then be serviced. This though is the key behind the 'mantra', recited on this board again and again, _keep interrupt handlers short_. If the total time used in any ISR, is longer than the time between events on any of the ISR's, data will be lost, or interrupt events will be missed.
In your RDA ISR for example, the fact that an RDA interrupt has occured, tells you that there is a character waiting. All the ISR should do, is read the character, and copy it to a buffer (you do not need to check kbhit). You main program should do any timing, and printing (remember that printing a single character, takes the same time as receiving a character, so printing very much in an ISR, _will_ mean the UART will overflow.
Even on a PC, interrupts at the same or lower priority will be disabled the same way.

Best Wishes
Charles Linquist



Joined: 07 May 2005
Posts: 28
Location: Campbell, CA

View user's profile Send private message

PostPosted: Tue May 24, 2005 6:43 pm     Reply with quote

So, since global interrupts are disabled when in any ISR, the only reason to set the #priority compiler directive is to insure that when you come out of an ISR, pending interrupts are processed in a known order. Correct - or not.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Tue May 24, 2005 9:54 pm     Reply with quote

Charles Linquist wrote:
So, since global interrupts are disabled when in any ISR, the only reason to set the #priority compiler directive is to insure that when you come out of an ISR, pending interrupts are processed in a known order. Correct - or not.

Correct

Interrupts are meant to be short as possible. You should receive the data into a buffer and do all the processing in the main loop.
Ttelmah
Guest







PostPosted: Wed May 25, 2005 2:58 am     Reply with quote

Yesish!.
Think of this scenario. You have a timer interrupt, which is used to send data to a LCD. You also have a serial interrupt. Functionally, missing a timer interrupt, will not actually matter. Even if two or three timeouts took place, the LCD data would eventually be sent. Conversely the serial interrupt, is a critical event. The priority statement, in this case, would allow you to ensure that the RS232 handler will always 'win' if both interrupt flags are set.
If #priority is not used, the interrupt routines are called in the order that they appear in the source code.
You also need to look at latency values. For instance, if you have a serial interrupt routine, that takes 30uSec to handle, and the serial rate is only 9600bps (so a 'character' time is nearly a mSec), while you also have a quadrature decode routine, that only takes 15uSec to handle (remember there is as much as a fifty instruction 'overhead', involved in the global interrupt handler), but may happen for short bursts at a rate up to 50KHz. You have 'error recovery' in the serial handler, so loss of a character is not a major event, then it becomes vital to ensure that the quadrature decode routine always wins.
You need to look at the delays involved in each routine, and the worst case scenario (this is normally when an interrupt triggers just after the code has started serving another interrupt). You also need to avoid disabling interrupts in the main code (in the example you have, using the putc/printf, and delays in the interrupt handler, ensures that interrupts will be disabled if these functions are used in the main code, making latency worse...
For reliability, unless you know exactly what you are doing, interrupt routines should be short, and simple.

Best Wishes
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