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

RS232 problem - why do outgoing chars trigger #int_rda?

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



Joined: 20 Sep 2005
Posts: 23
Location: Glasgow, Scotland, UK

View user's profile Send private message

RS232 problem - why do outgoing chars trigger #int_rda?
PostPosted: Tue Nov 01, 2005 4:12 am     Reply with quote

I have written a code to implement a circular buffer on the received data side. Every char that I send out triggers an #int_rda and so I have to flush the circ buffer after every packet that I send out. This works after a fashion providing that the other end doesn't respond too quickly after I send, and providing that the dialog is strictly master /slave, but its really not very satisfactory...

So my real question is...Does #int_rda cover several sources of interrupt, not just just received character? & in partic., is there an #int_rda each time that the transmission char is completed? In which case, what bit do I have to test for when checking the source of the interrupt? I'll post the code if need be - just tryign to keep the length of the openign question to a min.!
Foppie



Joined: 16 Sep 2005
Posts: 138
Location: The Netherlands

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

PostPosted: Tue Nov 01, 2005 4:37 am     Reply with quote

As far as I know, the #int_rda interrupt is only called when a char is received. I never had any problems such as you describe.

What PIC do you use and what are the fuses?
Ttelmah
Guest







PostPosted: Tue Nov 01, 2005 4:43 am     Reply with quote

INT_RDA, triggers just on received data (remember though that if the incoming line goes 'low' for any other reason, this too will trigger the interrupt). There is a fully working buffered RS232 receive code in the CCS 'examples', as 'EX_SISR'.

Best Wishes
KenMacfarlane



Joined: 20 Sep 2005
Posts: 23
Location: Glasgow, Scotland, UK

View user's profile Send private message

PostPosted: Tue Nov 01, 2005 6:04 am     Reply with quote

My code differs from ex_sisr in that its non-blocking in bgetc, but other than that its similar e.g. buffer length is 32 & ptrs are 8 bits long.


Code:
#include "18f6621.h"
   //  ICD must not be TRUE if trying to build a PIC to run standalone
#device *=16   ICD=TRUE
   // ICD puts a 0 at loc 0 & use 16 bit addresses for all pointers (for 14 bit instruction word PICs)
#fuses HS,PROTECT,PUT,BROWNOUT,NOLVP,NOWDT
   // some modes (e.g. ICD) don't support LVP

#use delay(clock=10000000)
   // xtal clock frequency for SB65
#use rs232(BAUD=9600, xmit=pin_c6, rcv=pin_c7, stream = com1)
#use rs232(baud=9600, xmit=PIN_G1, rcv=PIN_G2, stream = COM2)


Still comparing with ex_sisr, but I can't see any significant differences.
I presume that CCS generate code to set TXIE = 0 somewhere in the setup assoc'd with #use rs232...
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: Tue Nov 01, 2005 7:31 am     Reply with quote

Is your target device set up to echo received characters?
_________________
Regards, Andrew

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



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

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

PostPosted: Tue Nov 01, 2005 7:41 am     Reply with quote

or are you using rs485 and have the tx and rx enabled on the transceiver?
KenMacfarlane



Joined: 20 Sep 2005
Posts: 23
Location: Glasgow, Scotland, UK

View user's profile Send private message

PostPosted: Tue Nov 01, 2005 9:05 am     Reply with quote

No, its not rs485, and I'm sending stuff to teraterm on com1, and its not echoing back (setup\terminal\local echo & answerback are unticked and so they're off).

Here's the code behind the com1 (the stream name on the pic, as well as the PC port number)
Code:

/*
Comms1.c
   interrupt driver serial comms rtns

Revisions:
  Date: to 1/7/2005, with v1.23j

Changes made:
   circ buff code rewritten (it didn't work)
   Xon/off handling: signalled via gbRxrBuffTooFull: True if in XOFF

By: Ken

*/


/********************************************/
// variables to implement a circ buffer for Rx
/********************************************/
#define BuffNotEmpty (RxWriteIndex!=RxReadIndex)
   /* effectively a 1 bit flag, equiv to kbhit() in non-buffered apps
   - evaluated directly from checking the ptrs.  */


