Software to debug teensy hardware

jonr

Well-known member
I design/build custom circuits, some use teensy modules and some are custom designs based on the same MCU/bootloader. Not surprisingly, there can be yield issues and a few don't work. So I'm looking for quick ways to find the problem. I understand that a JTAG boundary scan is the standard, but with teensy modules, this isn't an option (no JTAG access). So I started looking for something similar. I found that I can tell a lot about what is or isn't connected to a pin by looking at how long it takes to change state. For example, running this code and comparing to a known good circuit will tell me that a pin is/isn't connected to something (even a trace). Also useful to know is if a pin wont pull up or down over any time period. Any thoughts? Other quick ways to find problems (usually soldering)?

Code:
   int x[100];
    pinMode(i, INPUT_PULLUP);
    delay(20);
    int j = 0;
    pinMode(i, INPUT_PULLDOWN);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    x[j++] = digitalReadFast(i);
    for (j = 0; j < 20; ++j) {
        if (x[j] == 0) {
          Serial.printf(" %d ",j);   // how long to change state
          break;
        }
    }
 
Last edited:
The test fixtures we use for testing each Teensy do this by driving all (or almost all) the pins with a shift register. Resistors are used between the shift register outputs and Teensy pins. Some have 1K resistors, others have 470 ohms. The idea is if there's a short between pins, you want to limit the current to a safe amount so the shift register isn't damaged.

The Teensy being tested is loaded with a very simple program which reads all the pins and makes that data available to the tester (exactly how varies among the various models). Another Teensy runs the test by shifting out bit patterns. Each pin is driven low with all the other pins high, and driven high with all the other pins low. For each pattern, the tester reads the data from the Teensy being tested.

This approach of using another Teensy to run the test might be more complicated that you want. But it works very well. Having done this many times, I'd recommend keeping the code you load onto the hardware under test as simple as possible. Sending the pin state by a serial pin works well, especially if you ASCII encode the data so you can also send a unique byte to start and end each frame of data. You can have it just transmit continuously and design the tester to discard any partial message, or you can have the loaded program wait for a pulse or incoming byte to cause it to read all the pins and send the message. Either way is fine, if you resist the urge to add more complexity than needed.
 
Thanks, that's a good idea to look for shorts.

On a T4, this code can detect whether or not a pin has < 1 inch of wire connected to it.

Code:
for (register int i = 0; i <= 33; ++i) {

    Serial.printf("%d - ", i);

    pinMode(i, INPUT_PULLUP);
    delay(2);
    if (digitalReadFast(i) == 1)
      Serial.printf("up ");
    else
      Serial.printf("xx ");

    // check time to change state - might normalize to pin 1
    noInterrupts();
    ARM_DEMCR |= ARM_DEMCR_TRCENA;
    ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
    uint32_t cycles = ARM_DWT_CYCCNT;

    pinMode(i, INPUT_PULLDOWN);

    for (int j; i < 2000; ++j) {
      if (digitalReadFast(i) == 0) break;
      if (digitalReadFast(i) == 0) break;
      if (digitalReadFast(i) == 0) break;
    }

    interrupts();
    Serial.printf("%d ", ARM_DWT_CYCCNT - cycles);

    delay(20);
    if (digitalReadFast(i) == 0)
      Serial.printf(" down");
    Serial.println("");
}
 
I tried it and variations in "time-to-change" also detects shorts to another pin, even with no change to the length of the connected wire. Since both pins change timing, which input pin it is shorted to is usually clear (ground or supply show up as as failure to change).

It's looking like time-to-change compared to a known good board is a simple but effective screening tool for board problems.
 
Last edited:
For what it is worth, a sketch that I often use to check out hardware is a sketch that @defragster and myself kept adding different things to.

You can alternate between either it setting all IO pins to PULL_UP or PULL_DOWN and then cycles through seeing if a pin is in the opposite state, if so it prints out that pin has changed... So it is good for testing which pin is what. It also tells you when multiple pins changed at same time which may indicate an issue.

It also has some simple tests for again checking for shorts. Like it maybe sets all of the pins in PULL_DOWN and then it changes one pin at a time to OUTPUT and HIGH and see if any other pins change state.

