RS485 TxEnable on ESP32 (transmit buffer empty interrupt)

I thought this would have already been solved but I found very few references.

I want to use UART2 to drive an RS485 transceiver which requires the RE/DE pins to be driven ~synchronously with the UART.

Turning on the driver is easy to do just before sending the data to the UART but I need to turn off the driver really fast when done transmitting because the remote devices on the RS485 bus start responding very quickly and any delay in turning the transceiver around would make me lose the first byte coming back.

The way I have done it with other microcontrollers is to trigger the TX_BUFFER_EMPTY (or whatever it's called on any particular chip) interrupt and I turn off the driver in the ISR.

TLDR; how to I configure and detect the transmit buffer empty interrupt of the ESP32 under Arduino IDE?

Thanks in advance!

Edit: found this link: https://esp32.com/viewtopic.php?t=10469
Will try it in a moment

Sounds very strange. So what's the whole point of RE/DE at this point?
Are you sure you have both pins solidly wired?
I would expect turning too quickly would cause lost byte...

Partial solution is in post number 5.

Note the difference between "tx buffer empty" and "when done transmitting"

The link in the original post allowed me to write working code, but not optimized.

The important part is to use the uart_wait_tx_done() function instead of TX_BUFFER_EMPTY or TX_FIFO_EMPTY interrupts because those are set when the last byte is transfered from the buffer to the shift register and of course it takes a moment to actually shift the last byte out, so if you turn off the driver as soon as you get FIFO_EMPTY or BUFFER_EMPTY, you will lose the last byte. You could always add a dummy byte I guess, but in my case it would not work because the remote devices sometimes start transmitting almost immediately after receiving a message.

The call to uart_wait_tx_done() works, but it's just a function call, it does not use an interrupt so you just have to wait in a loop for the entire message to be transmitted.

It's not a big problem in my current application because the messages are short and I can afford to wait a few mS while sending a message, but with a busy system, that would be undesirable.

So the original question remain, is there a way to setup an ISR callback on the tx_done event?

I expect so while not played with that. Your link doesn't open on my browser.

Page 351>>

Not sure while the link does not work.
Anyhow, the summary is as follows.
Add the following to your sketch:

#include <HardwareSerial.h>
#include "rom/ets_sys.h"
#include "driver/uart.h"

I use UART2 so I declare it as follows:

#define UART_NUM      2
HardwareSerial MySerial( UART_NUM );
#define MAX_WAIT_MS   10  // timeout in mS for transmitting data
#define TX_ENABLE     15  // Define the pin used for TX_ENABLE

Set the TX_ENABLE pin in setup()

pinMode( TX_ENABLE, OUTPUT );
digitalWrite( TX_ENABLE, LOW );

Then in the routine that sends data:

digitalWrite( TxEnablePin, HIGH );  // enable RS485 driver
MySerial.write( buf );
esp_err_t result = uart_wait_tx_done( (uart_port_t)UART_NUM, portTickType( MAX_WAIT_MS )); 
if( result != ESP_OK ){
    // Handle error if transmission did not finish within timeout
}
digitalWrite( TX_ENABLE, LOW ); // driver turns off about 120uS after the end of the stop bit (at 9600 bauds)

You probably can also use the standard flush() function that's part of the HardwareSerial class. I doesn't return until the print buffer has been emptied.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.