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

PIC24f: Only getting first 5 bytes read from RS232

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



Joined: 10 Apr 2009
Posts: 4

View user's profile Send private message

PIC24f: Only getting first 5 bytes read from RS232
PostPosted: Thu Apr 23, 2009 11:09 am     Reply with quote

I'm not sure what's going on, but when sending data to the PIC over RS232 I'm only getting the first 5 bytes that I send.

The PIC is a PIC24FJ128GA006 Dev kit, compiled with PCD 4.091.

Here's the code that's got RS232 in it:

Code:

#include <24fj128ga006.h>
#include <stdlib.h>
#build (stack=256)

#fuses   NOPROTECT,NOWDT  //Use internal oscillator /*pic24 fuses*/
#use delay(clock=8000000, internal)

#use rs232(baud=9600,parity=N,bits=8, UART1, ERRORS,stream=payload)
#use rs232(baud=9600,parity=N,bits=8, UART2,stream=sensor)

#int_rda
void serial_isr() {
 
   getInput();
   processInput();
     
   if (output) // if output needed
   {
     fprintf(payload, "%s\r\n", msg);
     output = FALSE; // reset output flag
   } 
}

/*******************************************************************************
 * UART2 ISR
 * Function called when data is available in UART2 buffer
 ******************************************************************************/
#int_rda2
void serial_isr2()
{
   sensor_rx = TRUE;
   fprintf(payload, "data found on UART2\r\n");
   getSensorInput();
}

void main(void) {

  //uint32_t batChkDelay = 0; // for extending time between checks
  //uint32_t batChkMult = 0; //For extending time between checks
 
  // Initialize PIC configuration (set clock and pins)
  Init();
 
  set_timer1(0);
  //setup_counters(RTCC_INTERNAL, RTCC_DIV_256);
  enable_interrupts(int_rda);
  enable_interrupts(int_rda2);
  enable_interrupts(int_rtc);
  enable_interrupts(INTR_GLOBAL);
  //sleep();
  while(TRUE);//{sleep();}
}

/*******************************************************************************
 * Function to get input from sensor over RS232.
 ******************************************************************************/
 void getSensorInput(void)
 {
   char buffer[512] = {0};
   uint16_t i = 0;
   long timeout;
   
   while(i < 512)
   {
      while(FALSE == kbhit(sensor) && (++timeout < 5000))
      {
         delay_us(100);
      }
      if(kbhit(sensor))
      {
         buffer[i] = fgetc(sensor);
         //if(buffer[i] == 0x04)
         //   break;
         i++;
         timeout = 0;
      }
      else
      {
         fprintf(payload, "Timeout of rs232 read\r\n");
         fprintf(payload, "buffer contains %s\r\n", buffer);
         fprintf(payload, "got %d bytes from UART2\r\n", i);
         return;
      }
   }
 }

void Init(void) {

  // Set Oscillator
  osccon=0x70;   //0111000  changing the setting of bits 6-4 sets internal oscillator to 8MHz
  delay_ms(500);           // give it a chance to settle before garbling output
  output_high(PIN_G2);
  output_high(PIN_G3);
//#endif
  //setup_uart(1, payload, UART_WAKEUP_ON_RDA); // sets the RDA/rs232 interrupt to wakeup from sleep mode
  sprintf(msg, "\r\nCompiled on %s at %s", __DATE__, __TIME__);
  PutLine(msg);

  //disable_interrupts(INT_RTCC);
}





right now when I test it by sending it data over the second UART it receives only the first 5 bytes of data, and then on subsequent data transfers it repeats the last byte received 5 times.

I'm sending it data with `echo "ABCDEFG" > /dev/ttyS0`

This is the result:
Compiled on 23-Apr-09 at 12:09:20
data found on UART2
Timeout of rs232 read
buffer contains ABCDE
got 5 bytes from UART2
data found on UART2
Timeout of rs232 read
buffer contains EEEEE
got 5 bytes from UART2
data found on UART2
Timeout of rs232 read
buffer contains EEEEE
got 5 bytes from UART2

I can also send it data with a python script and get the same results.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Apr 23, 2009 12:27 pm     Reply with quote

Simply, the lengthy debug output from the interrupt procedure is causing an receiver FIFO overflow. Such operations must be avoided in an interrupt, unless you have a buffered RS232 output.

The problem isn't actually related to PIC24.
krogers



Joined: 10 Apr 2009
Posts: 4

View user's profile Send private message

PostPosted: Thu Apr 23, 2009 1:18 pm     Reply with quote

I removed all the printfs from the interrupt code, have the while(TRUE) loop in main printing the contents of the buffer I'm copying into every so often, and now it's getting the first 6 bytes and repeating that 6th byte on every getc after it. So as the buffer fills it starts as:

ABCDEF
ABCDEFFFFFFF
ABCDEFFFFFFFFFFFFF
...