// ptrs to the circ buffer..
byte    RxWriteIndex;
   /* volatile - i.e. gets changed during sercomms'
   INT_RDA interrupt, so must be read/set atomically
    - but I'm not using interrupts of a higher
   priority so that's ok */

byte    RxReadIndex;
   // non-vol - changed only when chars are read out

char    RxBuffer[BUFFER_SIZE], *pRxBuffer = RxBuffer;
   // circ buffer: addressing is only quick if the length is a power of 2 & 2^8 works best of all

int1 gbRxrBuffTooFull;
byte    nRxdCharWaiting;
/********************************************/


/*********************************************
 Serial Interrupt Service Routine (ISR)
 Rx'd Chars go into a circ RxBuffer
*********************************************/
#int_rda
void rs232_handler(void)
{
byte t;

  RxBuffer[RxWriteIndex] =  getch(); // why not getc?

     /* don't know if XOFF could be anywhere in the stream,
      or just at the start of a reply to a status enq. msg,
      so I'll test every char as soon as it rx'd, for
      max. responsiveness... */

  if(RxBuffer[RxWriteIndex] == XOFF)
    gbRxrBuffTooFull = TRUE;
  if(RxBuffer[RxWriteIndex] == XON) // <017> is XON
    gbRxrBuffTooFull = FALSE;

   // bump the incoming ptr around the circle..
  RxWriteIndex = (RxWriteIndex+1) % BUFFER_SIZE;
                         /* increment pointer: overflow/wrap around handles
                         itself because buffer size is <= 256 and
                         ptr is 8bits long */
   nRxdCharWaiting++;
}

void COM_FlushRxBuffer(void)
{
   RxReadIndex = 0;
   RxWriteIndex = 0;
      //   BuffNotEmpty = FALSE; no need to update it now - no longer a copy
   nRxdCharWaiting = 0;

   // clear the buffer so that you can see whats gone into it - it doesn't get zeroed on reset
   {
      int i;

      for (i=0; i < BUFFER_SIZE; i++)
         RxBuffer[i]=0;
   }
}

/*
COM_TxStr

Seems identical to fputs - wonder why they didn't just use fputs!

sends a null terminated char string pointed to by DataStr over the rs232 xmit pin
does not block even under XOFF because I still have to be able to query status
by comparison, putc send a char over the rs232 xmit pin

      from SendULRec: this rtn sends 24 chars searching for the Null.
      What if there's a stray one?
      This isn't safe enough! mod it to count through the chars!


Limitations:
   Cannot take a ptr to a constant string held in ROM
   - have to use an intermediary like pszTmp
*/
void COM_TxStr(char * DataStr)
{
   while (*DataStr) // transmit till you find the NULL.
      putc(*DataStr++);
}


/*
COM_RxChar
   returns either the next char from a circ buffer (RxBuffer)
   containing the chars received by the serial port,
   or int16 RXEMPTY, indicating that the circ buffer is empty
   (so the caller  should test for this after every call)
   Does not block.
    This is the buffered equiv of getc
    An improved equiv of CCS' BYTE bgetc(), from their ex_sisr.c example
*/
int16 COM_RxChar(void)
{
int16 RxData = RXEMPTY;

   if (BuffNotEmpty) // i.e. if the head leads the tail, there's data there to be dished out
   {
      RxData = (int16)RxBuffer[RxReadIndex];
      RxReadIndex = (RxReadIndex+1) % BUFFER_SIZE;

      nRxdCharWaiting--;

   }
   return (RxData);
}


/*
fgetsCom1CircBuf(char * Buff)

A souped up version of fgets - this gets the chars from the circ buff assoc'd
with COM1, stuffed by int_rda.

By comparison, fgets gets the chars directly from uart, not a circ buff (so it relies on kbhit being called regularly
enough for fgets not to missing the start of the string)
*/
void fgetsCom1CircBuf(char * Buff)
{
  while( BuffNotEmpty )
      *Buff++ = (int8)COM_RxChar();

   *Buff  = '\0'; // add trailing NULL
}




