I'm specifically interfacing with Serial2 on my board and am having trouble with messages getting all the way through. It appears to be some timing issue with Serial2.write and Serial2.flush commands.
It seems that the entire full length message is not being transmitted to the RS-485 chip.
See Modbus Slave communication window, which is showing the repetitive polls being different every time.
If I modify the library by adding a delay after the Serial Flush command and it fixes the issue!
MBSerial.flush(); //Wait for transmission to get completed
delay(50);
if (MBUseEnablePin == 1) { //Switch RS485 driver back to receiving mode.
setReceiveMode();
}
Here see the RX and TX message being sent back by Modbus Slave program after adding the delay after Flush:
I believe this is an issue on the RTL872x, and affects all serial ports, and also SPI. The problem is that there are two FIFOs, the byte-oriented user FIFO, and also an internal FIFO that is responsible for outputting the actual bits over the wire.
The issue is that the queue will be empty, or the DMA callback is called when the user FIFO is empty, not when all bytes have successfully been transmitted over the wire.
This doesn't matter if all you are doing is refilling the queue. However, if you are using queue empty to change direction in RS485 or de-assert CS in SPI, that will be an issue.
At this time, the only solution is adding a delay.
However this is what it looks like for Serial2 using flush(). The signalPin is deasserted far before the transmission is complete, but only for Serial2.
Thanks for your in-depth analysis and for confirming my suspicions with logic @rickkas7 .
I've designed two P2 boards that both offer RS-485. One uses Serial3 (no issues) and the other uses Serial2.
If I'm reading your replies correctly, you are suggesting to use availableForWrite() instead of flush() for Serial2? I'll give that a shot and see if I have any issues.
This seems high enough priority (a Serial UART not working as it should) to add to the bug fixes list for future DeviceOS versions. Is it possible to fix Flush in DeviceOS code?
No, availableForWrite behaves the same way as flush() on Serial2.
I believe it's a problem in how Serial2 works on the P2/Photon 2. All of the other ports uses a dedicated UART peripheral, but Serial2 uses the generic high speed serial port, which is also used for SPI. It appears that it behaves differently.
Serial3 shares the same pins as SPI, but Serial3 uses an internal pin mux to switch the port between the dedicated UART peripheral and the SPI peripheral, which is why that behaves differently.
So for now, the fix is to add a delay (not really a solution for my application), change my board design to Serial1 or Serial3, or potentially wait for a DeviceOS solution/fix?