[ECOS] MPC555 serial receive drops bytes

Steven Clugston steven.clugston@newcastle.ac.uk
Tue May 6 15:59:00 GMT 2008


I've been developing an application which makes use of the mpc555 serial
driver (xxx555_serial_with_ints.c).

I was having problems with my app just hanging after receiving only a
few bytes on either of the two serial ports at 57600 baud.

After fixing this (I'll explain the cause below), I've then also had
problems with bytes going missing.

To test this I've used the serial_echo program and pasted individual
lines of text into hyperterminal/minicom and characters are consistently
lost ant any baud rate above 2400bps, getting worse as the baud rate is
increased.

The following code is the DSR which handles a received byte interrupt:


#define MPC555_SERIAL_SCxSR_ERRORS (MPC555_SERIAL_SCxSR_OR | \
                                    MPC555_SERIAL_SCxSR_NF | \
                                    MPC555_SERIAL_SCxSR_FE | \
                                    MPC555_SERIAL_SCxSR_PF)

static void mpc555_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32
count, cyg_addrword_t data)
{
  serial_channel * chan = (serial_channel *)data;
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info
*)chan->dev_priv;
  cyg_addrword_t port = mpc555_chan->base;
  cyg_uint16 scdr;
  cyg_uint16 scsr;

  // Allways read out the received character, in order to clear receiver
flags
  HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);

  HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
  if(scsr & (cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS)
  {
    scsr &= ~((cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS);
    HAL_WRITE_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
  }
  else
  {
    (chan->callbacks->rcv_char)(chan, (cyg_uint8)scdr);
  }

  cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
}

In this configuration the mpc555 has only a single byte receive buffer
for which an interrupt is generated each time it is filled. The SCI
status register SCSR has some bits which can flag status info and
errors, specifically Overrun error(NR), Noise error (NF), Framing error
(FE) and Parity error.

Using a hardware debugger I've found that the OR, overrun error bit was
being set.
The code above reads the data register SCDR buffer then reads the status
register, then if any error bits are set, attempts to clear them.

According to the mpc555 user manual, the act of reading the data
register clears or invalidates the status register, and at least some of
the bits are read-only. Attempting to clear these bits (specifically the
overrun bit) was causing a processor execption in my application.

Ok, it was an easy fix to read the data register after the status
register, but is there a way to report read errors back to the
application so that it doesn't fail silently? It might be useful for
example to return the line noise error as an error code unique to that
driver or the serial IO layer, whereas maybe an overrun should be an
assert as this shouldn't really happen.

With the exception fixed, I was still getting overruns so I moved the
code out of the DSR code into the ISR to improve latency. Since its only
moving a byte out of a register, I thought it doesn't really need a DSR.
This improved matters, but the overrun was still occuring.

In the status register there is also an IDLE, or idle line detected bit
which is flagged when there is a gap of one frame in the data stream. It
seems that a first level fix would be to stay in a hard loop in the DSR
until the IDLE bit is set. This seems to be the only way to ensure that
all incomming bytes are read in time. There is still a risk that the DSR
would not be serviced in time to get the first byte out of the buffer
though. The knock-on effect of this is that application code would be
blocked for as long as a continuous stream of serial bytes are being
sent.

The next level fix would require a partial re-implementation of the
driver. One of the two serial channels supports the QSCI, or queued
receive buffer which uses a 16-byte buffer and half-water and full-water
mark interrupts to allow it to be used as two 8-byte buffers. You read
one half whilst the other is being filled until you get the idle line
bit then you read whatever is left over. This would allow normal async
interrupt operation on one of the serial ports. I think this should be
implemented as a cdl option for the serial port that supports it, but
would require differentiation of which port is being accessed at runtime
in the code.

Steven.

--
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss



More information about the Ecos-discuss mailing list