and here's the noddy test prog that I'm using to call these...
Code:

/*********************************************************

Filename: Test8.c

Purpose:
  Comms Tester:
   1's out of Com1 & 2's out of Com2
   Red led on Reception of anything on Com1
   Green for Com2
   Stalking horse for debugging problem with TxD appearing in RxD CircBuffer

Staring with:
   Continuous
   1's out of Com1 & 2's out of Com2
   to allow DS to ID the wiring fault on the Vero DB

Derived from Test5 SB65 BothComs.c

Revisions:
  Date:
   Changes made:
  By:

Revisions:
  Date:               30/9/'05
   Changes made: Rc0 & 1 swapped to compensate for miswiring
                        so RTS wasn't being driven

Notes: works on 6621 RC6&7, with 10MHz xtal(easy to forget)

*********************************************************/


#include "18f6621.h"
   //  ICD must not be TRUE if trying to build a PIC to run standalone
#device *=16   ICD=TRUE
   // ICD puts a 0 at loc 0 & use 16 bit addresses for all pointers (for 14 bit instruction word PICs)
#fuses HS,PROTECT,PUT,BROWNOUT,NOLVP,NOWDT
   // some modes (e.g. ICD) don't support LVP

#use delay(clock=10000000)
   // xtal clock frequency for SB65
#use rs232(BAUD=9600, xmit=pin_c6, rcv=pin_c7, stream = com1)
#use rs232(baud=9600, xmit=PIN_G1, rcv=PIN_G2, stream = COM2)


// these form defs.h:...
#define ON   1
#define OFF   0
#define ENABLED   1
#define DISABLED   0


#define UWORD int16
// #define UBYTE unsigned char // globally replaced with int8
// #define BOOL short int replaced by boolean, which is a built-in type

#define LINE_LENGTH 20 // 16 plus Nul, plus 3 byte margin for error

#define LCD_COL0 0 // beware of dup define that is keypad's COL0 - not the same thing
#define LCD_ROW0 0
#define LCD_ROW1 1 // e.g. lcd_gotoxy(LCD_COL0, LCD_ROW0)


char Tmp[LINE_LENGTH], *pszTmp = Tmp; // one global  string, one line long, for sprintf'ing to the LCD
// ...end of defs.h


#include  <string.h>

#include "..\common\KeypadCodes.h"
#include "..\common\prototp.h"
#include "..\common\PortPinsConfig.h"
#include "..\common\LCD.h"
#include "..\common\comms.h"
// the other .c files that are compiled in... the compiler doesn't support modularisation - a 7000 line compile every time!!!
//#include "internal_eeprom.c" // read_ & write_eeprom r&w to the pic's internal eeprom

//include C files
//#include "..\common\PICconfig.c"    // commented
//#include "..\common\i2c.c"          // needed: e.g. i2c_start
#include "..\common\Comms1.c"        // Serial RX Interrupt Service Routine (ISR) * com buffer handlers
#include "..\common\Comms2.c"
#include "..\common\LCD.c"          // commented
//#include "..\common\Keypad.c"

//#include "..\common\RTC.c" // need RTC_Initialise

// prototypes def'd in this file, in the order that they're defined...
void main(void);
void Beep_ms(int16 n); // n = beepLenMillisecs

// file scope variables:


