Page 1 of 1

Understanding UART and 485 modes

Posted: Fri Feb 09, 2024 10:15 am
by mark.lamneck
I’m new to the forum and hope to find some support here.

I want to use an esp32 as a node in a 485 bus with the following conditions:
  • baudrate: 921600 bits/sec
  • no master slave, so all nodes can send at all times
  • inter frame delay >= 10bytes ~ 100us
  • addressed nodes are sending a 1byte acknowledge within the inter frame delay
Requirements for the ESP:
  • Response time to send an ack <= 70us
  • Arbitration: only send if rx is not busy and not in the inter frame delay (except it needs to send an ack)
  • Collision detection: The receiver on the 485 chip is enabled all the time. The esp should compare the received bytes with the one it sends and stop sending if there’s a difference.
I started with the uart_events example and set rx_timeout_thresh=1. The data event is approx. 30us after the last byte has been completed (10us timeout + 20us delay by rtos). If I send an ack right away, I see it on the bus aprox. 30us later, so in sum 60us. That would be fine, but could be better. I can improve it slightly by setting rx_full_thresh=1. This results in 50us response time over all. Now I have a few questions.

Q1: By setting rx_full_thresh=1, I was expecting to see data events after each received byte (of course with a delay). But what I see is that these events occur after the end of the msg. In my understanding the events are sent to the queue from the isr and consumed by the thread reading the queue. But it seems like there is a layer in between?

Q2: The documentation says the UART_RS485_CLASH_INT is generated when there is a collision on the bus. However, in case of collisions, I never receive an event in my uart driver, regardless of the settings for uart_mode, loopback and interrupt configuration. How can I handle this interrupt? Do I have to register my own isr? How do I do that?

Q3: The documentation says if the UART_RS485_CONF_REG.UART_RS485RXBY_TX_EN flag is set, the transmitter will only send if rx is not busy. I thought this flag would be set by setting uart_mode to UART_MODE_RS485_COLLISION_DETECT or UART_MODE_RS485_APP_CTRL, but it seems not. How can I manually set this flag? Or in general what is the recommended way to access hardware registers? For example, if I want to check if the bit is really set?

Q4: Any suggestions how to handle the arbitration? I guess even if the UART_RS485_CONF_REG.UART_RS485RXBY_TX_EN approach, explained in Q3 would work, I cannot use it, because I have to have a pay attention to the inter frame delay. Sending right away after a msg is not allowed. And I guess this is what the hardware would do, right? One idea is to connect an additional pin to the rx pin of the uart, configure a pin change interrupt, but not enable it and just read/clear the interrupt request bit (the bit would be my indicator for bus activity within a timeslot between clearing and checking it again). How can achieve this on the esp?

Q5: I’ve checked the delay between the call of uart_write_bytes and the start of the msg physically on the bus. It’s around 10us. Is there any chance to speed this up as it increases the chance for collisions.