Hello
We have 2 problems with serial interface.
We are using RTU Modbus protocol over RS485 through UART peripheral.
Kernel version: Linux ABB-54-4a-16-fb-1f-16 4.19.94-rt39 #3 PREEMPT RT Tue Mar 9 16:16:21 CET 2021 armv7l GNU/Linux
Serial driver: OMAP 8250 with DMA (as default conf from evm-06.03.00.106)
The first strange behavior regards the transmission. Sometime, roughly 1 over 1000, the frame sent out by our AM33354 microprocessor is not correct. There is one byte unexpectedly inserted in the first position, then we get the normal frame except the last byte that is missing.
The byte prefixed is always the first byte of the previous transmitted frame (frame which is correct).
For example:
the following frame has a wrong prefixed 0xFA
The correct frame would have been:
FA 10 00 10 00 0A 03 EA 03 84 00 00 07 E5 00 03 00 05 00 0D 00 0D 00 39 00 83 02 9C
Thus, the length is correct, but from the real frame the actual one is truncated by 1 byte and 1 byte is inserted in the first position.
The previous frame was :
Which starts with 0xFA too. If this previous file started by 0xYY, then the worn one would start by 0xYY.
Our application sends always the same set of frames that is composed by modbus function code (req[1], the second byte of frame) that can be 0x04 or 0x06 or 0x10 or 0x14. Moreover, the first byte (the modbus slave address) can be 0x11, 0x81 or 0xFA. As already described, in case of error, the second byte is the first one of the previous frame, thus 0x11, 0x81 or 0xFA.
We have inserted a log in the modbus library (libmodbus) we use that proves the buffer passed to write system call is never the strange frame we see by oscilloscope.
static ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_length) {
/* ... */
if (req[1] != 4 && req[1] != 6 && req[1] != 16 && req[1] != 20) { // This line filter frames affected by the problem, normally Tx frames have 0x04 or 0x06 or 0x10 or 0x14 as second byte.
time_t t = time(NULL);
printf("*** Suspect outbound frame before write %ld\n", t);
for (int i = 0; i < req_length; i++)
printf("[%.2X]", req[i]);
printf("\n");
}
size = write(ctx->s, req, req_length);
}
We never enter in the IF condition, that means the req buffer is always composed as expected.
The second strange behavior regards the reception.
The data we read from the sensors is retrieved through chunks of files, transferred using the Modbus opcode 20 (read file record).
To read these file chunks we manually access the serial port socket with a custom poll()/read() loop.
The problem we are experiencing is that many opcode 20 requests (like 1 in 70) fail because the first read() instantly returns a block of data filled with a single repeated value.
We analyzed the RS485 line with an oscilloscope, and concluded that this data is not present on the bus.
I’ve attached a log file with 6 examples of this problem.
We noticed a few things about this problem:
- The size of the "fake" data block is always 48, which we think is the size of a DMA trasfer in the UART driver
- The repeated value is always the 65th byte of the previous read chunk. You can see it from the attached examples
- If we set CONFIG_SERIAL_8250_DMA=n in kernel configuration, the problem disappears
Thanks in advance.
BR.
Lorenzo