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

problem with interrupt and rs232

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



Joined: 05 Jun 2006
Posts: 41
Location: Belgium

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

problem with interrupt and rs232
PostPosted: Sat May 21, 2011 11:06 am     Reply with quote

hello,
I have a problem with serial communication and fast interrupt.

The fast interrupt is comming from 2 encoders.

Serial communication from a pc, who is polling the pic.

When encoder is not moving, communication is running a long time, but when encoder is moving, after a few seconds, the serial communications stucks...it sounds as a serial buffer overrun.

Have anybody a idea how to solve this ?
I send the complete code...

Thanks,
Carl

Code:

#include <30f4013.h>
#device adc=12
#Device icd=true
#FUSES WDT // Watch Dog Timer
#FUSES HS
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#fuses HS2_pll8 // div by 3 and  multiply the ext. clock of 40mhz by 8x
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#include <stdlib.h>
#include <string.h>
#define XTAL_FREQUENCY 120000000,RESTART_WDT
#use delay(clock=XTAL_FREQUENCY)
#use rs232(baud=115200,parity=N,uart2,bits=8)

/////////////////// Variabelen /////////////////
   int32      EL_actu_position,AZ_actu_position;
   int32       EL_calc_position,AZ_calc_position;
   int32       EL_dest_position,AZ_dest_position;
   int         EL_init_ok, AZ_init_ok;
   int32      EL_offset, AZ_Offset,AZ_u1;
   int         EL_stapteller=0,AZ_stapteller;
   int         EL_PID_OVER, AZ_PID_OVER;
   int         EL_STILL, AZ_STILL;
   int         el_brake_state, AZ_brake_state;
/////of the PID-controller azimuth ///////////////////////
   int32 AZ_x0=0.0, AZ_y0=0.0, AZ_z0=0.0, AZ_u=0.0;
   int32 AZ_y1, AZ_z1 ;
   int32 AZ_Kr=15000.0, AZ_Ti=5000.0, AZ_Td=1000.0;        // parameters of the PID-controller
   int32 AZ_u0, AZ_dt=0.667;
/////of the PID-controller elevatie  ///////////////////////
   int32 EL_x0=0, EL_y0=0, EL_z0=0, EL_u=0;
   int32 EL_y1, EL_z1, EL_u1;
   int32 EL_Kr=15000, EL_Ti=5000, EL_Td=10000;        // parameters of the PID-controller
   int32 EL_u0, EL_dt=0.667;
///// variabelen voor rs232 ///////////////////////
   #define COMBUFFSIZE 40
   static int packet_ready = false;
   static int8 buff[COMBUFFSIZE] = {0};
   static int8 commNotActive = 0;
   #define BUFFER_SIZE 100
   BYTE buffer[BUFFER_SIZE];
   BYTE next_in = 0;
   BYTE next_out = 0;
/////////////////// UIT-gangan /////////////////

      #define AZ_CCW_Lswitsh   PIN_B0   // input    pen 2
      #define AZ_CW_Lswitsh   PIN_B1   // input    pen 3
      #define EL_CCW_Lswitsh   PIN_B2   // input    pen 4
      #define EL_CW_Lswitsh   PIN_B3   // input    pen 5
      #define AZ_enc_A      PIN_A11   // input    pen 17
      #define AZ_enc_B      PIN_B4   // input   pen 6
      #define AZ_enc_Z      PIN_B11   // input   pen 36
      #define EL_enc_A      PIN_D8   // input    pen 23
      #define EL_enc_B      PIN_B5   // input    pen 7
      #define EL_enc_Z      PIN_B12   // input    pen 35
      #define AZ_Enbl_Drive   PIN_F1   // output    pen 29
      #define EL_Enbl_Drive   PIN_F0   // output    pen 30
      #define AZ_pwm_CCW      PIN_D3   // output    pen 19
      #define AZ_pwm_CW      PIN_D2   // output    pen 22
      #define EL_pwm_CCW      PIN_D1   // output    pen 33
      #define EL_pwm_CW      PIN_D0   // output    pen 34
      #define AZ_Brake      PIN_B9   // output    pen 38
      #define EL_Brake      PIN_B10   // output    pen 37
   
