MartynHill
Member
Hi everyone
I have spent days troubleshooting a Serial USB issue with my Teensy++2.0 and have either uncovered a bug (library or hardware) or have misunderstood something about how the USB packet buffers operate in the device.
Some details:
USB Host: Windows 7, tested with the latest and earlier USB Virtual-COM Port Drivers installed
TeensyDuino/Arduino versions tested: 1.5.3/1.18.13 and the latest v1.5.7/1.8.19
In short, when using Serial.write() followed by a Serial.send_now() of a stream of bytes that happens to be an exact multiple of 64-bytes in length, the USB packet never leaves the device, until a new byte is sent (which is my workaround.) I have verifided that nothing leaves the device by sniffing the USB packets in Wireshark.
Serial.send_now() DOES return (toggling a digital Pin immediately after send_now is observable) even though my (possibly flawed) understanding is that it should block until the USB host takes the packet - I rely on this blocking activity to maintain synchronisation between my applications on the Teensy and in Windows (actually, within a retro-computer emulation running in Windows.)
Workaround: If the length of the next packet to be sent to the USB Host is exactly divible by 64-bytes, I add an extra null-byte before issuing send_now(), and which is then dropped within the target application.
Here's a code snippet, if it's needed, including the workaround:
Is there a better approach?
Warm regards
I have spent days troubleshooting a Serial USB issue with my Teensy++2.0 and have either uncovered a bug (library or hardware) or have misunderstood something about how the USB packet buffers operate in the device.
Some details:
USB Host: Windows 7, tested with the latest and earlier USB Virtual-COM Port Drivers installed
TeensyDuino/Arduino versions tested: 1.5.3/1.18.13 and the latest v1.5.7/1.8.19
In short, when using Serial.write() followed by a Serial.send_now() of a stream of bytes that happens to be an exact multiple of 64-bytes in length, the USB packet never leaves the device, until a new byte is sent (which is my workaround.) I have verifided that nothing leaves the device by sniffing the USB packets in Wireshark.
Serial.send_now() DOES return (toggling a digital Pin immediately after send_now is observable) even though my (possibly flawed) understanding is that it should block until the USB host takes the packet - I rely on this blocking activity to maintain synchronisation between my applications on the Teensy and in Windows (actually, within a retro-computer emulation running in Windows.)
Workaround: If the length of the next packet to be sent to the USB Host is exactly divible by 64-bytes, I add an extra null-byte before issuing send_now(), and which is then dropped within the target application.
Here's a code snippet, if it's needed, including the workaround:
Code:
// Added DEBUG signalling
PORTB |= 0b10000000; // DEBUG_USB - 50us: USB_SEND_START
delayMicroseconds(50);
PORTB &= 0b01111111;
Serial.write( MQ_SYNC, MQ_SYNC_LEN );
Serial.write( &mQTable[nextReplyMQSlot * MQTABLE_ENTRY_SZ], MESSAGE_HLEN );
if ( (mID & MQ_LONG_MASK) && (mLenPar2 > 0) ) {
mBufPtr=getMQBufPtr(nextReplyMQSlot);
Serial.write( &heap[mBufPtr], mLenPar2 );
mBufPtr=releaseHeap(mBufPtr); // Release the heap-space used for the LONG reply
// Workaround for fault in Serial.write/send_now for packets with lengths exactly divisble by 64!
if ( (mLenPar2 + MQ_SYNC_LEN + MESSAGE_HLEN) % USB_PACKET_LEN == 0) Serial.write( NUL_CHAR );
}
Serial.send_now(); // On Teensy, will force (and wait for) all pending USB data to be transmitted
// Added DEBUG signalling
PORTB |= 0b10000000; // DEBUG_USB - 50us: USB_SEND_STOP
delayMicroseconds(50);
PORTB &= 0b01111111;
Is there a better approach?
Warm regards