SCI0 Dropouts

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

SCI0 Dropouts

3,291 Views
rhb3
Contributor II
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!
Labels (1)
0 Kudos
4 Replies

629 Views
rhb3
Contributor II
Do I need to add SCI0SR1?

------------------------------------------------------------------
/* Check for RDRF and OR */
if (SCI0SR1 & 0x28) {

SCI0SR1; /*ADD THIS LINE??? */

/* Read data to RAM...clear flags */
data_rd = SCI0DRL;

------------------------------------------------------------------

Does the if statement not actually read and clear the flag or is it possible I'm having an overrun (even with HPRIO = D6h) flag and this is the "failure" case where you need to read it twice that I've read about and still don't fully understand?

Thanks!
0 Kudos

629 Views
Steve
NXP Employee
NXP Employee
You should only have to access SCI0SR1 once in the statement, but you are ignoring the overrun flag. Is it possible that some lengthy interrupt occurs in mid transmission causing you to receive two bytes before the first one is read? If you have an overrun you would lose the latter bytes rather than the first one.
Test for the OR flag separately from the RDRF flag to see if you are getting an overrun. Also it may be worthwhile to make sure you are not seeing any of the other error flags (corruption due to noise etc.)
Remember that unless you explicitly allow it the S12 does not support multiple level interrupts so the priority of the SCI receive ISR is irrelevant if another interrupt is already running.
0 Kudos

629 Views
rhb3
Contributor II
Thanks for the reply.  So if I do:
 
Code:
    /* Make SCI0 the highest priority isr */    HPRIO = 0xD6;    /* Enable interrupts */    /*lint -e(950, 960) */    __EI();

  ...then I should have multiple level interrupts, right?   HPRIO needs to be written to prior to the "asm cli" which is associated with __EI().  Is there any additional setup I need to do?  I do have one "lengthy" timer isr that decrements a pool of timers that may be suspect.  Perhaps, I could setup the decrment to occur outisde of the isr?
 
Thanks.
0 Kudos

629 Views
Steve
NXP Employee
NXP Employee
Multi-level interrupts require you to re-enable the interrupts when inside an ISR so maybe your lengthy timer interrupt could do this. Just be careful that you don't overrun the stack.
As you suggest, moving decrements outside of the ISR would also help but you need to be careful that doesn't give you another problem with coherency. In general try to keep your ISRs as short as possible.
However, I would suggest that you first check that overrun is the problem by examining the OR flag - maybe your debug approach with the port line could be reassigned to that function.
0 Kudos