-
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 truncated packets (IDFGH-14948) #15657
Comments
It is unpredictable when every time UART_DATA event happens how many data is available, it is not going to be a fixed amount of data all the time. From your code, it looks like you know how much data you want for one transaction. So you should fetch specific amount of data out each time, not rely on the UART_DATA event. You may take uart_async_rxtxtasks as the example. |
I have modified my approach and checking the tx packets as they come in. The responses containing the register counts so I can determine how much byte will come from the first 3 bytes. This works much better but I notice that I lose the first two or even three bytes sometimes. This is because the slave starts to answer as soon as it processes the packet but the esp32 still not pulled the rts pin so the rs485 chip is still in transfer mode. This is because the int HsUart::write(uint8_t *data, uint16_t length) {
int crc16 = getCRC(data, length - 2);
data[length - 2] = lowByte(crc16);
data[length - 1] = highByte(crc16);
internalRxBufLen = 0;
outgoingFunctionCode = data[1];
return uart_write_bytes(_uartNum, data, length);
} Will measure the rts pin with an oscilloscope soon but I have read that it can take up to 30us for the driver to pull the rts pin. This is unacceptable. https://esp32.com/viewtopic.php?t=22980 |
Your slave device is suppose to wait for the RTS line to be high to answer. This is how RS485_HALF_DUPLEX mode should work. Please check why your slave device answers before the RTS line is set to high, is it really in RS485 half duplex mode? BTW, can you close your other issue (#15668). We can discuss in this post. |
We try to squezee every bit of speed from the devices so they answer as soon as they get the message. |
The RTS line is set in the ISR when TX_DONE interrupt raises. 30us doesn't really seem to be a ridiculous time for ESP-IDF interrupt to response. Maybe you can try to enable |
This is already set in menuconfig
Now I'm trying uart_driver_install(
_uartNum,
HS_UART_RX_BUF_SIZE * 2,
0,HS_UART_QUEUE_SIZE,
&uart_queue,
ESP_INTR_FLAG_LEVEL3
); |
Still the first few bytes are missing but not every time, just sometimes. Frustrating... |
void HsUart::uart_event_task() {
uart_event_t event;
while (true) {
if (xQueueReceive(uart_queue, (void *)&event, portMAX_DELAY)) {
if (event.type == UART_DATA) {
handleDataEvent(&event);
} else if (event.type == UART_BUFFER_FULL) {
emitErr(HS_UART_BUFFER_FULL_ERROR);
} else if (event.type == UART_FIFO_OVF) {
emitErr(HS_UART_FIFO_OVF_ERROR);
} else if (event.type == UART_FRAME_ERR) {
emitErr(HS_UART_FRAME_ERROR);
} else if (event.type == UART_PARITY_ERR) {
emitErr(HS_UART_PARITY_ERROR);
} else if (event.type == UART_DATA_BREAK) {
emitErr(HS_UART_DATA_BREAK_ERROR);
} else if (event.type == UART_PATTERN_DET) {
emitErr(HS_UART_PATTERN_ERROR);
} else if (event.type == UART_BREAK) {
uart_flush_input(_uartNum);
}
}
}
}
void HsUart::handleDataEvent(uart_event_t *event) {
uint8_t tempBuf[event->size];
int len = uart_read_bytes(_uartNum, tempBuf, event->size, portMAX_DELAY);
if (len <= 0) return;
// Add to internal buffer
if (internalRxBufLen + len > sizeof(internalRxBuf)) {
emitErr(HS_UART_BUFFER_FULL_ERROR);
internalRxBufLen = 0;
return;
}
memcpy(internalRxBuf + internalRxBufLen, tempBuf, len);
internalRxBufLen += len;
int expectedLen = expectedPacketLength(internalRxBuf, internalRxBufLen);
if (expectedLen > 0 && internalRxBufLen >= expectedLen) {
// validate the packet if we got the expected bytes
handlePacket(internalRxBuf, expectedLen);
internalRxBufLen = 0;
}else if(event->timeout_flag){
// validate the packet also on timeout.
handlePacket(internalRxBuf, internalRxBufLen);
internalRxBufLen = 0;
}
}
|
Well, I guess the major problem is that you are not following RS485 half duplex mode, since your other device sends before RTS line gets set. In our TX_DONE ISR handling, we do reset the RX FIFO and then set the RTS high if the mode is RS485 half duplex. Maybe you can try our other RS485 modes, UART_MODE_RS485_COLLISION_DETECT or UART_MODE_RS485_APP_CTRL. Some documentations for your reference: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/uart.html#overview-of-rs485-specific-communication-0ptions. |
Okay I have tried everything but then I noticed something. I have a continous websocket sending task which consumes it's own queue to send frames to a server. When I uncomment highPriorityQueue = xQueueCreateWithCaps(20, sizeof(WsMessage), MALLOC_CAP_SPIRAM);
lowPriorityQueue = xQueueCreateWithCaps(128, sizeof(WsMessage), MALLOC_CAP_SPIRAM);
void ServerBridge::bridgeSender_task() {
WsMessage wsMessage;
while (1) {
if (xQueueReceive(serverBridge.highPriorityQueue, &wsMessage, pdMS_TO_TICKS(10)) == pdTRUE) {
serverBridge.sendWsMessage(wsMessage);
}
if (xQueueReceive(serverBridge.lowPriorityQueue, &wsMessage, pdMS_TO_TICKS(10)) == pdTRUE) {
serverBridge.sendWsMessage(wsMessage);
}
vTaskDelay(pdMS_TO_TICKS(2));
}
}
void ServerBridge::sendWsMessage(WsMessage& wsMessage) {
// When I remove the comments from this if statement, the uart errors are reappearing.
/*if (isConnected()) {
// This causes the uart truncation.
int err = esp_websocket_client_send_text(
serverBridge.client,
wsMessage.message,
wsMessage.size,
pdMS_TO_TICKS(1000)
);
if (err == -1) {
ESP_LOGE(SERVER_BRIDGE_DEBUG_TAG, "Failed to send message");
}
}*/
// Free memory allocated for the message
if (wsMessage.message != nullptr) {
free(wsMessage.message);
wsMessage.message = nullptr;
}
}
It also seems to me that any kind of websocket code causes an altered uart frame. ( like server reconnection, etc ) |
Yeah, it makes sense. Any use of websocket could lead to the delay in handling the UART ISR. Since you are on ESP32, which has two cores, you can install the UART driver on a different core than your websocket service. |
O.o is it make sense? How? Can you explain please |
I think your UART and ethernet interrupts were both registered on core 0. Say both peripheral interrupts got triggered at almost the same time, and core 0 processed ethernet interrupt first, then UART interrupt has to wait until ethernet ISR exits to get handled. This is why "Any use of websocket could lead to the delay in handling the UART ISR". If you register UART interrupt on core 1, then core 0 can handle ethernet ISR, while in the meantime, core 1 can handle UART ISR. You can use |
So it's not just websockets but any ethernet interrupt? Even wifi? So I need to pin every network related stuff to core 0 and the uart to core 1? |
Exactly! 💡 |
Thank you very much for the help. I really appreacite! |
Okay, confirmed. It seems that any kind of flash or SPI will mess with the uart timings if it is on the same core the uart driver is installed on. I had a couple of unexplained things going on before but this cleared out a bunch of them.
Thank you very much for the help. |
Answers checklist.
IDF version.
ESP-IDF v5.3.2.250210
Espressif SoC revision.
ESP32-WROVER-E (N16R8) (rev 3)
Operating System used.
Windows
How did you build your project?
VS Code IDE
If you are using Windows, please specify command line type.
PowerShell
Development Kit.
ESP32-Wrover-Kit
Power Supply used.
External 3.3V
What is the expected behavior?
I expect uart to not drop frames.
What is the actual behavior?
Uart misses packets.
Steps to reproduce.
Debug Logs.
Diagnostic report archive.
No response
More Information.
This is how I use it
I have confirmed via an oscilloscope that the data is OK. There is no inter byte delay. The line is properly terminated with resistors. We are using an RS485 chip. If I go with SYMBOL_TIMEOUT 1 the uart even split the packets by every
0xFF
byte. If I go with more then SYMBOL_TIMEOUT 1 it does not split on0xFF
bytes but we got truncated packets at random intervals and at random bytes.What we have tried without resolution
The text was updated successfully, but these errors were encountered: