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

strange

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



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

strange
PostPosted: Fri Jun 17, 2005 5:56 am     Reply with quote

on RDA interrupt this happens:

Code:
#int_RDA
RDA_isr()
{
   int8 datalengte,i;

   disable_interrupts(INT_RDA);

   if (getch() == COMMANDO_BYTE)             // We krijgen een commando
   {
      char data[47];

      for (i = 0 ; i < 5 ; i++)  // 5 karakters inlezen van de PC
      {                    //
         data [i] = getc();
      }
      datalengte = data [4];

    if ( datalengte > 0 )         // data bufferen
    {
         for (i = 5 ; i < (datalengte+5) ; i++)
         {
            data [i] = getc();
         }
    }

// Alle DATA is binnen gelezen
// Commando gaan toetsen:
   switch(Check_commando(data))
   {
   case VBAT_METEN:
      Meet_Vbat(&Vbat);
      Send_Vbat(Vbat);
      break;

  //.... other cases
   case ENABLE_200V:   
      BR_WAKE();
      break;


 }

}    //if c == COM
   else
   {
      BR_WAKE();
   }

   enable_interrupts(INT_RDA);
}


So the data get's buffered and the command is being tested (Checkcommando *data). Everything OK..

But then, check the BR_WAKE() function. It is in a file functies.h that is included in the main file.:

Code:
//********************** BRAILLE WAKE = 200V aan  ****************************//
//Het 200V blok wordt aangeschakeld
BR_WAKE()
{
   output_low(BR_SLEEP);
   BR_CLEAR(40);
   [size=18][b]delay_ms(50);[/b][/size]
}


When I DONT use delay_ms(50); everything works, but when I use the delay instruction, the program hangs on an RDA interrupt! How is that? solution?
Ttelmah
Guest







PostPosted: Fri Jun 17, 2005 7:32 am     Reply with quote

First: Do _not_ disable and enable the interrupt inside the handler. The chip itself disables the _global_ interrupt for you. Ideally (personal choice here), you can add the option 'noclear' to the handler header, then clear the interrupt yourself as the first line of the handling code, which then allows you to test at the end of the handler for the interrupt being set, and loop back inside the handler if it is. This gives better handling of 'fast' interrupts than the default code. However the simplest solution is to not fiddle with the interrupts at all in the handler.
Second, your code should only read one character from the serial. As it stands, if you see the incoming 'COMMANDO_BYTE', the code will sit inside the interrupt handler for five more character times. Look at a 'state machine', that in the first state, looks for this command byte, if it is found, it advances to the next state, and exits.. On the next interrupt the first character is read, ad you advance to the next state. As written, the code is only using interrupts to find the first character, which is inefficient, and may cause problems for other code. If the five characters do not arrive, the code will be 'hung' inside the handler.
I'd suspect your 'hang', is the result of more characters arriving while you delay. If so, adding 'errors' to your #use RS232, _may_ prevent this happening, but a better solution is not to have delays in interrupt handlers. There have been a _lot_ of posts explaining the problems this can cause in the past. Why on earth would you want to delay, of the charater is not a recognised one?.
The code as written, is a good example, of how _not_ to write an interrupt handler.

Best Wishes
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Sat Jun 18, 2005 8:30 am     Reply with quote

Ttelmah is right you shouldn't try to pick up more than one char in an RDA interrupt service routine. There must be a hundred posts on this issue... to have a chance of success you need to learn from others and have your interrupt routine accept the single char thats been recieved and save it in a circular buffer. In you main routine you can parse the circular buffer looking for the command sequences you want.
This circular buffer is provided behind the scenes by PC operating systems so it is often ommitted in a PIC design..the PIC hardware buffer is two chars deep one just received and one possibly being received..you will need a circular buffer. As for the clearing of interrupt flags it is always good practice to look at the .lst file ..thats where you can see that the compiler does it for you.
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Mon Jun 20, 2005 1:07 am     Reply with quote

Ttelmah wrote:
First: Do _not_ disable and enable the interrupt inside the handler. The chip itself disables the _global_ interrupt for you. Ideally (personal choice here), you can add the option 'noclear' to the handler header, then clear the interrupt yourself as the first line of the handling code, which then allows you to test at the end of the handler for the interrupt being set, and loop back inside the handler if it is. This gives better handling of 'fast' interrupts than the default code. However the simplest solution is to not fiddle with the interrupts at all in the handler.
Second, your code should only read one character from the serial. As it stands, if you see the incoming 'COMMANDO_BYTE', the code will sit inside the interrupt handler for five more character times. Look at a 'state machine', that in the first state, looks for this command byte, if it is found, it advances to the next state, and exits.. On the next interrupt the first character is read, ad you advance to the next state. As written, the code is only using interrupts to find the first character, which is inefficient, and may cause problems for other code. If the five characters do not arrive, the code will be 'hung' inside the handler.
I'd suspect your 'hang', is the result of more characters arriving while you delay. If so, adding 'errors' to your #use RS232, _may_ prevent this happening, but a better solution is not to have delays in interrupt handlers. There have been a _lot_ of posts explaining the problems this can cause in the past. Why on earth would you want to delay, of the charater is not a recognised one?.
The code as written, is a good example, of how _not_ to write an interrupt handler.

