Hello, I'm working on streaming data from PC to WS2811/2/3 strips/strings (Neopixels). Because of strict WS2811-3 timing requirements, Teensy 3.2 was chosen to distribute data from PC to the strips because of the excellent OctoWS2811 board with library and Teensy's USB full speed serial throughput. However I have experienced very often PC->Teensy data corruptions when a larger amount of data is transferred over USB serial.
I have narrowed the problem down to scenario, where PC is sending data to its serial port and Teensy is receiving the data by usb_serial functions and verifying it (so OctoWS2811 does not have anything with this issue). When the Teensy is receiving the data without any processing (without the delay call in the code below), everything works fine. I can see 800 kbps with 512 byte chunks (see the COUNT macro below) or even 1000 kBps with 4096 byte chunks sent to the Teensy. But when I simulate some data processing (e.g. leds.show()) by the delay call in the Teensy code below, Teensy gets corrupted data within a few seconds (i.e. after 30 kB, 60kB or 1MB of data transferred). I can see that the data is corrupted, because when the data verification fails, Teensy is instructed to blink slowly forever.
Note that I'm expecting the Teensy to regulate the incoming serial data throughput from PC via USB Flow Control, which is dedicated to such function. Also, the USB Flow Control already works to some extent because when data verification is disabled and the delay below enabled, I can see stable throughput of 160 kBps. From the big picture, I intend to use the USB Flow Control to automatically maximize the refresh rate of the WS2811-3 strips, i.e. generate and send the data from PC as fast as Teensy is able to receive and process it.
I was searching through this forum whether somebody else have already faced this issue, but have found only problems with Teensy transmit drops. That one could have been fixed by removing timeouting code from usb_serial.c, but that's not the case of Teensy USB serial receive drops.
Teensy code:
Generator code (VC++):
I have spent a lot of time investigating this and I don't know what else I can try besides modifying Teensy core library sources. Maybe someone with more background will have the answer right out of the box based on my description.
This whole issue looks like some USB packets are just dropped on seemingly random basis. From my software-experienced developer point of view, this behavior may point to some race conditions when pulling bytes from full USB buffers.
Tested on:
- multiple pieces of Teensy 3.2 at 96, 72, 48 MHz
- Teensyduino 1.44, Arduino 1.8.7
- Windows 7, Visual C 6 (the code works in up to VC 2017 and also under Linux)
I have narrowed the problem down to scenario, where PC is sending data to its serial port and Teensy is receiving the data by usb_serial functions and verifying it (so OctoWS2811 does not have anything with this issue). When the Teensy is receiving the data without any processing (without the delay call in the code below), everything works fine. I can see 800 kbps with 512 byte chunks (see the COUNT macro below) or even 1000 kBps with 4096 byte chunks sent to the Teensy. But when I simulate some data processing (e.g. leds.show()) by the delay call in the Teensy code below, Teensy gets corrupted data within a few seconds (i.e. after 30 kB, 60kB or 1MB of data transferred). I can see that the data is corrupted, because when the data verification fails, Teensy is instructed to blink slowly forever.
Note that I'm expecting the Teensy to regulate the incoming serial data throughput from PC via USB Flow Control, which is dedicated to such function. Also, the USB Flow Control already works to some extent because when data verification is disabled and the delay below enabled, I can see stable throughput of 160 kBps. From the big picture, I intend to use the USB Flow Control to automatically maximize the refresh rate of the WS2811-3 strips, i.e. generate and send the data from PC as fast as Teensy is able to receive and process it.
I was searching through this forum whether somebody else have already faced this issue, but have found only problems with Teensy transmit drops. That one could have been fixed by removing timeouting code from usb_serial.c, but that's not the case of Teensy USB serial receive drops.
Teensy code:
Code:
#define BUSYPIN 13 //This pin will be high when busy
static void blink(int ms)
{
for(;;){digitalWrite(BUSYPIN, HIGH);delay(ms);digitalWrite(BUSYPIN, LOW);delay(ms);}
}
static int serial_read(void* dst, int size)
{
while(usb_serial_available()<size);
return usb_serial_read(dst, size);
}
void setup()
{
pinMode(BUSYPIN, OUTPUT);
}
void loop()
{
uint32_t count;
serial_read(&count, sizeof(count));
digitalWrite(BUSYPIN, HIGH);
for(uint32_t i=0;i<count;i++)
{
int a;while((a=usb_serial_getchar())==-1); //Wait until a byte is ready
if(a!=(uint8_t)i)blink(400); //Blink forever when unexpected data received - with the delay below, this happens within a second
}
digitalWrite(BUSYPIN, LOW);
delay(3); //Comment this out to get working setup (seems that Teensy is able to consume the data faster that USB full speed is passing it through)
}
Generator code (VC++):
Code:
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#define O_BINARY 0
#endif
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#define COUNT 512
int main()
{
unsigned char buf[sizeof(long)+COUNT];
*(long*)buf=COUNT;
for(size_t i=0;i<COUNT;i++)buf[sizeof(long)+i]=(unsigned char)i; //This data will be verified by Teensy
int fd=open("\\\\.\\COM25", O_RDWR|O_BINARY);
if(fd==-1){perror("port open failed");return 1;}
size_t total=0;
for(time_t lastt=time(NULL), t;;)
{
total+=write(fd, buf, sizeof(buf));
t=time(NULL);
if(t!=lastt){printf("%d Bps\n", total);total=0;lastt=t;}
}
close(fd);
return 0;
}
I have spent a lot of time investigating this and I don't know what else I can try besides modifying Teensy core library sources. Maybe someone with more background will have the answer right out of the box based on my description.
This whole issue looks like some USB packets are just dropped on seemingly random basis. From my software-experienced developer point of view, this behavior may point to some race conditions when pulling bytes from full USB buffers.
Tested on:
- multiple pieces of Teensy 3.2 at 96, 72, 48 MHz
- Teensyduino 1.44, Arduino 1.8.7
- Windows 7, Visual C 6 (the code works in up to VC 2017 and also under Linux)