/////////////////////////////////////////////////////////////////////////////////////
      void EXT_Encoder_AZ();
       void EXT_Encoder_EL();
         void RS232();
         void AZ_TrajectBerekening();
      void EL_TrajectBerekening();

/////////////////////////////////////////////////////////////////////////////////////
#int_rda2
void serial_isr() {
   int t;

   buffer[next_in]=getc();
   t=next_in;
   next_in=(next_in+1) % BUFFER_SIZE;
   if(next_in==next_out)
     next_in=t;           // Buffer full !!
}

#define bkbhit (next_in!=next_out)

BYTE bgetc() {
   BYTE c;
   while(!bkbhit) ;
   c=buffer[next_out];
   next_out=(next_out+1) % BUFFER_SIZE;
   return(c);
}
////////////////////////////////////////////////////////////////////////////////////
/****************** encoder Azimuth inlezen *******************/
#int_ext0
   void EXT_Encoder_AZ()
   {
      if (input(AZ_enc_B) == 1)   
         {
               AZ_actu_position = AZ_actu_position + 1.0;
         }
         else
         {
               AZ_actu_position = AZ_actu_position - 1.0;
         }
   }
/////////////////////////////////////////////////////////////////////////////////////
/****************** encoder elevatie inlezen *******************/
#int_ext1
   void EXT_Encoder_EL()
   {
      if (input(EL_enc_B) == 1)   
         {
               EL_actu_position = EL_actu_position +1.0;
         }
         else
         {
               EL_actu_position = EL_actu_position- 1.0;
         }
   }
/////////////////////////////////////////////////////////////////////////////////////
#INT_TIMER4
   void TIMER4_isr()
   {
      //  AZ_TrajectBerekening();
   //   EL_TrajectBerekening();
   
   }
/////////////////////////////////////////////////////////////////////////////////////
void AZ_CalcError (void)
      {
         // AZ_actu_position is de positie waarde encoder is
         // AZ_calc_position is de berekende positie
         // AZ_u0 is de foutwaarde die in de PID gaat
            AZ_u0 = AZ_actu_position - AZ_calc_position;
      }
/////////////////////////////////////////////////////////////////////////////////////
void EL_CalcError (void)
      {
         // EL_actu_position is de positie waarde encoder is
         // EL_calc_position is de berekende positie
         // EL_u0 is de foutwaarde die in de PID gaat
            EL_u0 = EL_actu_position - EL_calc_position;
      }
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
void AZ_CalcPID ()
      {
         AZ_x0 = (AZ_Kr*AZ_u0)/1000;                   // P-action with         Kr=100
         AZ_y1 = AZ_y0 + AZ_x0/AZ_Ti*AZ_dt;
         AZ_z1 = AZ_y0 + AZ_x0;  // I-action with timeconstant Ti= 10
         AZ_u1 = AZ_z0 + AZ_Td*(AZ_z1-AZ_z0)/AZ_dt;           // D-action with timeconstant Td=  1
         AZ_y0=AZ_y1;
         AZ_z0=AZ_z1;
         AZ_u=AZ_u1;
       //  hier word de ondergrens begrensd , dus hier tot -500
         if(AZ_u1 < -500) //limit the calculated new dutycycle to zero to prevent strange behaviour
         {
        //    indien kleiner als -500 deze waarde doorgeven
            AZ_u1 = -500;  // limit u1
         }
      //
       //  hier word de bovengrens begrensd , dus hier tot 500
         if(AZ_u1 >  500) //limit the calculated new dutycycle to 1023 to prevent strange behaviour
         {
       //     indien groter als 500 deze waarde doorgeven 
            AZ_u1 =  500;  // limit u1
         }
         
      }
