-
Notifications
You must be signed in to change notification settings - Fork 7.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UART splits packets on every 0xFF byte. #11132
Comments
@hitecSmartHome - a couple questions:
|
Sorry for not being more precise. I'm using
#define MBUS_BAUD 115200
#define MBUS_RX 35
#define MBUS_TX 32
#define MBUS_RTS 33
#define PACKET_TRIGGER_ONLY_ON_TIMEOUT 1
#define MBUS_RX_TIMEOUT 1 // Can't set it higher if UART_MODE_RS485_HALF_DUPLEX
#define MAX_MBUS_DATA_LENGTH 256
#define MAX_RX_BUFFER_SIZE 256
void setup(){
Serial1.setRxBufferSize(MAX_RX_BUFFER_SIZE);
Serial1.setTxBufferSize(MAX_MBUS_DATA_LENGTH);
Serial1.begin(MBUS_BAUD, SERIAL_8N1, MBUS_RX, MBUS_TX);
Serial1.setPins(-1, -1, -1, MBUS_RTS);
Serial1.setMode(UART_MODE_RS485_HALF_DUPLEX);
Serial1.setRxTimeout(MBUS_RX_TIMEOUT);
Serial1.onReceive([](){
int available = Serial1.available();
uint8_t rawPacket[available] = {0};
int read = Serial1.readBytes(rawPacket, available);
printf("Raw uart data: ");
for (int i = 0; i < length; i++) {
printf("0x%02x ", data[i]);
}
printf("\n");
},PACKET_TRIGGER_ONLY_ON_TIMEOUT);
} If I throw any frame ( valid or invalid modbus frame it does not matter ) and if it has any 0xff it will split it into two packets. But it will split only when there are more bytes after a 0xff byte. So for example |
@hitecSmartHome - I have modified the original Sketch and I am able to reproduce the reported issue. I have found out that when the UART is set using EVEN or ODD parity bit, it works correctly. |
It seems that 0xff + some other byte will trigger a BREAK. This seems to interfere with the IDF UART Driver and it causes the package to be broken into pieces when it is read using "onReceive()". I'll try to figure out a way to create a work around for it.. |
I did not see any correlation to the sequence of bits or bytes. I observed only this |
@hitecSmartHome - Not sure if this information may help within your project, but I also have found out that this Therefore, I think that it may be an ESP32 internal hardware design problem that has been solved latter. |
Lastly, I also verified that when It seems that there is no way to fix it, unless using ODD/EVEN parity or a RX_TIMEOUT higher than 1. |
That is bad news for us for sure.
How can we set |
Using ======= |
I have tried to set it to 5 but I got an error message like that and it did not have any effect. I can try that again tomorrow. |
@hitecSmartHome - I have found out why When it uses APB Clock as UART Clock Source, RX Timeout can be way higher. ESP32 and ESP32-S2 are the affected target. A way to solve this issue is by setting the Baudrate to higher than 250000 and setting the RX Timeout to 2. #define MBUS_BAUD 250001 // higher than 250,000 allows RX_TIMEOUT to goes up to 101
#define MBUS_RX 35
#define MBUS_TX 32
#define MBUS_RTS 33
#define MBUS_RX_TIMEOUT 2 // Can't set it higher than 1 if Baud rate is 250000 or lower |
That is still bad news because we are limited to 115200 baud with modbus communication because of external slave chips. |
And why does it split at specifically 0xff? If it is a timing/clock issue it would not matter which byte it is |
If I use the uart driver directly I can set the rx timeout hovewer I want. With symbol time of 2 it works with the uart driver. uart_config_t uart_config = {
.baud_rate = baud,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
uart_driver_install(_uartNum, HS_UART_BUF_SIZE * 2, HS_UART_BUF_SIZE * 2, HS_UART_QUEUE_SIZE, &uart_queue, 0);
uart_param_config(_uartNum, &uart_config);
uart_set_pin(_uartNum, tx, rx, rts, UART_PIN_NO_CHANGE);
uart_set_mode(_uartNum, UART_MODE_RS485_HALF_DUPLEX);
uart_set_always_rx_timeout(_uartNum, 1);
uart_set_rx_timeout(_uartNum, byteTimeout); We will continue to use the driver directly and avoid |
So basically this is my implementation so far and it seems to work. This still triggers on packet timeout and I got all the data reliably. Still testing... void HsUart::init(int baud, uint8_t rx, uint8_t tx, uint8_t rts, byte byteTimeout){
uart_config_t uart_config = {
.baud_rate = baud,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
uart_driver_install(_uartNum, HS_UART_BUF_SIZE * 2, HS_UART_BUF_SIZE * 2, HS_UART_QUEUE_SIZE, &uart_queue, 0);
uart_param_config(_uartNum, &uart_config);
uart_set_pin(_uartNum, tx, rx, rts, UART_PIN_NO_CHANGE);
uart_set_mode(_uartNum, UART_MODE_RS485_HALF_DUPLEX);
uart_set_always_rx_timeout(_uartNum, 1);
uart_set_rx_timeout(_uartNum, byteTimeout);
// This spawns a task with the stack in psram
worker.offloadToPsRam(
std::bind(&HsUart::uart_event_task, this),
4096, 12, "HsUart"
);
}
void HsUart::uart_event_task() {
uart_event_t event;
uint8_t data[HS_UART_BUF_SIZE];
while (true) {
if (xQueueReceive(uart_queue, (void *)&event, portMAX_DELAY)) {
switch (event.type) {
case UART_DATA:
int len = uart_read_bytes(_uartNum, data, event.size, portMAX_DELAY);
handlePacket(data,len);
break;
case UART_FIFO_OVF:
emitErr(HS_UART_FIFO_OVF_ERROR);
break;
case UART_BUFFER_FULL:
uart_flush_input(_uartNum);
xQueueReset(uart_queue);
emitErr(HS_UART_BUFFER_FULL_ERROR);
break;
case UART_FRAME_ERR:
emitErr(HS_UART_FRAME_ERROR);
break;
default:
break;
}
}
}
}
|
Well, it works except a weird |
I think that it is a combination of timming and clock as you say. That is why setting EVEN or ODD parity in the UART Frame also solves the issue. That parity adds "time" for the correct RX Timeout detection. Another way may be using 2 Stop bits, instead of just 1. |
This may be some UART BREAK detection... It happens in the very begining of the UART set up. |
We observe this behaviour after uart setup at inconsistent rates. Sometimes we get 2-3 single 0x00 bytes under 1 minute but sometimes we get only one in five minutes. |
You can also modify the Just modifying https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-uart.c#L42 in this way shall force the ESP32 to always use APB as UART Clock Source: //#define REF_TICK_BAUDRATE_LIMIT 250000 // this is maximum UART badrate using REF_TICK as clock
#define REF_TICK_BAUDRATE_LIMIT 0 // Force ESP32 and ESP32-S2 to always use APB as Clock Source |
Do you see also any BREAK verbose log mode messages or BREAK Error in the |
I dont see any BREAK event associated with the
We have a 2.2k ohm resistor |
@hitecSmartHome - I think that we have clarified the issue and there is a work around for the |
Thank you for the help. We ended up using the raw idf driver and using that instead of the Serial. |
@SuGlider is it possible to make the choice of clock a parameter in menuconfig? Or at least define
Although the menuconfig setting is more elegant. EDIT: Preparing a Pull Request for this. |
Board
ESP32-Wrover-E
Device Description
Hardware Configuration
Version
latest master (checkout manually)
IDE Name
VsCode
Operating System
Windows 10
Flash frequency
80
PSRAM enabled
yes
Upload speed
115200
Description
When the ESP32 receives a frame which has
0xFF
in it, it will break the packet into multiple packets.We measured with oscilloscope and there is no byte timeout, the bytes are continous.
So a single continous packet which has 3pcs
0xFF
byte in it, it will be split into 3 different packets.Sketch
Expected single packet:
0x04 0x03 0x40 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x1b 0x00 0x00 0x00 0x0b 0x00 0x01 0x00 0x1b 0x00 0x00 0x00 0x35 0x00 0x00 0x00 0x1c 0x00 0x00 0x00 0x1f 0x00 0x00 0x00 0x1f 0x00 0x00 0x00 0x27 0x00 0x00 0x00 0x25 0x00 0x00 0x00 0x83 0x00 0x00 0x00 0x58 0x00 0x00 0x94 0x20 0x00 0x04 0xff 0x3d 0xff 0xff 0xeb 0x35
Received packets instead.
0x04 0x03 0x40
0xff 0xff 0xff
0xff 0xff 0xff
0xff 0x00 0x00 0x00 0x1b 0x00 0x00 0x00 0x0b 0x00 0x01 0x00 0x1b 0x00 0x00 0x00 0x35 0x00 0x00 0x00 0x1c 0x00 0x00 0x00 0x1f 0x00 0x00 0x00 0x1f 0x00 0x00 0x00 0x27 0x00 0x00 0x00 0x25 0x00 0x00 0x00 0x83 0x00 0x00 0x00 0x58 0x00 0x00 0x94 0x20 0x00 0x04
0xff 0x3d 0xff 0xff 0xeb 0x35
I have checked existing issues, online documentation and the Troubleshooting Guide
The text was updated successfully, but these errors were encountered: