Teensy 3: Avoiding 'USB lockout' / need for Reset?

Status
Not open for further replies.

kriegsman

Member
I'm continuing to find that running some of my programs seem to cause 'USB lockout', where no new code can be uploaded to the Teensy 3 without resorting to a hardware Reset first. Given that I'm going to be armoring the Teensy inside a weather-proof (playa-proof!) enclosure, I want to be able to make sure that new software can be loaded over USB without requiring any access to the hardware Reset function.

My code is all SPI-heavy LED-driving (LPD8809) code; I'm using FastSPI_LED2 -- the new, Teensy-savvy version, but I was seeing the same periodic 'USB lockout' with older versions of the FastSPI library, too. My code runs inside the loop() call -- and does not ever return from the first call to 'loop()', so if there's some service routine happening outside of 'loop()', it's not getting automatically called. I have a few dozen different programs, and which ones cause 'USB lockout' and which ones don't seems mysteriously unpredictable to me. It seems, casually, to me that if I insert a call to delay() here and there, I get fewer lockouts, but this might just be anecdotal accidents. How likely is it that noise/ringing on the SPI pins is borking USB communication? Is it worth trying the 220-ohm-resistor trick, or is that merely voodoo here?

Ultimately, my question is this: What actually causes the Teensy 3 'USB lockout' condition? What can I do (or avoid) in my code to ensure that it never happens? Is there a service routine that I should periodically call?

Seeking enLEDenment-
-Mark
 
...it's over two years later, but did you ever figure this one out? I'm having the exact same problem, only with a teensy 3.1.
 
The basic answer is do not loop inside of the loop() routine in a 'normal' arduino style sketch, write your loop routine as if
Code:
void loop() {
  // do your thing
}
actually meant
Code:
while(1) {
  // do your thing
}
and it will have a much better chance of being robust over time.
 
The basic answer is do not loop inside of the loop() routine in a 'normal' arduino style sketch, write your loop routine as if (...) ant it will have a much better chance of being robust over time.

Thanks for the advise and comments!

Also, my basic old question still remains: Why is it like that? I'm looking for a complete "cause-and-effect" level of understanding here, not just "this works better / that works worse" -- although that is definitely useful, too!

I still don't understand why or how the T3 or T3.1 can lock itself out of USB communication like this, and that's what I'm really striving to understand deeply.


For the record, in the two years since I posted the original question, "FastSPI_LED2" has evolved into "FastLED v3" (which totally supports the T3 and T3.1), and I've become one of the two co-authors of that library. And even with all that additional time and coding... I still don't understand why the Teensy3/3.1 sometimes locks out USB communication and needs a hard reset... and I still wish I knew the cause.

Truthfully, it happens less to me these days, but it still happens, and I still can't say for sure why.
 
Also, my basic old question still remains: Why is it like that? I'm looking for a complete "cause-and-effect" level of understanding here, not just "this works better / that works worse" -- although that is definitely useful, too!

I still don't understand why or how the T3 or T3.1 can lock itself out of USB communication like this, and that's what I'm really striving to understand deeply.

As I do not know, what you are exactly doing inside the loop, or know your host OS, I can offer only my observation when T3.1 becomes non-responsive. Every time when the T3.1 cycles around a Serial.print, either intentionally, as in loop{Serial.print(...);}, or by chance, e.g. where an error handler cycles around a Serial.printf, and the Terminal on my windows system cannot keep up, the T3.1 will become non-responsive. On windows, there is potentially a very large Queue building up that could (IMO) lock the interaction with T3.1.
 
I wish I knew why too. It's very possible there's some subtle bug lurking deep within the USB code.

As always, to even start investigating, I need a program that reproduces the problem.
 
.... the Terminal on my windows system cannot keep up, the T3.1 will become non-responsive.

Teensyduino 1.21-test2 tries to address this, with several improvements to improve the Arduino Serial Monitor's ability to handle fast data. If you haven't given 1.21-test2 a try, I'd really like to know if it's effective at keeping up with maximum rate data on your machine?

However, 1.21-test2 is far from perfect. It's called "test2" and not even beta for a reason (the other half of that reason is testing the transition from gcc 4.7.2 to 4.8.4). It breaks the serial monitor in non-serial modes, and it also crashes the entire Arduino IDE if you try to initiate an upload at just the wrong moment during high speed incoming data.

Handling fast incoming data is difficult. I'm trying to get this working reliably, and 1.21-test2 is at least a step in that direction, but clearly I still have more work to do. Even with the known bugs, it's really help me if you could test on a machine that's seen bad problems with keeping up with maximum speed printing, and let me know what it's CPU usage is. Also, keep an eye on the java process's memory usage. It will grow initially, but over a long time, it should stablize and not infinitely leak memory (like 1.20 and all other Arduino without Teensyduino does).
 
Handling fast incoming data is difficult. I'm trying to get this working reliably, and 1.21-test2 is at least a step in that direction, but clearly I still have more work to do. Even with the known bugs, it's really help me if you could test on a machine that's seen bad problems with keeping up with maximum speed printing, and let me know what it's CPU usage is. Also, keep an eye on the java process's memory usage. It will grow initially, but over a long time, it should stablize and not infinitely leak memory (like 1.20 and all other Arduino without Teensyduino does).

As I experienced this in the last hour more or less every 5 minutes (trying to understand the behavior of spi-dma while doing scatter-gather)
and I only could go around this by killing JAVA Platform SE binary, I will try to collect some statistics.
 
As I experienced this in the last hour more or less every 5 minutes (trying to understand the behavior of spi-dma while doing scatter-gather)
and I only could go around this by killing JAVA Platform SE binary, I will try to collect some statistics.

I just generated on Windows 8.1 quad core I7 laptop, a non-responsive IDE and a locked Terminal (commented out clearInterrupt() (sic!) in an isr with an Serial.printf statement inside) but could not see any changes in the Task manager JAVA is stable on 0-1% CPU; 142.9 MB Memory; 0 MB/s disk activity. Any special place I could look to?
 
Last edited:
So, I will admit I really only understand about 25% of what is being said in the above replies! But, in my own testing, I've narrowed down to this phenomenon, and I'm wondering if someone could help me figure it out (and if it has anything to do with the above comments).

I've got the following piece of code that will only work if I comment out the
else if(pushNumber>0){
greenDots(pushNumber);
}
else (pushNumber==0){
setBlank();
}
bit in the loop.

//~~~~~~~~~~~~~~~~~~~~~~~ALL the libraries!~~~~~~~~~~~~~~~~~
//TIME
#include <Time.h>

//SD CARD
#include <SD.h>
#include <SPI.h>

//BTLE
//char INBYTE;
#define BTLE Serial1

//SPEAKER
#include "pitches.h"

//LEDS
#include <Adafruit_NeoPixel.h>

//VIBE MOTOR

//BUTTON




//~~~~~~~~~~~~~~~~~~~~~~~~PRE-SETUP~~~~~~~~~~~~~~~~~~~~~~~~~~~

//TIME

//SD CARD
File logFile;
const int chipSelect = 10;

//BTLE



//SPEAKER
const int speakerPin = 20;
int celebration1notes[8]={NOTE_C4, NOTE_D4, NOTE_E4, NOTE_F4, NOTE_G4, NOTE_A4, NOTE_B4, NOTE_C5};

//LEDS
#define PIN 16
#define NUMPIXELS 12
// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel. Avoid connecting
// on a live circuit...if you must, connect GND first.

//VIBE MOTOR
const int motorPin = 9;

//BUTTON
const int buttonPin = 8;
int buttonState = 0;
int pushNumber = 0;

//~~~~~~~~~~~~~~~~~~~~~~~~~SETUP~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void setup() {

//TIME
// set the Time library to use Teensy 3.0's RTC to keep time

setSyncProvider(getTeensy3Time);

Serial1.begin(9600);
if (timeStatus()!= timeSet) {
Serial1.println("Unable to sync with the RTC");
} else {
Serial1.println("RTC has set the system time");
Serial1.println("Time is:");
digitalClockDisplay();
}


//SD CARD
pinMode(10, OUTPUT);
if (!SD.begin(chipSelect)) {
Serial1.println("SD initialization failed!");
return;
}

//BTLE

//SPEAKER

//LEDS
strip.begin();
strip.show(); // Initialize all pixels to 'off'

//VIBE MOTOR
pinMode(motorPin, OUTPUT);

//BUTTON
pinMode(buttonPin, INPUT_PULLUP);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~LOOP~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void loop() {

buttonState = digitalRead(buttonPin);
if (buttonState == LOW) {
time_t t = now();
Serial1.print("Log time: ");
digitalClockDisplay();

//~~~~~~~~~~~~~~~~~~~ CELEBRATION~~~~~~~~~~~~~~~~~~~~~~~~

celebration1();

//~~~~~~~~~~~~~~~~~~~~LOG TO SD~~~~~~~~~~~~~~~~~~~~~~~~
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
logFile = SD.open("logFile.txt", FILE_WRITE);

// if the file opened okay, write to it:
if (logFile) {
Serial1.print("Writing to logFile.txt...");
logFile.print(hour());
logFile.print(":");
logFile.print((minute()));
logFile.print(":");
logFile.print((second()));
logFile.print(" ");
logFile.print(day());
logFile.print(" ");
logFile.print(month());
logFile.print(" ");
logFile.print(year());
logFile.println();
// close the file:
logFile.close();
Serial1.println("done.");
}
else {
// if the file didn't open, print an error:
Serial1.println("error opening logFile.txt");
}
pushNumber++;
delay(10);

}
else if(pushNumber>0){
greenDots(pushNumber);
}
else (pushNumber==0){
setBlank();
}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~FUNCTIONS~~~~~~~~~~~~~~~~~~~~~~~

//CELEBRATION 1

void celebration1() {
strip.setBrightness(255);
for(int i=0; i<8; i++){
digitalWrite(motorPin, HIGH);
if(i<7){
//Serial1.println(i);
tone(speakerPin, celebration1notes);
strip.setPixelColor(i, strip.Color(50,10,250));
strip.show();
delay(100);
}
else{
tone(speakerPin, celebration1notes);
theaterChase(strip.Color(127, 127, 127), 20);
delay(200);
}
}
digitalWrite(motorPin, LOW);
noTone(speakerPin);
fadeOut(1000);
}


//TIME

void digitalClockDisplay() {
// digital clock display of the time
Serial1.print(hour());
printDigits(minute());
printDigits(second());
Serial1.print(" ");
Serial1.print(day());
Serial1.print(" ");
Serial1.print(month());
Serial1.print(" ");
Serial1.print(year());
Serial1.println();
}

time_t getTeensy3Time()
{
return Teensy3Clock.get();
}

/* code to process time sync messages from the serial port */
#define TIME_HEADER "T" // Header tag for serial time sync message

unsigned long processSyncMessage() {
unsigned long pctime = 0L;
const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013

if(Serial1.find(TIME_HEADER)) {
pctime = Serial1.parseInt();
return pctime;
if( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013)
pctime = 0L; // return 0 to indicate that the time is not valid
}
}
return pctime;
}

void printDigits(int digits){
// utility function for digital clock display: prints preceding colon and leading 0
Serial1.print(":");
if(digits < 10)
Serial1.print('0');
Serial1.print(digits);
}



//SD CARD

//BTLE

//SPEAKER

//LEDS
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
for (int j=0; j<10; j++) { //do 10 cycles of chasing
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, c); //turn every third pixel on
}
strip.show();

delay(wait);

for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}


// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}

void blackout()
{
for (int i = 0 ; i < NUMPIXELS; i++)
{
strip.setPixelColor(i, 0, 0, 0);
}
strip.show();
}

void fadeOut(int time) {
for (int i = 0; i < 255; i++) {
strip.setBrightness(255-i);
strip.show();
delay (time/255);
}
blackout();
}

void setGreen() {
strip.setBrightness(20);
for (int j = 0 ; j < NUMPIXELS; j++)
{
strip.setPixelColor(j, 0, 250, 20);
}
strip.show();
}

void setRed()
{
strip.setBrightness(20);
for (int j = 0 ; j < NUMPIXELS; j++)
{
strip.setPixelColor(j, 250, 0, 20);
}
strip.show();
}

void greenDots(int number)
{
for (int i = 0 ; i < NUMPIXELS; i++)
{
strip.setPixelColor(i, 0, 0, 0);
}
strip.setBrightness(50);
int s=0;
int z=0;
for (int j = 0 ; j < number; j++)
{
if (((j+1) % 2) == 0) { //even
strip.setPixelColor(j+1+z, 0, 250, 20);
z++;
}
else { //odd
strip.setPixelColor(s, 0, 250, 20);
strip.setPixelColor(s+1, 0, 250, 20);
s= s+3;
}

}
strip.show();
}

void setBlank()
{
strip.setBrightness(10);
for (int j = 0 ; j < NUMPIXELS; j++)
{
strip.setPixelColor(j, 0, 0, 0);
}
strip.show();
}

//VIBE MOTOR

//BUTTON


If I don't comment out the else if/else parts of the loop, the program will run just fine if it's still plugged into the computer. But, as soon as I transfer it to an external power source, it acts as though there is no sketch there at all. When I plug it back into the computer, the arduino IDE doesn't list my usb port as a serial port option, and then re-upload the sketch, it will tell me to press the reset button (which all makes me think that somehow my sketch is getting deleted when unplugged).

If I do comment out. it will run fine no matter how many times I unplug/replug into whatever power sources. Thoughts?
 
WMXZ,
i'm away from the serial monitor a long time ago.
HID is great, with putty. No reconnection needed, all can stay open.
The only issue i have is, that i can't send anything to the teensy with HID (i don't know why, and i did'nt investigate this ..)
 
WMXZ,
i'm away from the serial monitor a long time ago.
HID is great, with putty. No reconnection needed, all can stay open.
The only issue i have is, that i can't send anything to the teensy with HID (i don't know why, and i did'nt investigate this ..)

The above note is only for my testing the DMA Scatter/Gather issue.
In my real application I used first HID and switched then to usb_serial trying to maximize transfer rate.
I now realize the for usb_serial the CPU load is still significant.

I may try HID again and compare performance (speed and CPU load)

Frank, do you have any performance numbers?
 
Status
Not open for further replies.
Back
Top