/////////////////////////////////////////////////////////////////////////////////////
void EL_CalcPID ()
      {
         EL_x0 = (EL_Kr*EL_u0)/1000;                   // P-action with         Kr=100
         EL_y1 = EL_y0 + EL_x0/EL_Ti*EL_dt;
         EL_z1 = EL_y0 + EL_x0;  // I-action with timeconstant Ti= 10
         EL_u1 = EL_z0 + EL_Td*(EL_z1-EL_z0)/EL_dt;           // D-action with timeconstant Td=  1
         EL_y0=EL_y1;
         EL_z0=EL_z1;
         EL_u=EL_u1;
             //hier word de ondergrens begrensd , dus hier tot -500
         if(EL_u1 < -500) //limit the calculated new dutycycle to zero to prevent strange behaviour
         {
               //indien kleiner als -500 deze waarde doorgeve
            EL_u1 = -500;  // limit u1
         }
            //
             //hier word de bovengrens begrensd , dus hier tot 500
         if(EL_u1 >  500) //limit the calculated new dutycycle to 1023 to prevent strange behaviour
         {
             //indien groter als 500 deze waarde doorgeven
            EL_u1 =  500;  // limit u1
         }
         
      }
/////////////////////////////////////////////////////////////////////////////////////
void AZ_PWM(int AZ_speed,AZ_driv_enb)
   {
      // Drive enabelen en pwm instellen //
      // De waarde kan negatief of positief zijn, dus CW of CCW    //
      // De waarde mag tussen -500 en +500 zijn, 0 is stilstaan //
       if (AZ_speed > 1 && !input(AZ_CCW_Lswitsh))
      {

         AZ_brake_state=1;
         set_pwm_duty(3,0);                    // --> fsw = 78.12 kHz
         set_pwm_duty(4,AZ_speed);             // --> fsw = 78.12 kHz
         AZ_STILL = 1;
            
      }
       if (AZ_speed == 0)
      {
         set_pwm_duty(3,0);                    // --> fsw = 78.12 kHz
         set_pwm_duty(4,0);                    // --> fsw = 78.12 kHz
         AZ_STILL = 0;
         AZ_brake_state = 0;
      }
       if (AZ_speed < -1 && !input(AZ_CW_Lswitsh))
      {
         AZ_brake_state = 1;            
         set_pwm_duty(3,(AZ_speed * -1));       // --> fsw = 78.12 kHz
         set_pwm_duty(4,0);                    // --> fsw = 78.12 kHz
         AZ_STILL = 1;
      }

   if (   AZ_brake_state == 1)   
            {
            output_high(AZ_brake);
         output_high(AZ_Enbl_Drive);
            }         
            else
            {
            output_low(AZ_brake);
         output_low(AZ_Enbl_Drive);
            }
   }
/////////////////////////////////////////////////////////////////////////////////////
   void EL_PWM(int EL_speed,EL_driv_enb)
   {
      // Drive enabelen en pwm instellen //
      // De waarde kan negatief of positief zijn, dus CW of CCW    //
      // De waarde mag tussen -500 en +500 zijn, 0 is stilstaan //
      if (EL_speed > 1 && !input(EL_CCW_Lswitsh))
      {
         EL_brake_state=1;
         set_pwm_duty(1,0);                    // --> fsw = 78.12 kHz
         set_pwm_duty(2,EL_speed);             // --> fsw = 78.12 kHz
         EL_STILL = 1;
      }
      if (EL_speed ==0)
      {
         set_pwm_duty(1,0);                    // --> fsw = 78.12 kHz
         set_pwm_duty(2,0);                    // --> fsw = 78.12 kHz
         EL_STILL = 0;
         EL_brake_state=0;
      }
      if (EL_speed < -1 && !input(EL_CW_Lswitsh))
      {
         EL_brake_state=1;
         set_pwm_duty(1,(EL_speed * -1));       // --> fsw = 78.12 kHz
         set_pwm_duty(2,0);                    // --> fsw = 78.12 kHz
         EL_STILL = 1;
      }
   if (   EL_brake_state == 1)   
            {
            output_high(EL_brake);
         output_high(EL_Enbl_Drive);
            }         
            else
            {
            output_low(EL_brake);
         output_low(EL_Enbl_Drive);
            }
   
   }
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
   void Init_AZ()
   {
   //  nulpunt zoeken van de encoder //
      if ((!input(AZ_CW_Lswitsh)& AZ_stapteller==0))
         {
            AZ_PWM(-80,1);
            AZ_stapteller=1;
         }
      if ((input(AZ_CW_Lswitsh)& AZ_stapteller==1))
         {
         AZ_PWM(0,0);
         delay_ms(100);
         AZ_PWM(50,1);
         AZ_stapteller=2;
         }   
      if ((!input(AZ_CW_Lswitsh)& AZ_stapteller==2))
         {
         AZ_PWM(50,1);
         AZ_stapteller=3;
         }
      if ((!input(AZ_enc_Z)& AZ_stapteller==3))
         {
         AZ_PWM(0,0);
         AZ_stapteller=4;
         AZ_actu_position=10000;
         AZ_calc_position = AZ_actu_position;
         AZ_init_ok=1;
         }         
   
   
   }
