|
|
View previous topic :: View next topic |
Author |
Message |
FISH6942
Joined: 03 Feb 2006 Posts: 13 Location: Minnesota
|
Interesting UART situation |
Posted: Fri Mar 03, 2006 3:16 pm |
|
|
I came across an interesting situation with an RS-485 app I'm putting together. I'm using the 9th bit and setting it for the first byte of the packet and clearing it for the rest of the packet.
What I found is that if I continually clear the 9th on every iteration of the loop that sends out the packet, the start bit of the second byte gets stretched out (should be 4uS long, ends up being around 7.2uS instead). All other bits in all other bytes appear to be correct. If I write the 9th bit low only once during the loop then the problem goes away.
(I apologize for the formatting, I copied it from my editor and the indenting and spacing is all goofed up... any suggestions for next time?)
#case // Turn on case sensitivity
#device PIC18F4520
#device *=16 // Enable generation of 16 bit pointers
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOPUT,NOBROWNOUT,NODEBUG,NOPBADEN
#define DEBUG_MODE // Uncomment to use ICD2 as debugger
#ifdef DEBUG_MODE
#fuses DEBUG
#device ICD=TRUE
#endif
#include "4520_REGS_PINS.h"
#define XTAL_SPEED 20000000
#use delay( clock = XTAL_SPEED ) // required for delay_ms()
void main() {
bool led;
int8 bytes_sent_cntr;
int8 packet_size;
int8 data_to_send[3];
// ** Set up the chip I/O registers
trisA = 0x0C; // A2:A3 input, others output
portA.whole = 0x30; // Initialize A outputs
trisB = 0xFF; // B0: buttonPress, B1 & B2: tach inputs,
// B3 & B4: limit switches, B5: auto-level set,
// B6 & B7: PGM
portB.whole = 0; // Initialize B outputs
trisC = 0xD0; // C6/TX, C7/RX are used for UART, configure
// both as input. C4/SDI is input.
// C0, C1, C2, C3, C5 are output
portC.whole = 0; // Initialize C outputs
trisD = 0xC0; // D6 & D7 inputs, others outputs
portD.whole = 0x30; // SHUTDOWN pins inactive (high)
trisE = 0; // DEBUG outputs
portE.whole = 0;
adcon0 = 0; // Disable A/D converter
adcon1 = 0x0F; // Configure all I/O as digital
// ** initialize the serial port
baudcon = 0x00; // no autobaud, no wake-up, 8-bit baud rate generator
txsta = 0x46; // high baud rate enabled, asynch mode, 9-bit mode
rcsta = 0xC0; // addr detect disabled, 9-bit mode, enable serial port
spbrg = 4; // 250k baud, xtal = 20MHz, high baud rate mode
// desired baud rate(BR) = (Fosc/[16(n+1)]
// n = 20,000,000/[(250,000)(16)] -1
// n = 4
spbrgh = 0; // ignored in 8-bit baud rate mode
// ** enable trasmit mode, set '485 driver lines
txen = 1;
cren = 0;
PIN_NOT_RECV_EN = true;
PIN_XMIT_EN = true;
// ** initialize test data
data_to_send[0] = 0x55;
data_to_send[1] = 0x55;
data_to_send[2] = 0x55;
packet_size = 3;
for (EVER) {
bytes_sent_cntr = 0;
tx9d = 1; // set address bit
// once the button is pressed, sent the packet of data
if ( PIN_PUSH_BUTTON == 0 ){
do {
// wait for txreg to empty
while( txif == 0 ) {}
txreg = data_to_send[ bytes_sent_cntr ];
tx9d = 0;
//works with the following two lines in place of the previous line
// if( bytes_sent_cntr == 0 )
// tx9d = 0; // clear address bit
} while ( ++bytes_sent_cntr <= ( packet_size - 1 ) );
} // end of if
while( PIN_PUSH_BUTTON == 0 ) {} // wait for button to be released
} // end of for (EVER)
} // end of main() |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Mar 03, 2006 4:44 pm |
|
|
Quote: | (I apologize for the formatting, I copied it from my editor and the indenting and spacing is all goofed up... any suggestions for next time?) | On posting your message use the Code button to place markers around the text that you want keep preserved.
Quote: | What I found is that if I continually clear the 9th on every iteration of the loop that sends out the packet, the start bit of the second byte gets stretched out (should be 4uS long, ends up being around 7.2uS instead). All other bits in all other bytes appear to be correct. If I write the 9th bit low only once during the loop then the problem goes away. | Check out the hardware errata for your chip, there are two nasty errors related to the UART and 9-bit transmissions that might be related to your problem.
An easy to perform test would be to use the CCS supplied routines for serial communications and see if the problem still exists. The CCS routines often contain workarounds for known chip problems.
Code: | #device *=16 // Enable generation of 16 bit pointers | You don't need this line, PIC18 processors always use 16 bit pointers. |
|
|
FISH6942
Joined: 03 Feb 2006 Posts: 13 Location: Minnesota
|
|
Posted: Sat Mar 04, 2006 9:39 am |
|
|
ckielstra - You are correct, the eratta describes the problem. I'll go with their suggested fix. It was really baffling as to why this was happening.
Thanks!! |
|
|
FISH6942
Joined: 03 Feb 2006 Posts: 13 Location: Minnesota
|
|
Posted: Mon Mar 06, 2006 3:31 pm |
|
|
After looking at the errata, I reworked the code and got it to work properly for my application. However, I only need to write to the 9th address bit once during packet transmission. I found that if I continually write to the 9th bit that every start bit after the first will be stretched to about 6.8uS (should be 4.0uS).
What the errata suggests is to only write to the 9th bit IMMEDIATELY after the txif bit gets set (txif == 1 => txreg is ready for another byte). This is seems curious because even if txreg is empty, the transmit shift register may still be shifting out data. The errata goes on to say that the problem stems from "any write to the TXSTA register(which is where the 9th bit is located) will result in a reset of the baud rate timer which will effect any ongoing transmission".
I also tested a version that monitored the trmt bit so that new data was only loaded into the txreg once the shift register was empty. This worked ok except for a delay of a few uS between each stop-start bit.
Here is the new code. Any comments would be welcome.
Code: |
#case // Turn on case sensitivity
#device PIC18F4520
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOPUT,NOBROWNOUT,NODEBUG,NOPBADEN
#define DEBUG_MODE // Uncomment to use ICD2 as debugger
#ifdef DEBUG_MODE
#fuses DEBUG
#device ICD=TRUE
#endif
#include "4520_REGS_PINS.h"
#define XTAL_SPEED 20000000
#use delay( clock = XTAL_SPEED ) // required for delay_ms()
void main() {
int8 dummy;
int8 bytes_sent_cntr;
int8 packet_size;
int8 data_to_send[4];
// ** Set up the chip I/O registers
trisA = 0x0C; // A2:A3 input, others output
portA.whole = 0x30; // Initialize A outputs
trisB = 0xFF; // B0: buttonPress, B1 & B2: tach inputs,
// B3 & B4: limit switches, B5: auto-level set,
// B6 & B7: PGM
portB.whole = 0; // Initialize B outputs
trisC = 0xD0; // C6/TX, C7/RX are used for UART, configure
// both as input. C4/SDI is input.
// C0, C1, C2, C3, C5 are output
portC.whole = 0; // Initialize C outputs
trisD = 0xC0; // D6 & D7 inputs, others outputs
portD.whole = 0x30; // SHUTDOWN pins inactive (high)
trisE = 0; // DEBUG outputs
portE.whole = 0;
adcon0 = 0; // Disable A/D converter
adcon1 = 0x0F; // Configure all I/O as digital
// ** initialize the serial port
baudcon = 0x00; // no autobaud, no wake-up, 8-bit baud rate generator
txsta = 0x46; // high baud rate enabled, asynch mode, 9-bit mode
rcsta = 0xC0; // addr detect disabled, 9-bit mode, enable serial port
spbrg = 4; // 250k baud, xtal = 20MHz, high baud rate mode
// desired baud rate(BR) = (Fosc/[16(n+1)]
// n = 20,000,000/[(250,000)(16)] -1
// n = 4
spbrgh = 0; // ignored in 8-bit baud rate mode
// ** enable trasmit mode, set '485 driver lines
txen = 1;
cren = 0;
PIN_NOT_RECV_EN = true;
PIN_XMIT_EN = true;
// ** initialize test data
data_to_send[0] = 0x55;
data_to_send[1] = 0x55;
data_to_send[2] = 0x55;
data_to_send[3] = 0x55;
packet_size = 4;
for (EVER) {
// once the button is pressed, sent the packet of data
if ( PIN_PUSH_BUTTON == 0 ){
bytes_sent_cntr = 0;
tx9d = 1; // set address bit
do {
txreg = data_to_send[ bytes_sent_cntr ];
dummy++; // allow time for txif to get cleared after
// writing to txreg
while( txif == 0 ) {} // wait for txreg to empty
if( bytes_sent_cntr == 0 ) // ** problems if this "if" is removed **
tx9d = 0; // clear address bit
} while ( ++bytes_sent_cntr <= ( packet_size - 1 ) );
} // end of if()
while( PIN_PUSH_BUTTON == 0 ) {} // wait for button to be released
} // end of for(EVER)
} // end of main()
|
|
|
|
|
|
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
|