/******************************************/
/******************************************/
void Init(void)
{
   setup_adc_ports(NO_ANALOGS);

   set_tris_a(0x00);

//   port_b_pullups(true);   // keypad uses internal pullups
//   set_tris_b(0xff);

   set_tris_c(0B10011101);
   // TXI1E = 0;    // disable tx interrupts  - but won't compile

   output_c  (0B00000000); // initially, Reset & RTS are deasserted: xx0x xx0x. All other bits are inputs
   delay_ms(1);               // RTS =  "Request to Send to me"

   output_c  (0B00100000);
      /* xx1x xxx:  assert ReSeT active high (bit5), assert rts(bit1) active Low
      (cmos is opposite of rs232):
      bit1, all other bits don't care */
   delay_ms(50);

   output_c  (0B00000000);
               // xx0xxx0x:  deassert RST (i.e. -> low) and leave rts(bit1) asserted (low)

/* D & E not used
   set_tris_d(0x00);      // set PRT port to All outputs
   set_tris_e(0x04);      // set E.2 to input all other pins to outputs
*/
   set_tris_f(0x00);      // all outputs

   disable_interrupts(GLOBAL);
  enable_interrupts(int_rda);  // msgs from the pc
  enable_interrupts(int_rda2); // circ buff for barcodes coming in
   enable_interrupts(int_rb); // TS PassA
   enable_interrupts(GLOBAL);

// no i2c anyway...
//   output_float(I2C_SCL);
//   output_float(I2C_SDA);

   LCD_Initialise();

                                             //  no need for gVersionString yet!
   sprintf(pszTmp, "(Comms)Test8");
   LCD_putstr_xy(pszTmp, LCD_COL0, LCD_ROW0);
   sprintf(pszTmp, "1's->Com1,2's->2");
   LCD_putstr_xy(pszTmp, LCD_COL0, LCD_ROW1);

   Beep_ms(100);
}

/******************************************/
void Beep_ms(int16 n) // n = beepLenMillisecs in the prototype
{
   Output_high(pin_f0); // On when 1/True

  for ( ; n != 0; n--) // lifted from the CCS manual: delay won't accept var args > 255
     delay_ms(1); // & I haven't got time to chop n up into chunks & do call fewer calls - yuk!!
   Output_low(pin_f0);    // Off again before returning

}
static int8
iMillisecsInThisState1; // assoc with AmberToggle

void AmberToggleEvery ( int8 Period )
{
   // Actions once per Period...
   if(iMillisecsInThisState1++ > Period)
   {
      iMillisecsInThisState1 = 0;
      if(input(pin_f0))
      {
         Output_low(pin_f0);
      }
      else
      {
         Output_high(pin_f0);
       LCD_ClearLower();
      }
   }
   delay_ms(1);
}


void main()
{
   char c;
   int16 i;

   Init();

   COM_FlushRxBuffer();
   puts("Com1 running...", com1);

   // a breakpoint here show 14 or 15 chars in RxBuffer (its difficult to count in ICD-U due to the time that mouse-over last for!

#define COM2_ON_TOO FALSE // in case this is due to some cross coupling between the 2 streams
#if COM2_ON_TOO
   COM_FlushRxBuffer2();
   puts("Com2 running...", com2);
#endif   
   // and now emit a stream of 1's on com1
   // and 2's on com2   
   while(1)
   {
      AmberToggleEvery(250); // more use than delay_us(1000L);
      putc(0,com1); putc('1',com1);
#if COM2_ON_TOO
      putc(0, com2); putc('2', com2);
#endif
   }
}



At the point where I've put the breakpoint in main,
RxWriteIndex = 14
just after sending out "Com1 running..." which is 15 chars long. RxBuffer doesn't contain "Com1 running..." - it contains a string of chars starting e circumflex (ascii 130 decimal), which looks nothing like the string sent out, but almost as if the baud rate is half what it should be.
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Tue Nov 01, 2005 9:27 am     Reply with quote

Is it possible that you are having cross-talk between your RXD and TXD lines? If you have an oscilloscope available, hook it up to see what you're getting on your RXD line. Maybe try a different part. They have been known to go bad. Wink

Ronald
Guest








PostPosted: Tue Nov 01, 2005 11:43 am     Reply with quote

First, I'd get rid of your three array accesses in the interrupt. Load the value into a temporary store, and save it/refer to it from this, using just a single array access. Array accesses are _slow_, they involve about twenty machine cycles each, against just one (or at worst two, if the bank has to change), for a 'fixed' variable.
If you keep your buffers to binary multiples, the modulus is much more rapidly be generated by just an 'and' operation. This again helps speed.
You don't have 'errors' in your RS232 declaration, or the equivalent of a test and toggling CREN in the interrupt handler. If an error does arise, it'll hand the UART.
I really would be looking hard at the hardware. The following has worked fine for me, for years now, I have just amended the get character code to behave like yours.:
Code:

