I noticed interesting behaviour on the UART (uart57 on one of our prototype IMP001s) when using it in combination with an RS485 tranceiver at low (4800 baud) speeds. Here’s what happens :
- when byte(s) are transmitted, the transition from receive to transmit (direction pin con,trolled by the SetTxactive method) creates a framing error on a series of 0 bits coming in on the Rx channel. Using a logic analyser, this is indeed correctly interpreted as a frame_error.
- when using a default uart rx callback (no flags), this actually gets picked up as a valid “00” byte coming out of the UART fifo. Result is that in almost all cases, an extra “00” byte ends up in your reception queue, but not always which makes it tricky
- when using the CALLBACK_WITH_FLAGS callback, this false byte does get identified as a FRAME_ERROR which allows discarting this phantom byte.
I’ve never seen this happening at higher speeds (normally use 9600 or 19200). But at 4800baud, it’s happening in 90% of cases.
==> when working at low speed RS485, it’s best to use the CALLBACK_WITH_FLAGS and a filter on the FRAME_ERROR bit set in the flags parameter to correctly identify framing errors and subsequently remove this phantom byte from the rx fifo (it’s there in any case so you have to actually read from the fifo to remove it).
This callback function correctly handles this phenomenon (note that the frame end detection timeout is very broad here @ 100msecs. Works only for sporadic messages on bus. With more bus traffic, reduce the 100msec to 10msec (timer can’t trigger on smaller values in my experience):
function _readback(flags)
{
// pick up frame error and remove phantom byte from the fifo
if ((flags & FRAME_ERROR)==FRAME_ERROR)
{
local dummy = _uart.read();
}
else if ((flags & READ_READY)==READ_READY) // normal callback operation
{
local bytereceived = _uart.read(); // read the UART buffer
// if a char is received, the end-of-frame detection timer needs to be reset
if (_uartdetectframetimer) imp.cancelwakeup(_uartdetectframetimer);
// This will return -1 if there is no data to be read.
while (bytereceived != -1) // we keep reading until there is no data to be read.
{
// 'byte' belongs to the current frame
_currentRxFrame.Payload.writen(bytereceived,'b');
_currentRxFrame.Len++;
bytereceived = _uart.read();
}
// when a pause is occuring in the reception of bytes over the UART (bytereceived = -1), start the timer to detect a frame end
// end of frame is assumed when the timer fires, unless it gets cancelled by a new incoming byte
_uartdetectframetimer = imp.wakeup(0.1,_processCurrentFrame.bindenv(this));
}
}