codingisfun
Member
I have run into the problem that when you use USB Serial as a bi-directional device, Teensy 3.1 tends to lose some data. I was wondering if anybody else has run into this problem and would have some advice on how to solve the problem.
Concretely, I am trying to use a Teensy 3.1 as an interface to my PC, where the Teensy monitors sensors and other microcontrollers, sending a lot of data to the PC to store, visualize and process it there, and receiving a lot of stored data from the PC to feed it to the microcontrollers. The maximum capacity I need is 588 kBytes/sec from the PC to Teensy, and 192 kBytes/sec from Teensy to the PC (in parallel). I can easily achieve either, but when I try to do this in parallel, data is lost going from Teensy to the PC. I have brought it down to a very simple sketch illustrating the issue:
And on the PC side, using Processing 2.0:
When I run this, I find that I lose some data going from Teensy to the PC.
Checking out the source code of the Teensy USB modules, I found that Teensy drops data going out, either if there is no space in the buffers anymore, or if the PC does not react for some time. Without having understood all the details of how things work, and understanding the design trade-off that you cannot buffer a lot of data on Teensy (and have to go for either making the application wait or dropping data if the buffers get full), I still would like to get this to work. Note that I have broken down the data into packets that fit the 1kHz rate of USB (i.e. one read and one write per ms), and that they also fit the 64-byte USB-packet size used in the Teensy USB modules, with 192 bytes being 3 such packets).
Any suggestions on what might work? I have been considering the following:
- Go for 64 byte packets (i.e. exactly what the Teensy USB modules use) - just breaking down the current "readBytes" and "write" calls did not make a difference (as expected), but maybe a different ordering of reads and writes might
- Try to increase the number of buffers used in the Teensy USB modules (if I understood it correctly, currently there are 12 buffers of 64 bytes each, which is exactly what I would fill up per ms - I could understand that you can lose data in that case, even though I do not understand how the benchmarks figures of about 1 MByte/sec transfer rates are achieved if you can only store 12*64=768 bytes per ms in the buffers); if possible, I would try to avoid changing anything in the core modules, but if that is the recommended way, I would try that
- Try to implement something using the RAW_HID interface (and thus control exactly what is transferred in every ms) - what keeps me from doing that is the issue of implementing a RAW_HID interface on the host side in Processing.
Any ideas or hints? Thanks a lot for your help!
Cheers,
CodingIsFun
Concretely, I am trying to use a Teensy 3.1 as an interface to my PC, where the Teensy monitors sensors and other microcontrollers, sending a lot of data to the PC to store, visualize and process it there, and receiving a lot of stored data from the PC to feed it to the microcontrollers. The maximum capacity I need is 588 kBytes/sec from the PC to Teensy, and 192 kBytes/sec from Teensy to the PC (in parallel). I can easily achieve either, but when I try to do this in parallel, data is lost going from Teensy to the PC. I have brought it down to a very simple sketch illustrating the issue:
Code:
const int insize = 3*192;
const int outsize = 4*48;
void setup()
{
char inbuf[insize];
char outbuf[outsize];
int i;
long sent, received;
Serial.begin(9600);
while (!Serial) ;
sent = 0; received = 0;
for (i = 0; i < 32000; i++) {
received = Serial.readBytes(inbuf, insize);
received += rec;
Serial.write(outbuf, outsize);
Serial.send_now();
sent += outsize;
}
}
void loop()
{
}
And on the PC side, using Processing 2.0:
Code:
import processing.serial.*;
Serial port;
i
void setup()
{
int i;
byte[] inbuf = new byte[4*48];
byte[] outbuf = new byte[3*192];
long t0, t1;
int rec, received, sent;
port = new Serial(this, "COM27", 9600);
received = 0; sent = 0;
t0 = millis();
for (i = 0; i < 32000; i++) {
port.write(outbuf);
sent += outbuf.length;
if (port.available() > 0) {
received = port.readBytes(inbuf);
} else {
println("missed reading data at block "+i);
}
if (i % 1000 == 0) {
t1 = millis();
println("sent "+sent+", received "+received+" in "+(t1-t0)+" ms");
}
}
t1 = millis();
println(""+sent+" bytes sent, "+received+" bytes received in "+(t1-t0)+" ms");
}
void draw()
{
}
When I run this, I find that I lose some data going from Teensy to the PC.
Checking out the source code of the Teensy USB modules, I found that Teensy drops data going out, either if there is no space in the buffers anymore, or if the PC does not react for some time. Without having understood all the details of how things work, and understanding the design trade-off that you cannot buffer a lot of data on Teensy (and have to go for either making the application wait or dropping data if the buffers get full), I still would like to get this to work. Note that I have broken down the data into packets that fit the 1kHz rate of USB (i.e. one read and one write per ms), and that they also fit the 64-byte USB-packet size used in the Teensy USB modules, with 192 bytes being 3 such packets).
Any suggestions on what might work? I have been considering the following:
- Go for 64 byte packets (i.e. exactly what the Teensy USB modules use) - just breaking down the current "readBytes" and "write" calls did not make a difference (as expected), but maybe a different ordering of reads and writes might
- Try to increase the number of buffers used in the Teensy USB modules (if I understood it correctly, currently there are 12 buffers of 64 bytes each, which is exactly what I would fill up per ms - I could understand that you can lose data in that case, even though I do not understand how the benchmarks figures of about 1 MByte/sec transfer rates are achieved if you can only store 12*64=768 bytes per ms in the buffers); if possible, I would try to avoid changing anything in the core modules, but if that is the recommended way, I would try that
- Try to implement something using the RAW_HID interface (and thus control exactly what is transferred in every ms) - what keeps me from doing that is the issue of implementing a RAW_HID interface on the host side in Processing.
Any ideas or hints? Thanks a lot for your help!
Cheers,
CodingIsFun