What I really don't understand is why it gets stuck on that last byte, it never seems to clear it from where it's reading. For what it's worth, if I send less than 5 bytes it works consistently the way I'd expect.
Ttelmah
Guest







PostPosted: Thu Apr 23, 2009 3:01 pm     Reply with quote

Look at how the serial is handled in EX_SISR.
This is the approach you need to use. As a general rule, always get out of interrupts as soon as possible.

Best Wishes
asmallri



Joined: 12 Aug 2004
Posts: 1634
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Apr 23, 2009 7:44 pm     Reply with quote

Looks like your delay function call in the ISR is the culprit. In general, if you need to delay more than a few us total in an ISR then you are not using ISRs correctly.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri Apr 24, 2009 1:08 am     Reply with quote

Quote:
In general, if you need to delay more than a few us total in an ISR then you are not using ISRs correctly.
Right!

And it's also not the intended normal operation of an ISR to stay in a loop waiting for the next characters. I'm not sure, what's causing exactly the UART to freeze. Most likely it's an overrun. It's not cleared in your code, cause ERRORS isn't specified for this UART.

Anyway, you should change your design towards regular interrupt processing. That means, receive the characters to a buffer in the ISR, possibly set some flags to signal events, receiption of trigger characters and so on. And process the received data respectively react on the flags in the main loop, issue debug messages without haste.
Guest








PostPosted: Fri Apr 24, 2009 8:26 am     Reply with quote

Thanks for the help, I've made some more changes so that I'm in and out of the ISR as quick as I can, and letting the main loop handle the reading from the UART. But now I only get the first two bytes from the RS232. Also I enabled the errors, but I can't find any documentation that explains what rs232_errors means.


Code:

#int_rda2
void serial_isr2()
{
   sensor_rx = TRUE;
   return;
}

void main(void) {
 
  // Initialize PIC configuration (set clock and pins)
  Init();
 
  set_timer1(0);
  enable_interrupts(int_rda);
  enable_interrupts(int_rda2);
  enable_interrupts(int_rtc);
  enable_interrupts(INTR_GLOBAL);
  while(TRUE)
  {
     if(sensor_rx)
     {
        getSensorInput();
        if(rs232_errors)
        {
           fprintf(payload, "rs232_errors = 0x%x\r\n", rs232_errors);
           rs232_errors = 0;
        }
     }
  }
}

 void getSensorInput(void)
 {
   
   while(sb_index < 511)
   {
      if(kbhit(sensor))
      {
         sensor_buffer[sb_index] = fgetc(sensor);
         //if(buffer[sb_index] == 0x04)
         //   break;
         sb_index++;
      }
      else
      {
         break;
      }
   }
   sensor_rx = FALSE;
   fprintf(payload, "sensor buffer: %s\r\n", sensor_buffer);
   return;
 }


Compiled on 24-Apr-09 at 10:05:28
sensor buffer: A
rs232_errors = 0x11
sensor buffer: AB
rs232_errors = 0x13
sensor buffer: ABA
rs232_errors = 0x11
sensor buffer: ABAB
rs232_errors = 0x13
sensor buffer: ABABA
rs232_errors = 0x11
sensor buffer: ABABAB
rs232_errors = 0x13
Ttelmah
Guest







PostPosted: Fri Apr 24, 2009 8:44 am     Reply with quote

Your 'new' ISR, is not any better.
With this, you might as well not use the ISR at all.
As I said before, look at EX_SISR.

The interrupt code should do the _single job_, associated with the simple fact that _one_ character _is_ ready in the hardware. Nothing more, and _nothing less_. You new code does _less_...

ERRORS, is documented in the manual, in the sense of telling you that this will cause the compiler to add code to clear hardware errors. Then look further down the #use RS232 entry for the definitions of the RS232_ERRORS variable. It is though the automatic operation of clearing the hardware errors, that is important in terms of not causing a lockup.

Best Wishes
asmallri



Joined: 12 Aug 2004
Posts: 1634
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri Apr 24, 2009 8:51 am     Reply with quote

This is an example of what a receive interrupt handler should look like:

Code:
#int_RDA
void serial_isr()
   {
   RxBaseC[RxHeadC++]=getc();
   if (RxHeadC >= RxCQsize)
      RxHeadC = 0;
   }


This assumes you used the ERRORS option in the #use RS232 directive

Here is an equivalent function for a compiler (C18) that does not have automatic handling of errors

Code:
#pragma interruptlow COMM1_isr
void COMM1_isr(void)
///////////////////////////////////////////////////////////////////////////
// Interrupt Handler for COM1 UART receive interrupt
///////////////////////////////////////////////////////////////////////////
   {
   // test for overrun error
   if (RCSTAbits.OERR)
      {
      RCSTAbits.CREN=0;      // clear continous receive bit
      RCSTAbits.CREN=1;      // set continous receive bit
      }

   RxBaseC[RxHeadC++]=RCREG;
   if (RxHeadC >= RxCQsize)
      RxHeadC = 0;
   }

_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
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