Best Wishes


All the data is sent for sure, then it's being processed: it jumps to a function and there is a delay. But if I send ANY other command that does NOT execute the delay command, the code ALSO hangs!

*What does the 'errors' statement do?
* Is the use of timed_getc() a solution? So that you can't be stuck?

@Douglas Kennedy> Any idea how I can change my code to a safer one?
edit: the problem is that I have different buffers, one that holds the command, an another with data, there isn't always being data sent:

The protocol is as follows:

0xAA, CMD0,CMD1,CMD2,CMD3, DL, D0,D1...Ddl

If DL = 0 there is no data being sent, the command is being checked and executed.

edit: the delay is a hardware timing issue.. time given for a certain voltage to rise
Ttelmah
Guest







PostPosted: Mon Jun 20, 2005 4:53 am     Reply with quote

'Errors', will prevent the UART hardware hanging, if the internal hardware buffer overflows.
Consider rewriting, using the ex_sisr code that comes with the compiler. This shows how to buffer incoming characters. Have your main code, use bkbhit to check for characters waiting. When one arrives, retrieve it with bgetc, and check if it is the command header. If so, look for the rest of the command, using almost exactly the code you currently have in your interrupt. The key with this, is that the UART will still retrieve characters while you are doing this.
Alternatively, consider a state machine. You have a static variable 'state', that you set to zero, then a switch statement in the interrupt handler, using this variable. At the start of the interrupt handler, you retrieve the character (since there has been an interrupt, there will be a character). Then you enter the switch statment, which as the first state, checks for this being the command character. If it is, you increment the state, and exit. If not, you leave the state where it is. You then advance through the states for each incoming character, storing them into the array as required. On the last character, you launch a hardware timer, and set the state back to zero. When the hardware timer expires (and interrupts), you do what you need at the end of the time.

Best Wishesw
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Mon Jun 20, 2005 5:39 am     Reply with quote

I'm having difficulties understanding that code, can you post in code what you mean?

What exactly is the problem with my code? That while the UART is waiting for a character, - and none arrives - the program is stuck in that isr() ?
Then I can use timed_getc() no?
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Mon Jun 20, 2005 6:23 am     Reply with quote

Ok I modified the code, so that it can NEVER get stuck inside the isr();
Can you evaluate?

Code:
//***************************** RDA interrupt ********************************//
//Als een karakter wordt ontvangen door de UART
#int_RDA
RDA_isr()
{
   int8 datalengte = 0,i;

   if (getch() == COMMANDO_BYTE)             // We krijgen een commando
   {
      char data[47];
      long timeout = 0;

      for (i = 0 ; i < 5 ; i++)  // 5 karakters inlezen van de PC
      {                    //
         while (!kbhit() && (++timeout<50000))
            delay_us(10);
           
         if (kbhit())
            data [i] = getc();

         else
            break;
         
      }

    datalengte = data [4];
    timeout = 0;
           
    if ( datalengte > 0 )         // data bufferen
    {
         for (i = 5 ; i < (datalengte+5) ; i++)
         {
            while (!kbhit() && (++timeout<50000))
               delay_us(10);
           
            if (kbhit())
               data [i] = getc();

            else
               break;
         }
    }

// Alle DATA is binnen gelezen
// Commando gaan toetsen:
   switch(Check_commando(data))
   {
   case VBAT_METEN:
      Meet_Vbat(&Vbat);
      Send_Vbat(Vbat);
      break;

   case VADAP_METEN:
      Meet_Vadap(&Vadap);
      Send_Vadap(Vadap);
      break;

   case ADAPTER_STATUS_VRAGEN:
      if (!input(POWER_GOOD))
         printf("%c%S%c",COMMANDO_BYTE, ADAPTER_IN_COMMANDO,0);
      else
         printf("%c%S%c",COMMANDO_BYTE, ADAPTER_UIT_COMMANDO,0);
      break;

   case LAAD_STATUS_VRAGEN:
      if (!input(CHARGE_ON))
         printf("%c%S%c",COMMANDO_BYTE, START_LADEN_COMMANDO,0);
      else
         printf("%c%S%c",COMMANDO_BYTE, EINDE_LADEN_COMMANDO,0);

   case SCHRIJF_NAAR_LEESREGEL:
      setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_XMIT_L_TO_H|SPI_CLK_DIV_4);
      for (i = 5 ; i < datalengte+5 ; i++)
      {
         spi_write(data[i]);
      }
      output_high(BR_STROBE);       // STROBE PULS
      output_low(BR_STROBE);
      setup_spi(FALSE);
      break;

   case CLEAR_DISPLAY:
      BR_CLEAR(40);
      break;

   case ENABLE_200V:
      BR_WAKE();
      break;

   case DISABLE_200V:
      BR_SLAAP();
      break;

   case GA_IN_SLEEP:
      sleep_mode_2 = TRUE;
      break;

   default:
      break;
 }

}    //if c == COM
   else     // iets anders dan commando_byte binnengekregen?
   {
   }
}//RDA ISR


edit: the software 'flips' on the use of delay_MS() inside ISR(), instead you must use delay_us(999) in a loop.. CCS => bugreport
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