Teensy 4.0 Randomly Bricked - WTF?

Power_Broker

Well-known member
I've been working on a project with everything going well, (plenty of sketch updates and successful uploads to the T4.0) and this last sketch update bricked my Teensy. Now whenever I try to reupload a sketch I just get
No Teensy boards were found on any USB ports of your computer. Please press the PROGRAM MODE BUTTON on your Teensy to upload your sketch.
Looking in the device manager (Windows 10) I see the teensy is listed under "Universal Serial Bus Controllers" with the name
Unknown USB Device (Device Descriptor Request Failed)

I literally just tried to upload a valid sketch and it bricks itself? WTF? Anyone know how to fix this?

Here's the code I tried uploading:

Code:
#include "Adafruit_AMG88xx.h"
#include "TeensyTimerTool.h"


using namespace TeensyTimerTool;


#define PIN_1   2
#define PIN_2   3
#define PIN_3   4
#define PIN_4   5
#define PIN_5   6
#define PIN_6   7
#define PIN_7   8
#define PIN_8   9
#define PIN_9  10
#define PIN_10 11
#define PIN_11 12
#define PIN_12 17

#define RESOLUTION 12
#define VDD 3.3
#define V_MAX_OUT 1.0
#define VTD(r) (int)(((pow(2, RESOLUTION) - 1) * r) / VDD)
#define MAX_VAL VTD(V_MAX_OUT)

#define HORIZ 8
#define VERT  8

#define LSL_DURATION_US  26.0  // 27.3  us
#define LSH_DURATION_US  5.0   // 4.7   us
#define SSL_DURATION_US  1.5   // 2.35  us
#define SSH_DURATION_US  29.65 // 29.65 us
#define SYNC_DURATION_US 3.8   // 4.7   us
#define BACKPORTCH_DURATION_US   5.65 // 5.65 us
#define ACTIVE_VIDEO_DURATION_US 52.0 // 52   us
#define FRONTPORTCH_DURATION_US  1.65 // 1.65 us

#define SYNC  0
#define BLANK VTD(0.8)
#define BLACK BLANK
#define WHITE VTD(2.8)


Adafruit_AMG88xx amg;
OneShotTimer timer1(TCK);


float pixels[8 * 8];
int data[HORIZ][VERT];


enum STATE
{
  longsync_low,   // 27.3  us
  longsync_high,  // 4.7   us
  shortsync_low,  // 2.35  us
  shortsync_high, // 29.65 us
  sync,           // 4.7   us
  backportch,     // 5.65  us
  activevideo,    // 52    us
  frontportch     // 1.65  us
};
STATE state = longsync_low;


void updatePin(const int& val, const int& shift, const int& pin)
{
  if (bitRead(val, shift))
    digitalWriteFast(pin, HIGH);
  else
    digitalWriteFast(pin, LOW);
}


void dacOut(const int& val)
{
  updatePin(val, 0,  PIN_1);
  updatePin(val, 1,  PIN_2);
  updatePin(val, 2,  PIN_3);
  updatePin(val, 3,  PIN_4);
  updatePin(val, 4,  PIN_5);
  updatePin(val, 5,  PIN_6);
  updatePin(val, 6,  PIN_7);
  updatePin(val, 7,  PIN_8);
  updatePin(val, 8,  PIN_9);
  updatePin(val, 9,  PIN_10);
  updatePin(val, 10, PIN_11);
  updatePin(val, 11, PIN_12);
}


