damianolodi
Member
Hi everyone,
we recently started to use some Teensy boards in various parts of our product. Everything is working great, but I have a random loss of bytes during USB communication.
The system I am working on is this:
(NB: Serial7 is connected to Temperature Controller 7 of course, is a typing error)
I am programming both boards with PlatformIO and the Teensy framework, while on the Odroid I have a Python program that interface with USBs and is bouncing messages back and forth to allow communication between the boards.
Basically, the Teensy 3.6 wants to control the temperature controllers, so
Odroid
On the Odroid, the Python program is continuously listening on the USB port and reads any message until "\n" arrive.
This is the relevant code:
This same code, in a different program, is reading messages from an FTDI chip connected to a serial interface of an FPGA at 4.000.000 baud, without loosing data.
(Still, I am not discarding the option that this can be the source of loss)
Teensy 3.6
On the Teensy 3.6 side, I am writing serial messages with a strict format, and each message is ending with "\n". It will be difficult to isolate all the functions that are composing the message, for now I will post the main ones:
This Teensy is also doing some other things: it has a DMA on DAC1, it uses DAC2 and it has 2 interrupts to read ADCs and change some GPIO but all of this is not interfering with the USB port.
Teensy 4.0
On the Teensy 4.0 side, I catch the messages using the serialEvent function, and I put them into a circular buffer. From there they are sent when the temperature controller is ready.
Questions
So the problem that I see happening almost randomly is that, for example, if I am expecting two messages like "ooo.M.message 1\n" and "ooo.M.message 2\n", instead I read "ooo.M.message 1ooo.M.message 2\n" or even "ooo.M.messooo.M.message 2\n". Of course when this happens, communication fail.
I red some posts on this forum about Serial, and in some of them Paul was mentioning that the "print" and "println" will wait for other function calls to improve communication efficiency. Still, here I am using "write" because I am printing a composite message saved on an array.
So I am asking you some questions:
Concerning this last question I was thinking to attach the Teensy to a serial monitor and see if I have bytes drops. Still, this is not testing the entire program because to advance in its internal state machine, the Teensy 3.6 expect answers and of course the serial monitor is not answering. So maybe you have a better idea.
If some code or details are missing, feel free to ask.
Thank you in advance for your help!
we recently started to use some Teensy boards in various parts of our product. Everything is working great, but I have a random loss of bytes during USB communication.
The system I am working on is this:
(NB: Serial7 is connected to Temperature Controller 7 of course, is a typing error)
I am programming both boards with PlatformIO and the Teensy framework, while on the Odroid I have a Python program that interface with USBs and is bouncing messages back and forth to allow communication between the boards.
Basically, the Teensy 3.6 wants to control the temperature controllers, so
- it sends a message to the Odroid
- the message is bounced on the Teensy 4.0 over USB
- then bounced on the proper temperature controller on the hardware serial port
- the answer of the temperature controller is then doing the path in the opposite direction
Odroid
On the Odroid, the Python program is continuously listening on the USB port and reads any message until "\n" arrive.
This is the relevant code:
Code:
class FastSerial(serial.Serial):
def __init__(self, port, name, run=False, baudrate=4000000, timeout=2, dtr=False):
self.buf = bytearray()
super().__init__(port=port, baudrate=baudrate, timeout=timeout)
self.name = name
if dtr:
self.dtr = 0
if run:
self.recv_qs = weakref.WeakSet([])
self.send_q = Queue()
self.q_lock = Lock()
listener = Thread(target=self.listen, args=())
listener.start()
def readline(self, newline=b'\n'):
i = self.buf.find(newline)
if i >= 0:
r = self.buf[:i+1]
self.buf = self.buf[i+1:]
return r
while True:
i = max(1, min(2048, self.in_waiting))
data = self.read(i)
i = data.find(newline)
if i >= 0:
r = self.buf + data[:i+1]
self.buf[0:] = data[i+1:]
return r
else:
self.buf.extend(data)
def listen(self):
name = self.name
q_lock = self.q_lock
recv_qs = self.recv_qs
readline = self.readline
while True:
line = readline().decode()
if line:
for q in recv_qs:
with q.lock:
# Each private q has its private lock created
# by the serial interface.
q.put_nowait(name + '.' + line)
This same code, in a different program, is reading messages from an FTDI chip connected to a serial interface of an FPGA at 4.000.000 baud, without loosing data.
(Still, I am not discarding the option that this can be the source of loss)
Teensy 3.6
On the Teensy 3.6 side, I am writing serial messages with a strict format, and each message is ending with "\n". It will be difficult to isolate all the functions that are composing the message, for now I will post the main ones:
Code:
/// One of the functions that is sending a message
void TEC::read_setpoint() {
size = TEC::encode_msg(&tecCmds.setpoint, 1, false, 0);
Serial.write(msg, size);
}
// Encode the message for the temperature controller
uint8_t TEC::encode_msg(const uint8_t *cmd, uint8_t cmd_size, bool set, uint32_t val) {
memcpy(msg, this->msg_address, MSG_ADDRESS_SIZE);
*(msg + 3) = '-';
*(msg + 4) = 'T';
*(msg + 5) = '.';
memcpy(msg + 6, cmd, cmd_size);
cmd_size += 6;
if (set) {
cmd_size = TEC::to_digits(msg, cmd_size, val);
} else {
*(msg + cmd_size) = '?';
cmd_size++;
}
*(msg + cmd_size) = '\n';
cmd_size++;
return cmd_size;
}
This Teensy is also doing some other things: it has a DMA on DAC1, it uses DAC2 and it has 2 interrupts to read ADCs and change some GPIO but all of this is not interfering with the USB port.
Teensy 4.0
On the Teensy 4.0 side, I catch the messages using the serialEvent function, and I put them into a circular buffer. From there they are sent when the temperature controller is ready.
Code:
void serialEvent() {
while (Serial.available()) {
uint8_t msgLen = Serial.readBytesUntil('\n', usb_buffer, 20);
err = 0;
switch (usb_buffer[0]) {
case '1':
err = circular_buf_put2(cmd_buffer_1, usb_buffer + 1, msgLen - 1);
if (err) {
circular_buf_reset(cmd_buffer_1);
Serial.write("ooo.E.TEC-0-0: buffer 1 full\n");
}
break;
case '2':
// ...
// all cases are equal
default:
Serial.write("ooo.E.TEC: error: ");
Serial.write(usb_buffer, msgLen);
Serial.write("\n");
break;
}
}
}
Questions
So the problem that I see happening almost randomly is that, for example, if I am expecting two messages like "ooo.M.message 1\n" and "ooo.M.message 2\n", instead I read "ooo.M.message 1ooo.M.message 2\n" or even "ooo.M.messooo.M.message 2\n". Of course when this happens, communication fail.
I red some posts on this forum about Serial, and in some of them Paul was mentioning that the "print" and "println" will wait for other function calls to improve communication efficiency. Still, here I am using "write" because I am printing a composite message saved on an array.
So I am asking you some questions:
- did you experienced any bytes drop when reading USB port with Python programs? Or other programs?
- do you know which is the best way to interface with USB on a Linux PC? (Odroid has Ubuntu 18.04 for arm) - maybe C++ or C?
- is there any performance difference between using "Serial.print" and "Serial.write"?
- is there a more efficient/better way to read incoming USB messages?
- do you have any idea on how to isolate different parts of the system to test them and see where the bytes drop happen?
Concerning this last question I was thinking to attach the Teensy to a serial monitor and see if I have bytes drops. Still, this is not testing the entire program because to advance in its internal state machine, the Teensy 3.6 expect answers and of course the serial monitor is not answering. So maybe you have a better idea.
If some code or details are missing, feel free to ask.
Thank you in advance for your help!