/////////////////////////////////////////////////////////////////////////////////////
   void Init_EL()
   {
   //  nulpunt zoeken van de encoder //
      if ((!input(EL_CW_Lswitsh)& EL_stapteller==0))
         {
            EL_pwm(-100,1);
            EL_stapteller=1;
         }
      if ((input(EL_CW_Lswitsh)& EL_stapteller==1))
         {
         EL_pwm(0,0);
         delay_ms(100);
         EL_pwm(100,1);
         EL_stapteller=2;
         }   
      if ((!input(EL_CW_Lswitsh)& EL_stapteller==2))
         {
         EL_pwm(50,1);
         EL_stapteller=3;
         }
      if ((!input(EL_enc_Z)& EL_stapteller==3))
         {
         EL_PWM(0,0);
         EL_stapteller=4;
         EL_actu_position=10000;
         EL_calc_position = EL_actu_position;
         EL_init_ok=1;
         }         
   }
/////////////////////////////////////////////////////////////////////////////////////
void AZ_TrajectBerekening()
      {
      if (AZ_calc_position < AZ_dest_position)
         {   
            AZ_calc_position = AZ_calc_position + 1.0;
         }
      if (AZ_calc_position > AZ_dest_position)
         {   
            AZ_calc_position = AZ_calc_position - 1.0;
         }
   }
/////////////////////////////////////////////////////////////////////////////////////
void EL_TrajectBerekening()
      {
      if (EL_calc_position < EL_dest_position)
         {   
            EL_calc_position = EL_calc_position + 1.0;
         }
      if (EL_calc_position < EL_dest_position)
         {   
            EL_calc_position = EL_calc_position - 1.0;
         }
      }