void processVideo()
{
  static bool beginning = true;
  static int longsync_count = 0;
  static int shortsync_count = 0;
  static int line_count = 0;

  static int row = 0;
  static int col = 0;

  static bool incRow = true;
  
  
  if (state == longsync_low)
  {
    state = longsync_high;

    timer1.trigger(LSL_DURATION_US);
    dacOut(SYNC);
  }
  
  else if (state == longsync_high)
  {
    longsync_count++;

    if (longsync_count < 5)
      state = longsync_low;
    else
    {
      state = shortsync_low;
      longsync_count = 0;
    }
    
    timer1.trigger(LSH_DURATION_US);
    dacOut(BLANK);
  }
  
  else if (state == shortsync_low)
  {
    state = shortsync_high;
    
    timer1.trigger(SSL_DURATION_US);
    dacOut(SYNC);
  }
  
  else if (state == shortsync_high)
  {
    shortsync_count++;
    
    if (beginning)
    {
      if (shortsync_count < 5)
        state = shortsync_low;
      else
      {
        state = sync;
        shortsync_count = 0;
        beginning = false;
      }
    }
    else
    {
      if (shortsync_count < 6)
        state = shortsync_low;
      else
      {
        state = longsync_low;
        shortsync_count = 0;
        beginning = true;
      }
    }
    
    timer1.trigger(SSH_DURATION_US);
    dacOut(BLANK);
  }
  
  else if (state == sync)
  {
    state = backportch;
    
    timer1.trigger(SYNC_DURATION_US);
    dacOut(SYNC);
  }
  
  else if (state == backportch)
  {
    state = activevideo;
    
    timer1.trigger(BACKPORTCH_DURATION_US);
    dacOut(BLANK);
  }
  
  else if (state == activevideo)
  {
    timer1.trigger((ACTIVE_VIDEO_DURATION_US / HORIZ) - 0.5);
    dacOut(data[row][col]);

    col++;

    if (col < HORIZ)
      state = activevideo;
    else
    {
      state = frontportch;
      col = 0;
    }

    if (!((line_count + 1) % (304 / VERT)) && incRow)
    {
      row++;
      incRow = false;
    }
  }
  
  else if (state == frontportch)
  {
    line_count++;

    incRow = true;

    if (line_count < 304)
      state = sync;
    else
    {
      state = shortsync_low;
      line_count = 0;
      row = 0;
    }
    
    timer1.trigger(FRONTPORTCH_DURATION_US);
    dacOut(BLANK);
  }
}


void setup()
{
  Serial.begin(115200);
  
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWriteFast(LED_BUILTIN, HIGH);

  pinMode(PIN_1,  OUTPUT);
  pinMode(PIN_2,  OUTPUT);
  pinMode(PIN_3,  OUTPUT);
  pinMode(PIN_4,  OUTPUT);
  pinMode(PIN_5,  OUTPUT);
  pinMode(PIN_6,  OUTPUT);
  pinMode(PIN_7,  OUTPUT);
  pinMode(PIN_8,  OUTPUT);
  pinMode(PIN_9,  OUTPUT);
  pinMode(PIN_10, OUTPUT);
  pinMode(PIN_11, OUTPUT);
  pinMode(PIN_12, OUTPUT);

  dacOut(SYNC);
  timer1.begin(processVideo);
  timer1.trigger(100);
}


void loop()
{
  int j = 0;
  
  amg.readPixels(pixels);

  for (int i=0; i<HORIZ; i++)
  {
    for (int k=0; k<VERT; k++)
    {
      data[i][k] = map(pixels[j], 20, 28, BLACK, WHITE);
      j++;
    }
  }
}
 
I haven’t read your code, but the program has probably crashed or is in some infinite loop or something. Simply load up one of the simple examples (eg. Blink), and when the Teensy Loader program says it’s attempting to erase/upload, press the Teensy’s button and things should continue.

There’s also a way to restore the Teensy with the program button. It erases everything and loads a simple blink program. I’m having trouble finding instructions to do that. Can anyone chime in here with the pjrc.com link to the procedure?

Update: Found the link. Look for “Memory Wipe” here: https://www.pjrc.com/store/teensy40.html

Note that it’s very rare you’ll need to do this. Pressing the program button when the board is hung and then attempting to upload a new program just about always works for me. I’ve crashed my Teensy plenty. :)
 
Which version of Teensyduino are you using? In Arduino, click Help > About to check.

Version 1.54 added a default fault handler which tries to keep USB responsive and automatically reboot 8 seconds after a crash caused by all sorts of fault conditions. It also adds a feature called CrashReport so you can get info about what when wrong on the prior run when it reboots. Maybe those features can help?
 
Simply load up one of the simple examples (eg. Blink), and when the Teensy Loader program says it’s attempting to erase/upload, press the Teensy’s button and things should continue.

I've tried that, but unfortunately it doesn't work.

Which version of Teensyduino are you using? In Arduino, click Help > About to check.

My versions are Arduino 1.8.13 and Teensyduino 1.53. Should I uninstall Teensyduino to the latest version? Will this help since Windows can't even recognize my MCU?
 
Another thing. When I press the program mode button manually to force upload, after I let it go, a red LED lights by the USB receptacle and stays lit. If I completely power cycle by unplugging and replugging in the USB entirely, that red LED doesn't light up and the previous sketch boots up (I can tell by the LED on pin 13).
 
This is incredible - After switching USB cables it worked. I'm glad it's fixed, but the original USB cable that things errored with was working perfectly fine up until now...
 
Back
Top