Rich Bair

SCI0 Dropouts

Discussion created by Rich Bair on Aug 26, 2006
Latest reply on Aug 28, 2006 by Steve Mcaslan
Hello and thanks for reading. I am using RS485 communications between two boards (micro and display) where both parts are E series (E128 micro and E64 display). The micro used SCI0 and the display uses SCI2. The gist is that the micro sends an 11 byte command every ~100ms and the display processes the message and returns a 6 byte response. All comms are at 19200 baud and the baud rate error for each side is 0.2 percent (each micro does have a different crystal).

MICOR MSG:
START | LEN | CMD | DAT0 | DAT1 | DAT2 | DAT3 | DAT4 | DAT5 | XMODEMCRCHIGH | XMODEMCRCLOW

DISPLAY RESPONSE:
START | LEN | CMD | DAT0 | XMODEMCRCHIGH | XMODEMCRCLOW

So both sides use a CRC to qualify information transfer and other checks like echoing the command field back, etc. The display never misses a beat (keep in mind it doesn't have much to do either!). So I ALWAYS get the 6 byte response after a outboud micro message has been processed and passed CRC. Here's the problem...occasionally, maybe 1 of 50 messages I see a dropout on the micro receiving all of the 6 inboud bytes. Basically what seems to happen is mid-way through the receive message it is not recognized. I know this because I put a hardware debug pin to toggle every time a byte is received and it is not being processed (this could be code error after the missed one it runs properly so I don't think it is). The micro ISR code is:

----------------8-----------------------------------------
static volatile unsigned char idx;
volatile unsigned char data_rd;

/* Check for RDRF and OR */
if (SCI0SR1 & 0x28) {
/* Read data to RAM...clear flags */
data_rd = SCI0DRL;

/* Qaulify changes to rxbuf so send won't be corrupted */
/* Look for start of message */
if ((isr_state == (unsigned char)0U) && (data_rd == MSG_START_FLAG)) {
rxbuf[0] = data_rd;
/* Indicate in recevie of message */
isr_state = 1U;
idx = 1U;
}
else if (isr_state == (unsigned char)1U) {
/* Store data in the buffer */
if (idx MSG_MAXLEN) {
rxbuf[idx] = data_rd;
++idx;
/* Continue isr_state at 1 */
isr_state = 1U;
PTT_PTT2 = ~PTT_PTT2;
}
if (idx >= MSG_MAXLEN) {
rxbuf[idx] = data_rd;
/* Indicate expected number of bytes received */
isr_state = 2U;

/* Disable receiver: default state */
SCI0CR2 &= ~(SCI0CR2_RE_MASK);

/* Process received message */
if (ProcessMsg() == TRUE) {
}
com_state = 0U;
isr_state = 0U;
}
}
else {
isr_state = 0U;
}
}
----------------8-----------------------------------------

Here's what I've tried to remedy the situation...
1) HPRIO = D6h make SCI0 the high priority isr on the micro side
2) The display used to respond in ~500us from the stop bit of the micro command message...I added a 5ms delay (using 1/2 duplex MAX483 transceivers)
3) Moved ProcessMessage call to isr...I used to process at a later time in the non-isr portion of the code by coordinating with isr_state variable.

Could it be that I need more time between the bytes? It's really strange that it drops the 3rd or 4th display byte and picks up right after the missed byte. What about start bit identification...could it be missed if bytese are back to back? The send code from the display side is (identical except for MAG_MAXSENDLEN for the micro send portion as well):

----------------8-----------------------------------------
for (i = 0; i MSG_MAXSENDLEN; ++i) {
while ((SCI0SR1 & 0x80) != 0x80) {
if (check_timer(rxtx_timer) == 0UL ) {
(void)SCI0DRL;
return FALSE;
}
}

/* Send data byte */
SCI0DRL = sndbuf[i];

/* Wait for send to compete */
while ((SCI0SR1 & 0x40) != 0x40) {
if (check_timer(rxtx_timer) == 0UL ) {
(void)SCI0DRL;
return FALSE;
}
}
(void)SCI0DRL;
}
----------------8-----------------------------------------

Thanks! Any ideas would be much appreciated. BTW, when I posted this all of the indentation went away...sorry!

Outcomes