/////////////////////////////////////////////////////////////////////////////////////
void main() {
   setup_timer2(TMR_INTERNAL | TMR_DIV_BY_64,500);   // prescale=64, PR2=255
   setup_compare(1, COMPARE_PWM | COMPARE_TIMER2);      // Configre for PWM mode
   setup_compare(2, COMPARE_PWM | COMPARE_TIMER2);      // Configre for PWM mode
   setup_compare(3, COMPARE_PWM | COMPARE_TIMER2);      // Configre for PWM mode
   setup_compare(4, COMPARE_PWM | COMPARE_TIMER2);      // Configre for PWM mode
   AZ_PWM(0,0);
   EL_PWM(0,0);
     EXT_INT_EDGE(L_TO_H);
   enable_interrupts(INT_timer4);
   enable_interrupts(INT_EXT1);
   enable_interrupts(INT_EXT0);
   enable_interrupts(int_rda2);
   enable_interrupts(intr_global);
   output_low(AZ_Enbl_Drive);
   AZ_actu_position = 0;
   AZ_init_ok = 0;
   AZ_stapteller=0;
   AZ_dest_position=12000;
   AZ_calc_position=2000;
//   initialisatie Elevatie Drive
   output_high(EL_Enbl_Drive);
   EL_actu_position = 0;
   EL_init_ok = 0;
   EL_stapteller=0;
   EL_dest_position=2000;
   EL_calc_position=2000;

   printf("Boot");
   do {

        //   if (Packet_ready == true)
   //      Processcommand();
   //   output_high(AZ_brake);
//      output_high(EL_brake);
        if ((AZ_init_ok != 1))//||(EL_init_ok != 1))
            {
                  if (AZ_init_ok != 1)
                     Init_AZ(); //   eerst initialisatie uitvoeren
                  //if ((AZ_init_ok == 1)&(EL_init_ok != 1))
                  //   Init_El(); //   eerst initialisatie uitvoeren
            }
         else
            {
            ///////   de regellus doorlopen
                // AZ_TrajectBerekening();
                    AZ_CalcError();
                  AZ_CalcPID();   
                  AZ_PWM((AZ_U1),1);
                //  EL_TrajectBerekening();
                  EL_CalcError();
                  EL_CalcPID();
                  EL_PWM((EL_U1*-1),1);
            }
         
      while(bkbhit)
        putc( bgetc() );
   } while (TRUE);
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sat May 21, 2011 2:34 pm     Reply with quote

_Always_, when using the hardware UART, have the keyword 'ERRORS' in the RS232 setup. This adds error recovery code to the getc routine. Only time not to do this, is if _you_ are doing this recovery yourself.
Without this, if 2 characters arrive without the RS232 interrupt being serviced, you _will_ hang the UART.

Big reason for problems, is your UART buffer size. Using '%' in the ISR, only works safely, if you use a binary buffer size (32, 64 etc.). It really should be documented in the examples. For a non binary buffer size as you have, replace the line in the ISR with:
Code:

   //next_in=(next_in+1) % BUFFER_SIZE;
   if (++next_in)==BUFFER_SIZE next_in=0;


Using a non binary buffer size forces the modulus operation to use a division, and makes it very slow. It also means that interrupts will be disabled in any eight bit divisions in the main code. The test and replace, is about 40* faster, and avoids this problem....

Best Wishes
on7nh



Joined: 05 Jun 2006
Posts: 41
Location: Belgium

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

PostPosted: Sat May 21, 2011 3:27 pm     Reply with quote

@ Ttelmah

hmmm. I did read this post..re-read because it is almost midnight....
changing the buffer size make sense...change to 64 : check
test and communication hangs still after +-20 seconds.

I did also a test with slower communication, ...the same problem.

Changed also the code you mention, but I received a error on this...

greeting,
Carl
andrewg



Joined: 17 Aug 2005
Posts: 316
Location: Perth, Western Australia

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

PostPosted: Sat May 21, 2011 10:18 pm     Reply with quote

Your code should look like:
Code:
#use rs232(baud=115200,parity=N,uart2,bits=8,errors)
If you get an error, post back the message.

Also, when coding circular buffers I prefer to use code like:
Code:
if (++ptr == BUFFER_SIZE) ptr = 0;
That precise code may change slightly depending on if I'm adding or removing to/from the buffer, or if I want it to be a LRU or MRU (least/most-recently used). The concept remains the same. No division, no power-of-2 worries, and I can use any size buffer.
_________________
Andrew
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sun May 22, 2011 2:02 am     Reply with quote

I'd suspect you get a warning, not an error.
When you add the keyword 'errors', error handling code is added. The compiler also adds a variable 'rs232_errors', _containing_ details of the errors it has seen/fixed. Since your code does not use this, you get a compiler warning. However a _warning_, _not_ and 'error'.

You can:
1) Just ignore it. It is only saying there is an unused variable - this is what most people do.
2) Prevent the error, by reading this variable. Typically just add the line:

val=rs232_errors;

somewhere in your code, where 'val' is a variable you use for something else. Then just clear val, and carry on as normal.
3) Add your own code to unlock the UART (pointless in general).
4) Carry on having the locks.....

Best Wishes
andrewg



Joined: 17 Aug 2005
Posts: 316
Location: Perth, Western Australia

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

PostPosted: Mon May 23, 2011 1:04 am     Reply with quote

I forgot about that warning message! Sad

I just add the following function to my code:
Code:
void use_rs232_errors(void)
{
  rs232_errors = 0;
}
This uses the variable and gets rid of the warning. The trick is that I don't call it anywhere, so the compiler optimises it away so it doesn't take up any space.
_________________
Andrew
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