|
|
View previous topic :: View next topic |
Author |
Message |
KenMacfarlane
Joined: 20 Sep 2005 Posts: 23 Location: Glasgow, Scotland, UK
|
RS232 problem - why do outgoing chars trigger #int_rda? |
Posted: Tue Nov 01, 2005 4:12 am |
|
|
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
|
|
Posted: Tue Nov 01, 2005 4:37 am |
|
|
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
|
|
Posted: Tue Nov 01, 2005 4:43 am |
|
|
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
|
|
Posted: Tue Nov 01, 2005 6:04 am |
|
|
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
|
|
Posted: Tue Nov 01, 2005 7:31 am |
|
|
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
|
|
Posted: Tue Nov 01, 2005 7:41 am |
|
|
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
|
|
Posted: Tue Nov 01, 2005 9:05 am |
|
|
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
|
|
Posted: Tue Nov 01, 2005 9:27 am |
|
|
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.
Ronald |
|
|
Guest
|
|
Posted: Tue Nov 01, 2005 11:43 am |
|
|
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
|
|
Posted: Tue Nov 01, 2005 12:03 pm |
|
|
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
|
Pickup between RC6 & 7 |
Posted: Thu Nov 03, 2005 9:41 am |
|
|
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
|
|
Posted: Thu Nov 03, 2005 6:49 pm |
|
|
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!! |
|
|
|
|
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
|