//Buffer handling tests and code
#define isempty(buff,in,out,size) (in==out)
#define hasdata(buff,in,out,size) (!(in==out))
#define isfull(buff,in,out,size) (((in+1)&(size-1))==out)
#define tobuff(buff,in,out,size,chr) { buff[in]=chr;\
   in=((in+1) & (size-1));\
   if (in==out) out=((out+1) & (size-1));\
   }
#define frombuff(buff,in,out,size) (btemp=buff[out],\
   out=(out+1) & (size-1), \
   btemp)
#define ifrombuff(buff,in,out,size) (ibtemp=buff[out],\
   out=(out+1) & (size-1), \
   ibtemp)
#define clrbuff(buff,in,out,size) {in=0;\
   out=0;}

#define SRBUFF (16)

/* Sizes and numbers for the buffers */
/* Each buffer uses a character array. Size is in the 'S' defines, and
   the init_buff routine will have to be amended to add extra buffers if required */
int RSRin,RSRout;
int btemp,ibtemp;
unsigned int RSRbuff[SRBUFF+1];

#int_RDA
void RDA_isr(void) {
   int8 cval;
   //Here a RS232 receive character has arrived - store and set flag.
   //Also clear 'overrun' if flagged.
   cval=RCREG;
   tobuff(RSRbuff,RSRin,RSRout,SRBUFF,cval);
   if (OERR) {
      CREN=0;
      CREN=1;
   }
  if(cval == XOFF)
    gbRxrBuffTooFull = TRUE;
  if(cval == XON) // <017> is XON
    gbRxrBuffTooFull = FALSE;
}

int16 nbgetc(void) {
   if (hasdata(RSRBUFF,RSRIN,RSROUT,SRBUFF)) return((int16)frombuff(RSRBUFF,RSRIN,RSROUT,SRBUFF));
   return(RXEMPTY);
}

Try this, and if you still have the same problem, you have a hardware fault of some sort.

Best Wishes
KenMacfarlane



Joined: 20 Sep 2005
Posts: 23
Location: Glasgow, Scotland, UK

View user's profile Send private message

PostPosted: Tue Nov 01, 2005 12:03 pm     Reply with quote

There is data both on the RC7 & 6 - so it does seem to be a hardware problem. How things have worked up till now, I'll never know!

Thanks, guest, for the code - I'm afraid that don't follow all of your #defines - all a bit to clever for the likes of me, but it doesn't look like the isr is too slow, after all. More tomorrow!
KenMacfarlane



Joined: 20 Sep 2005
Posts: 23
Location: Glasgow, Scotland, UK

View user's profile Send private message

Pickup between RC6 & 7
PostPosted: Thu Nov 03, 2005 9:41 am     Reply with quote

After various experiments (same code, 2 different cpu pcb's; recompiled code on an 18f4620 on a different design of pcb, rather than a 6621), I have found that I have nearly 4 volts worth of data on the RCV pin when I'm streaming 1's out of RC6). Help!!!! Pullups/Pulldowns aren't going to suppress this sort of pickup! In fact, the bits have the leading edge rounded, so there is some capacitive loading there already (scope probe on x10, maybe not tuned up for best hifreq response, though).

I'm thinking about lifting the RC6/Tx pin with scalpel, to prove that the problem is caused by inductive coupling with the RCV data tracking, but
the 6621 is a TQFP, so the pins are very close together. RCV is an end of row pin, right on the corner, and XMIT is next door, one pin in from the corner.

I didn't think that layout would be all that critical at 9600 baud, even with pin spacing this close...I've checked for solder whiskers under a magnifier & there's 10 Meg between the pins. Anybody got any advice?
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 Nov 03, 2005 6:49 pm     Reply with quote

Look for a fault in your RS232 line driver hardware.
_________________
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