View previous topic :: View next topic |
Author |
Message |
jahan
Joined: 04 Apr 2005 Posts: 63
|
18F4520 and INT_TBE / INT_RDA |
Posted: Sun Aug 03, 2008 12:09 am |
|
|
Question about Serial Interrupts Buffers.
Does 18F4520 have internal buffer for serial communication?
Do I still need to use the 2 INT's for serial data buffers?
Thanks |
|
|
Ttelmah Guest
|
|
Posted: Sun Aug 03, 2008 2:21 am |
|
|
All PICs have a _small_ buffer. The size is a minimum of just under two characters (one in the input shift register, and the separate read latch), and the same in the output direction. PICs like the 4520, have an extra byte in the read buffer. Enough to help handle faster data rates without character loss, but not anything more.
Yes. There are effectively two separate devices. This is required, because this is an asynchronous bus, so data can arrive and depart at different times (unlike a synchronous bus, where on device provides the master clock, and bytes arrive and depart together).
Best Wishes |
|
|
jahan
Joined: 04 Apr 2005 Posts: 63
|
|
Posted: Sun Aug 03, 2008 9:14 am |
|
|
Thank you for your reply. It does confirm my original thoughts that having a larger buffer helps with ASYNC data transfer.
The reason I asked the question is because, each time I "enable_interrupts(INT_TBE);" the data coming back to me from device is corrupted. As soon as I disable it, then I'm OK.
another follow-up thought:
In my project, I know when I'm send data out and also exactly know what I'm getting back (time and size), so should I still use the INT's?
Thanks Ttelman. |
|
|
Ttelmah Guest
|
|
Posted: Sun Aug 03, 2008 2:58 pm |
|
|
INT_TBE, should _only_ be enabled, when you have got data to send. It will occur _continuously_, while the transmit buffer is empty.
Example code:
Code: |
#byte PIR1=0xF9E
#bit TXIF=PIR1.4
#byte TXREG=0xFAD
#byte TXSTA=0xFAC
#bit TRMT=TXSTA.1 //For 18 chips. Change all these for 16 chips
#define BUFFSIZE (32)
struct buffer {
char buff[BUFFSIZE];
int8 in;
int8 out;
};
struct buffer rs232_txbuff;
#define bkbhit(b) (b##.in!=b##.out)
#define isempty(b) (b##.in==b##.out)
#define incin(b) if(++b##.in>=BUFFSIZE) b##.in=0
#define incout(b) if(++b##.out>=BUFFSIZE) b##.out=0
#define clrbuff(b) b##.out=b##.in=0
#INT_TBE /* Transmit buffer empty interrupt */
void TXINT(void) {
if (isempty(rs232_txbuff)) {
DISABLE_INTERRUPTS(INT_TBE);
}
else {
TXREG=rs232_txbuff.buff[rs232_txbuff.out];
incout(rs232_txbuff);
}
}
void rs232_bputc(char val) {
int8 next;
/* routine to send one character on the RS232.
This puts the specified character into the software transmit buffer
(if data is already being transmitted), or else sends the single
character to the RS232 UART. */
/* Waits if the buffer is full */
//Buffer is full if _next_ addition address matches current retrieval
//address
next=rs232_txbuff.in+1;
if (next>=BUFFSIZE) next=0;
disable_interrupts(INT_TBE);
while (next==rs232_txbuff.out) {
if (TXIF==1) {
/* Here the transmit hardware buffer is empty */
TXREG=rs232_txbuff.buff[rs232_txbuff.out];
//So send one char
TXIF=0;
incout(rs232_txbuff);
}
}
/* put character into the output buffer */
rs232_txbuff.buff[rs232_txbuff.in]=val;
rs232_txbuff.in=next;
/* Enable interrupts */
enable_interrupts(INT_TBE);
}
|
Leave the interrupt disabled, then when you want to send characters, call rs232_bputc with the data. It'll automatically enable the interrupt as needed.
The same buffer handling code, can be used for a receive buffer, by adding:
Code: |
struct buffer rs232_rxbuff;
//Routine to get a character from the RS232. Waits if no data available
char rs232_bgetc() {
int8 temp;
while (!bkbhit(rs232_rxbuff)) ;
temp=rs232_rxbuff.buff[rs232_rxbuff.out];
incout(rs232_rxbuff);
return temp;
}
//Serial RX interrupt
#int_rda
void receive_rs232(void) {
rs232_rxbuff.buff[rs232_rxbuff.in]=getc();
incin(rs232_rxbuff);
if (rs232_rxbuff.in==rs232_rxbuff.out) {
//Buffer overflow
incout(rs232_rxbuff);
}
}
|
You can see the syntax for using the bkbhit call, and reading data, in the above bgetc routine. The receive interrupt needs to be enabled in the main for this.
Best Wishes |
|
|
jahan
Joined: 04 Apr 2005 Posts: 63
|
|
Posted: Mon Aug 04, 2008 10:11 am |
|
|
Thank you for your help and sample codes;
reading your code I came across following:
Code: | #byte PIR1=0xF9E
#bit TXIF=PIR1.4
#byte TXREG=0xFAD
#byte TXSTA=0xFAC
#bit TRMT=TXSTA.1 //For 18 chips. Change all these for 16 chips |
can you explain what these are? I don't see them anywhere in examples provided by CCS.
Thanks |
|
|
Ttelmah Guest
|
|
Posted: Mon Aug 04, 2008 10:23 am |
|
|
Register definitions.....
Lot's of examples here, and in the CCS example code.
Names are those used in the data sheet.
So, 'PIR1', is the 'Peripheral Interrupt flag Register 1'. Then the Transmit interrupt flag, is bit 4 in this.
There are internal instructions to clear this, but not directly to test it. Hence the definitions.
Similarly, the corresponding putc, and getc instructions will write/read the data registers, but add significant testing overhead. Since the interrupt occurring, implies the output buffer _is_ empty, it is faster to just load the byte directly into the register. etc. etc..
Best Wishes |
|
|
jahan
Joined: 04 Apr 2005 Posts: 63
|
|
Posted: Mon Aug 04, 2008 11:32 am |
|
|
thank you for your detailed explanation.
you are a great resource in this community. |
|
|
jhortwo
Joined: 03 Oct 2011 Posts: 1
|
|
Posted: Mon Oct 03, 2011 12:09 pm |
|
|
Thanks for the tips, works fine with pic16f690, now i want to use transmit enable pin but i don't know how to do it. I set enable pin in the # USE RS232 but doesn't work. I try setting this after and before the lines:
Code: |
#byte PIR1=0x0C
#bit TXIF=PIR1.4
#byte TXREG=0x19
#byte TXSTA=0x98
#bit TRMT=TXSTA.1
|
|
|
|
|