-
Notifications
You must be signed in to change notification settings - Fork 467
SerialPIO with baudrate 19200 receives incorrect data #2928
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
Comments
Can you post a pulseview/CSV high resolution capture of the serial data at the Pico pin? Without your specific hardware there's not much that can be done by anyone else. A simple loopback test, using UART0 and SoftwareSerial runs fine. Hook pin GP0 to GP15 and the output is as expected without corruption so there's nothing immediately obvious:
The divider in SerialPIO being off by a fraction of a 133MHz clock is immaterial at 19200bps. arduino-pico/cores/rp2040/SerialPIO.cpp Line 252 in 8d58a92
The way the SW serial UART is implemented it waits for the 1st transition of the start bit and counts to 1/2 the bit time, then samples every bit time (~2x that calculated delay). If there is noise on the line (or a very slow transition so the pin is indeterminate state) even for 1/133MHz of a second, then the start bit may be detected before the actually intended start bit. I think there were some cheap Chinese GPS units that had this kind of issue, check the closed reports here. They solved it, IIRC, by adjusting the baud rate passed in to work around the noise. |
Thanks for your answer. I'll try to get the capture and provide a picture from the scope. From my experience local loopback on the same system works most of the time fine as both UARTs are using the same system clock and experience no clock drift between them. The errors start when using different systems with different clocks. In my case sometimes the data is correct for a short period (2-3 seconds). Then errors occur for a longer time and the data may be ok for some bytes. The source is a Victron Smartshunt, connected to a PC I did not see errors during half an hour of monitoring, so I assume the TX baud matches good enough standard 19200, but I will compare again. |
The SerialPIO(SoftwareSerial) receive path was convoluted and required a lot of work on the host to get the actual data out. It also wasn't always sampling on the proper edge leading to errors whenever clocks or hold times shifted slightly. Rewrite the SerialPIO RX path fo explicitily wait for start bit, pause 1/2 bit time, then idle for a full bit time for all bits. Takes more PIO instruction memory but works flawlessly even with mismatched clocks. Tested with a loopback from HW UART to SW UART with a 5% clock mismatch @ 19200 baud without reception errors, whereas the original code would fail with less than a 0.5% variation. Fixes #2928 ```` SoftwareSerial s(15, -1); void setup() { Serial1.setTX(0); Serial1.begin(19200 + 1920/2, SERIAL_8N1); s.begin(19200, SERIAL_8N1); } void loop() { Serial.println("---"); Serial1.write("Had we but world enough and time", 32); uint32_t now = millis(); while (millis() - now < 500) { while (s.available()) { auto c = s.read(); Serial.printf("%02x '%c'\n", c, c); } } } ````
@earlephilhower Sorry for the delay. That is great, I did a test with the device and it looks very good, I now see correct data even for multiple hours. I also did a test with a USB-Serial converter (cheap CP210x something), which before also failed at 19200. Same here, works fine. Thank you very much, I can now use the RP2040 to monitor five devices and use a sixth serial port for RS485. |
Awesome, thanks for the update. No need to capture more info. I think the new way is simple enough to grok by just reading the code and it's now checking exactly (and only) at the bit center. My original code hurt my head trying to intuit exactly what bits and positions were getting dumped... |
The SerialPIO(SoftwareSerial) receive path was convoluted and required a lot of work on the host to get the actual data out. It also wasn't always sampling on the proper edge leading to errors whenever clocks or hold times shifted slightly. Rewrite the SerialPIO RX path to explicitily wait for start bit, pause 1/2 bit time, then idle for a full bit time for all bits. Takes more PIO instruction memory but works flawlessly even with mismatched clocks. Tested with a loopback from HW UART to SW UART with a 5% clock mismatch @ 19200 baud without reception errors, whereas the original code would fail with less than a 0.5% variation. Fixes #2928 ```` SoftwareSerial s(15, -1); void setup() { Serial1.setTX(0); Serial1.begin(19200 + 1920/2, SERIAL_8N1); s.begin(19200, SERIAL_8N1); } void loop() { Serial.println("---"); Serial1.write("Had we but world enough and time", 32); uint32_t now = millis(); while (millis() - now < 500) { while (s.available()) { auto c = s.read(); Serial.printf("%02x '%c'\n", c, c); } } } ````
Hi all,
I'm trying to get SerialPIO working with a Pico. After receiving incomplete data and disabling/removing more and more code I'm down to this test program:
I also tried changing the system clock from 200 MHz to 120 MHz or 240 MHz since because of this code:
arduino-pico/cores/rp2040/SerialPIO.cpp
Line 252 in 8d58a92
clock_get_hz(clk_sys) / (_baud * 2) - 7
With 120 MHz and 19200 it gets a nice round number of 3118.
It is not that it never matches the data but is about 50% errors or more, for example:
Normally everything is ASCII, tabs and newlines.
I would be happy for every idea what I could check.
The text was updated successfully, but these errors were encountered: