-
-
Notifications
You must be signed in to change notification settings - Fork 7k
Description
Trying to use SoftwareSerial at 115200 on an Arduino Uno only gave me garbage output. After trying to fix the timings, things improved, but I've still not managed to fix everything.
To be able to reliably and repeatedly test the SoftwareSerial class, I
wrote a small python script. It talks to the Uno's USB serial and to
a separate USB serial convertor (I used this one and a
cp210x one, but any one should do).
The serial convertor is connected to pin 2 and 3 of the Uno, which
creates a SoftwareSerial object on those pins. The sketch on the Uno
then forwards data between SoftwareSerial and the regular Serial object.
Additionally, using some binary commands that are not forwarded, the
python script can tell the sketch to open and close the SoftwareSerial
port and specify the baudrate to use.
I tested all rates listed in the SoftwareSerial timing table and found
that reception of the faster rates (and somehow, also 300 baud) failed.
For transmission, it's the reverse: Only the higest rates work, the
lower ones fail. Using gcc 4.8, things are even worse - none of the TX
rates works.
I tested all the rates listed in the SoftwareSerial timing table and
found that TX works every time (at 16Mhz) and fails at 115200 (at 8Mhz), but RX
fails at 115200 baud (at 16Mhz) and 38400 and up (at 8Mhz).
31250 baud also failed, but this appears to be a problem in the cp210x I
was using, using the Arduino USBSerial board 31250 worked (but 300 baud
failed...). When using gcc 4.8, RX baudrates from 28800 and up fail.
I tested the 1.5 branch with both the bundled gcc 4.3 version and a
locally compiled gcc 4.8 version and the master branch with just the
bundled 4.3 version. This was tested on a Uno, running at 16Mhz and at
8Mhz (using the prescaler register in the sketch below and setting the
cpu speed in boards.txt).
I'll see if I can fix this, but wanted to provide some documentation
about this issue already.
Here's the output from 1.5 with gcc 4.3 at 8Mhz.
Waiting for Arduino to start up
Testing at 300 baud
RX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 600 baud
RX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 1200 baud
RX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 2400 baud
RX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 4800 baud
RX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 9600 baud
RX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 14400 baud
RX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 19200 baud
RX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 28800 baud
RX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 31250 baud
RX: &\xa5K\xb5\xa8\x16g\xbd-\x a}hW\x17\xb5S\xbc\xa8\xb6Ui\x94\xa8\xf6eg\xb5\x96K\xbcoJA\xb1\xa9\x16S\xbbV\xe3O\x90-\x15i\x96
TX: \x18\xff\xdf\xff\xe4\xff\xcb\xff\xdb\xff\xc0\xd3\xff\xe0\xff\xe7\xff\xeb\xff\xdb\xff\xc0\xc8\xff\xdf\xff\xd8\xff\xdf\xff\xe4\xff\xc0\xe7\xff\xd3\xff\xe8\xff\xc0\xc3\xff\xdb\xff\xcb\xff\xe8\xff\xd8\xc0\xc7\xff\xdf\xff\xdc\xff\xe7\xff\xcb\xff\xc7\xff\xe8\xff\xcb\xff\xe8\xff\xeb\xff\xcb\xff\xe4\xff\xc0\xc3\xff\xc8\xff\xd3\xff\xe0\xff\xd3\xff\xe7\xff\xc7\xff\xd3\xff\xdc\xff\xcf\xff\xc0\xcb\xff\xd8\xff\xd3\xff\xe8\xff\xdc
Testing at 38400 baud
RX: Lore\xdd \xc9psum@d\xdflor \xe3i\xe4 ame\xec,@conse\xc3t\xc5tuer@adip\xd1s\xc3ing \xcdl\xc9t.
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 57600 baud
RX: L\xdfye\xed \xe9p\xf3u\xed \xe4o\xeco\xf2 \xf3i\xf4 \xc1m\xc5tL \xc3o\xces\xc5c\xe4e\xe4u\xc5r@a\xc4i\xe0i\xe3c\xd1n\xcf\x10dl\xd1t^
TX: Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Testing at 115200 baud
RX: NyW\x17Q\x13\xf3\xf5\xcd@\xe4\xef\xec\xef\xf2`\xf3\xe8\xf4 \xe0\x9b\xd8\xdc\xcb\xc8\x96y\x9d%\x d\xb15\xb1\x95\x15\x89\x 0\x 4\x90\xe8\xf0\xe8\xf3\xe3\xe8\xef\x 1-aM\xa1y\xff
TX: \x98\xde\xe4\xca\xda@\xd2\xe0\xe6\xea\xda@\xc8\xde\xd8\xde\xe4@\xe6\xd2\xe8@\xc2\xda\xca\xe8X@\xc6\xde\xdc\xe6\xca\xc6\xe8\xca\xe8\xea\xca\xe4@\xc2\xc8\xd2\xe0\xd2\xe6\xc6\xd2\xdc\xce@\xca\xd8\xd2\xe8\
Here's the python script I was using (requires python 3.3):
#!/usr/bin/python3
import sys
import time
import struct
import serial
import threading
tester = serial.Serial()
tester.port = "/dev/serial/fonera"
dut = serial.Serial()
dut.port = "/dev/ttyACM0"
dut.baudrate = 57600
text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit."
def read(prefix, ser, timeout):
sys.stdout.write(prefix)
sys.stdout.flush()
ser.timeout = .1
end = time.monotonic() + timeout
while (time.monotonic() < end):
def printable(c):
return c >= 0x20 and c < 0x7f
data = ''.join(chr(c) if printable(c) else "\\x{:2x}".format(c) for c in ser.read())
sys.stdout.write(data)
sys.stdout.flush()
sys.stdout.write("\n")
def testBaud(rate):
sys.stdout.write("Testing at {} baud\n".format(rate))
# First open the tester, then enable the dut, to prevent garbage on the line
# from opening the tester being reported.
tester.baudrate = rate
tester.open()
time.sleep(0.1)
# Switch device-under-test to the new baudrate, by sending a byte with value
#1 followed by the baudrate as a big-endian 32-bit number
dut.write(struct.pack(">BI", 1, rate))
time.sleep(0.1)
# Test RX
tester.write(text.encode('ascii'))
read("RX: ", dut, len(text) / rate * 16 + 1)
# Test TX
dut.write(text.encode('ascii'))
read("TX: ", tester, len(text) / rate * 16 + 1)
sys.stdout.write("\n")
# Switch the dut reception off first, and then the close the tester
dut.write(struct.pack(">B", 2))
time.sleep(0.1)
tester.close()
# Open the device-under-test port, this causes the Arduino to reset
dut.open()
sys.stdout.write("Waiting for Arduino to start up\n")
time.sleep(3)
testBaud(300)
testBaud(600)
testBaud(1200)
testBaud(2400)
testBaud(4800)
testBaud(9600)
testBaud(14400)
testBaud(19200)
testBaud(28800)
testBaud(31250)
testBaud(38400)
testBaud(57600)
testBaud(115200)
# vim: set sw=2 sts=2 expandtab:
And the Arduino sketch:
#include <SoftwareSerial.h>
SoftwareSerial ss(2, 3);
void setup() {
if (F_CPU == 8000000L) {
CLKPR = (1 << CLKPCE);
CLKPR = 1;
}
Serial.begin(57600);
}
bool listening = false;
void loop() {
int c = Serial.peek();
if (c == 1) {
if (Serial.available() >= 5) {
Serial.read();
uint32_t baud = ((uint32_t)Serial.read() & 0xff) << 24 |
((uint32_t)Serial.read() & 0xff) << 16 |
((uint32_t)Serial.read() & 0xff) << 8 |
((uint32_t)Serial.read() & 0xff);
ss.begin(baud);
listening = true;
}
} else if (c == 2) {
Serial.read();
ss.end();
listening = false;
} else if (c != -1) {
static int avail = 0;
delay(10);
// Forward any other bytes to SoftwareSerial. However, take care to
// only do this when we haven't received any bytes in the past 10ms,
// since SoftwareSerial::write at lower baudrates will break regular
// Serial reception due to disabled interrupts.
if (Serial.available() == avail) {
Serial.read();
ss.write(c);
--avail;
} else {
avail = Serial.available();
}
}
while (listening && ss.available())
Serial.write(ss.read());
}