Again nothing magical, but for example it did help with testing T4 when trying to solder on SDCARD adapters to find out if I screwed up and shorted something out or if one or more pins were not properly connected (by probing the pins in the actual SDCard connector or breakout board).

Code:
void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 4000 );
  Serial.println("Compile Time:: " __FILE__ " " __DATE__ " " __TIME__);
  Serial.printf("Num Digital Pins: %d\n", NUM_DIGITAL_PINS);

  testForShorts();
  
}

uint32_t cnt = 0;
void loop() {
  cnt++;
    allPinTest( cnt );
}

uint32_t pinLast[NUM_DIGITAL_PINS];
void allPinTest( uint32_t cnt ) {
  uint32_t ii, SET;
  Serial.print("PULLDOWN Start Vals:\n  ");
  SET = 0;
  Serial.print("PULLDOWN :: TEST to 3.3V\n  ");
  for ( ii = 0; ii < NUM_DIGITAL_PINS; ii++) {
    pinMode( ii, INPUT_PULLDOWN );
    delayMicroseconds( 5 );
    pinLast[ii] = digitalReadFast( ii );
    if (pinLast[ii]) {
      Serial.print("\nd#=");
      Serial.print( ii );
      Serial.print( " val=" );
    }
    Serial.print( pinLast[ii] );
    Serial.print(',');
  }
  Serial.println();
  Serial.println();
  while ( 1 ) {
    uint32_t jj, dd = 0, cc = 0, ee=4;
    cc = 0;
    for ( ii = 0; ii < NUM_DIGITAL_PINS; ii++) {
      jj = digitalReadFast( ii );
      if ( jj != pinLast[ii] ) {
        dd = 1;
        cc++;
        pinLast[ii] = jj;
        Serial.print("d#=");
        Serial.print( ii );
        if ( pinLast[ii] ) Serial.print( "\t" );
        Serial.print( " val=" );
        Serial.print( pinLast[ii] );
        Serial.print(',');
      }
      if ( cc > 1 && ee ) {
        Serial.println(">>> MULTI CHANGE !!");
        ee--;
      }
      if ( Serial.available() ) {
        while ( Serial.available() ) Serial.read();
        if ( 0 == SET ) {
          SET = 1;
          Serial.print("PULLUP :: TEST TO GND\n  ");
        }
        else {
          SET = 0;
          Serial.print("PULLDOWN :: TEST to 3.3V\n  ");
        }
        for ( ii = 0; ii < NUM_DIGITAL_PINS; ii++) {
          if ( 0 == SET )
            pinMode( ii, INPUT_PULLDOWN );
          else
            pinMode( ii, INPUT_PULLUP );
          delayMicroseconds( 20 );
          pinLast[ii] = digitalReadFast( ii );
          if (SET != pinLast[ii]) {
            Serial.print("d#=");
            Serial.print( ii );
            Serial.print( " val=" );
            Serial.println( pinLast[ii] );
          }
        }
      }
    }
    if ( dd ) {
      dd = 0;
      Serial.println();
      delay( 50 );
    }
  }
}

void testForShorts() {
  uint32_t ii;
  Serial.print("Quick Test for Shorts to adjacent pin");
  Serial.println("First pull pins down and see if the next one follows");
  for ( ii = 0; ii < NUM_DIGITAL_PINS-1; ii++) {
    pinMode( ii+1, INPUT_PULLDOWN );
    pinMode( ii, OUTPUT);
    digitalWrite(ii, HIGH);
    delayMicroseconds( 5 );
    if (digitalRead(ii+1)) {
      Serial.printf("%d:%d ", ii, ii+1);
    }
  }
  Serial.println("\n Now try Pull up and see if setting low follow");
  for ( ii = 0; ii < NUM_DIGITAL_PINS-1; ii++) {
    pinMode( ii+1, INPUT_PULLUP );
    pinMode( ii, OUTPUT);
    digitalWrite(ii, LOW);
    delayMicroseconds( 5 );
    if (!digitalRead(ii+1)) {
      Serial.printf("%d:%d ", ii, ii+1);
    }
  }
  Serial.println();  
}
 
Back
Top