UART picks up dummy byte at low speed RS485 usage


#1

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 :

  1. 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.
  2. 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
  3. 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));
	}
}

#2

Can you attach your analyzer traces? Interested that you see an RX glitch from your transceiver; maybe a pull-up resistor could help?


#3

Here are some screenshots.

  • no node response where only the 00 gets received
  • with response where there’s an extra zero
  • detail of the framing error


#4

And here’s with a 10K pull-up on RXD which indeed removes the glitch successfully…

I guess it’s an underlying STM32 problem that the frame-error (no stop bits detected) error ends up in the receive fifo as a valid byte. I’m normally working with LPC devices and have never seen that behaviour (also without pull-up) Tranceiver used is a MAX3430 with 1/4 loading on the bus.

This is just a test rig with an IMP001. Actual design will use IMP005 or IMP004m. Could you automatically enable an internal pull-up on the RXD pins if they get configured as part of a UART ?


#5

I mean, generally it’s best to use pull-ups/down resistors to ensure known state for tristate signals - on some imps, there is no way to assert an on-die pull-up on UART RXD (eg 005).

On-die pullups/downs tend to have a large range of values depending on the individual device being used, and this may not be strong enough for some setups.


#6

True. I wasn’t aware the RXD pins get tri-stated during transmission…


#7

I really don’t remember seeing that either - typically the RX side is running all the time (so you just receive what you’re transmitting) and you have a transmit enable pin (vs TX/nRX setup).

All sorts of chips out there though!


#8

Your last point may be part of the reason. I typically wire together TX/nRX enable pins to avoid receiving myself what I send. That will probably tristate the RX pin on the STM side and will require a pull up if there’s no on-die pull up on the tranceiver. So lesson learned is that you either need to keep RX enabled or use a pull-up on the RX line (at least with the MAX 3430, where this is btw not mentioned in the datasheet).

But on the STM side, a reception with a framing error (which is correctly identified as a frame error, otherwise you guys couldn’t pick it up for the extended callback) should be discarded and not end up in the RX fifo as a zero byte. That still smells like a uP bug to me…but one you could potentially intercept in the API. I don’t assume a bug in the API as I can’t see why you would push anything in the RX fifo that’s not coming out of the STM on-chip RX FIFO…