View previous topic :: View next topic |
Author |
Message |
aspalmer
Joined: 02 Aug 2010 Posts: 1
|
Uart Framing Problems |
Posted: Mon Aug 02, 2010 6:35 pm |
|
|
EDIT SOLVED: The problem was in silicon. Don't use PIC24hj12gp202 for high speed UART! It corrupts the transmission!
Hi. I am having trouble with the uart misreading transmissions from a sensor. I can't even get it to read its own transmissions properly. The Rx and Tx are connected together for the following test program. I transmit 2 0x01's and receive a 0x02 and 0x00. The staus register indicates a framing problem (FERR bit in the U1STA). Has anyone had or heard of similar problems?
I've edited the test program to respond to posters. The simplified program still has the same problem. Also sending an 'A' doesn't work either.
Code: |
#use rs232(UART1, baud=9600,bits=8, parity=N, stop=1)
void main()
{
char buffer_tbe[24];
char buffer_rda[24];
set_uart_speed(9600);
reset_serial_buffers();
clear_interrupt(INT_RDA);
enable_interrupts(INT_RDA);
enable_interrupts(INT_TBE);
putc(0x01);
putc(0x01);
delay_us(1000);
}
|
Last edited by aspalmer on Tue Aug 10, 2010 11:59 am; edited 6 times in total |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Tue Aug 03, 2010 7:43 am |
|
|
Ok first things first: how do you know it is a framing error and not anything else? A framing error occurs when the UART can't 'lock' onto the start bit; it starts reading from in-between the byte and produces gibberish at the output. I think you should first try to debug it for other problems before assuming it is a frameshift error.
Are you sure the baud rates are the same (9600 baud) at both ends? Double check this.
I see a whole lot of code above and I don't particularly want to read it. Try making a simple program that replicates the problem you are facing. Code: | while(1)
{
putc(0x01);
putc(0x01);
delay_ms(100);
} | You need to fill in the appropriate statements to include the header files/declare fuses/initialize the UART/etc.
If you get the same problem then post back.
Rohit |
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Tue Aug 03, 2010 8:14 am |
|
|
This:
putc(0x01);
Does not output a readable ASCII character. Why don't you try something like putc('A') instead.
Where are you enabling the transmit and receive interrupts? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Wed Aug 04, 2010 4:11 am |
|
|
I would be looking seriously at how TBE is handled. Once you enable INT_TBE, this interrupt will immediately be called. This is why it should _not_ be enabled till data is actually waiting to be sent in the software buffer. The originally posted TBE handling, looked messy, since you had interrupt driven serial transmit handling, and were also sending characters without this. You need to use 'one or the other', and not both. I'd guess you are actually sending garbage characters from the buffer, and these are resulting in the errors you are seeing.
Though this won't support buffers over 256 bytes, the attached is generic buffer handling code, and the corresponding interrupt/bputc. See if this solves the problem - send everything with bputc:
Code: |
#ifdef (__PCH__)
#byte TXREG=0xFAD
#byte TXSTA=0xFAC
#byte PIR1=0xF9E
#else
#byte TXREG=0x19
#byte TXSTA=0x98
#byte PIR1=0xC
#endif
#bit TRMT=TXSTA.1
#bit TXIF=PIR1.4
#define BUFFSIZE (32)
struct buffer {
char buff[BUFFSIZE];
int8 in;
int8 out;
};
struct buffer rs232_txbuff, rs232_rxbuff; //setup buffers
#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
//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);
}
}
#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);
}
}
//Routine to send a RS232 char
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 allready
being transmitted), or else sends the single character to the RS232 UART. */
/* Hold transmission 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);
}
//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;
}
|
As shown this also enables a RX buffer, and this shows how to use the 'bkbhit' function, to 'know' if a character is available.
Enable the RS232 receive interrupt, and the global interrupt, to use these. The transmit interrupt is automatically handled.
Best Wishes |
|
|
|