Program Teensy from another Teensy?

David M. Kramer

New member
We are developing an application using Teensy 3.2 that will be deployed in the field. In some cases it will be difficult to bring a full sized computer out to the field, so we need another method to upload new firmware (Teensy code). Is it possible to use another Teensy or another microprocessor to send the code, essentially replacing the computer?

I tried searching for this type of application but did not find anything relevant.

By the way, the current firmware does not fill the entire memory so it should be possible to store in one Teensy device the core program and another that sends the data to the target Teensy.

Thanks for any thoughts.

Dave
 
We are developing an application using Teensy 3.2 that will be deployed in the field. In some cases it will be difficult to bring a full sized computer out to the field, so we need another method to upload new firmware (Teensy code). Is it possible to use another Teensy or another microprocessor to send the code, essentially replacing the computer?

I tried searching for this type of application but did not find anything relevant.

By the way, the current firmware does not fill the entire memory so it should be possible to store in one Teensy device the core program and another that sends the data to the target Teensy.

Thanks for any thoughts.

Dave

I've seen various threads about this over the years, but I don't recall which ones worked.

One thought that occurs to me to use to use a Raspberry Pi Zero W, with the Raspberry Pi OS on a SD card, and the Teensy hooked up to the Pi Zero W via USB. The Pi zero W supports wifi, and can run headless. You can run the command line downloader on the Pi, and download HEX files to the pi, and from there upload the Teensy. If you need to run from a wired ethernet instead of wifi, you could go up a regular Pi and/or include USB hub and ethernet for the Pi Zero. In theory you could even do the iDE and build a teensy app from the Pi Zero W, but it would likely take a looong time. However, downloading the hex file to the Teensy is doable.

One downside is you can generally only order one at a time (or a few at a time at Microcenter at a higher price per unit than getting a single Pi Zero W). At times in the past, there have been periods where you couldn't get any. So if you need to order lots of them you probably need to go up to the Raspbery Pi B2/3.
 
i,
I wouldn't want to brick one of my teensy so I would like to know if this program works for micro mod teesny?
As they are very close to teensy 4.0 and 4.1 it could work.
 
i,
I wouldn't want to brick one of my teensy so I would like to know if this program works for micro mod teesny?
As they are very close to teensy 4.0 and 4.1 it could work.

Not sure which program is "this program"?

But nothing should brick a Teensy.

Though for whatever "this program" is it would need to be built like that working for a T_4.x - but have been made for : #ifdef ARDUINO_TEENSY_MICROMOD
 
I don't see a reference for the teensy micro mod in this last one. The last card that appears to be supported is teensy 4.0

Here is an excerpt:

case 0x1B: filename = "TEENSY20.HEX"; return true;
case 0x1C: filename = "TEENSYPP.HEX"; return true;
case 0x1D: filename = "TEENSY30.HEX"; return true;
case 0x1E: filename = "TEENSY32.HEX"; return true; // T3.1
case 0x1F: filename = "TEENSY35.HEX"; return true;
case 0x20: filename = "TEENSYLC.HEX"; return true;
case 0x21: filename = "TEENSY32.HEX"; return true;
case 0x22: filename = "TEENSY36.HEX"; return true;
case 0x24: filename = "TEENSY40.HEX"; return true;
 
I don't see a reference for the teensy micro mod in this last one. The last card that appears to be supported is teensy 4.0

Here is an excerpt:

case 0x1B: filename = "TEENSY20.HEX"; return true;
...

That's why the #define was noted in the last sentence - if that was the program of interest as it makes no provisions for Teensy_MicroMod, and no precompiled HEX is provided.
 
Creating a HEX precompiler is not the most complicated, I have already done it. It's sending it from one teensy to another that worries me.
I'll take some tests and see what I can do
 
Ok,
My first problem is when I plug a teensy 4.0 to a 4.1 I see the 4.0 in the test USBHost_t36> Serial, but I don't see the micor mod, even when I press the reprog button.

And in the USB Tester program, it doesn't see any device.
if (!device) return 0;
 
For the detection problem it was due to the USBSerial_BigBuffer. now the teensy 4.1 detect the teensy micromod well in the test USBHost_t36> Serial.
Now i work on USB Tester program.
 
I continue the tests and investigations because I really really really need this program.

I diagnosed something strange. Here is what is happening with the USB_Tester and/or HIDDDevicesinfo programs with a teensy 4.1 as main board.

teensy 4.0 on run mod plug on 4.1 -> Device detect
teensy 4.0 on program mod plug on 4.1 -> Device detect

teensy 4.1 on run mod plug on 4.1 -> no Device detect
teensy 4.1 on program mod plug on 4.1 -> no Device detect

teensy micromod on run mod plug on 4.1 -> Device detect
teensy micromod on program mod plug on 4.1 -> no Device detect

I do not know what is the reason for the problem and I don't think I have sufficient knowledge to be able to go further :/ .
Please help !!!
 
Not sure how to read p!16 for sure?

Was this list extended for T_4.1 ( 0x25 ) and T_MM ( 0x26 ) recognition?
Code:
...
case 0x22: filename = "TEENSY36.HEX"; return true;
case 0x24: filename = "TEENSY40.HEX"; return true;
 
Thanks for your help, but the detection of the model is not the problem,

Here is the code to detect the model

while (timeout < 2000) {
uint8_t id = bootloader.id();
Serial.print("bootloader.id = ");
Serial.println(id);
switch (id) {
case 0x00: break;
case 0x1B: filename = "TEENSY20.HEX"; return true;
case 0x1C: filename = "TEENSYPP.HEX"; return true;
case 0x1D: filename = "TEENSY30.HEX"; return true;
case 0x1E: filename = "TEENSY32.HEX"; return true; // T3.1
case 0x1F: filename = "TEENSY35.HEX"; return true;
case 0x20: filename = "TEENSYLC.HEX"; return true;
case 0x21: filename = "TEENSY32.HEX"; return true;
case 0x22: filename = "TEENSY36.HEX"; return true;
case 0x24: filename = "TEENSY40.HEX"; return true;
default:
Serial.printf("Unknown model ID = 0x%02X\n", id);
return false; // unknown
}

Here is bootloader.id () :

uint8_t TeensyBootloader::id()
{
if (!device){
Serial.println("No device");
return 0;
}
if (state == 0) return 0;
volatile uint8_t *idbyte = hiddesc + 4;
//return hiddesc[4];
return *idbyte;
}

And the problem is that device is not detected.
"No device" is displayed in the terminal, and 0 is returned. When I plug in a teensy 4.0, a correct value is return.

I can force use another file that I put on an SD card and compile for the Micromod, but the rest of the code doesn't work because the card is not detected.

And I don't know where in the code it is the detection of the card and the modification of the variable "device".
 
Not sure what code is in use for what purpose ...

But those ID's not being recognized somewhere in the code to ID the Teensy Type where T_4.1 ( 0x25 ) and T_MM ( 0x26 ) are not expected could be behind the failure.
 
If there is a problem that does not come from this part of the code, but I can't figure out where exactly this problem is coming from.
I don't know where the "device" variable is changed.
I'm afraid that the problem comes directly from the library "USBHost_t36.h".
As I have the same diagnosis with the HID Devices info code.

On the other hand with the example "USBHost_t36> Serial" I have the same diagnosis when I use the command USBSerial userial (myusb);. But by replacing it with USB Serial BigBuffer serial (myusb); everything is detected correctly.
Maybe there is a buffer problem on the HID Devices info and USB Tester program code, but I don't know how to solve it
 
Hi,

I have uncommented the line #define USBHOST_PRINT_DEBUG in the library USBhost_t36.h

From what I understood, void USBHost :: enumeration (const Transfer_t * transfer) is not calling With a Micromod teensy in programming mode, and I don't know why.
On the other hand, this function is called with the same card in run mode or a teensy 4.0 regardless of its operating mode.

I don't know where in the code and under what condition this function is apper

I don't know if I'm on the right track but that seems to me to be the problem.
I unfortunately think that only Paul Stoffregen can help me, because he is the one who created the USBhost_t36 library and the USB Tester program, and they are very complex.

But if someone else has the solution, I welcome them with open arms ;)
 
Not ever looked - but anything with #ifdef T_4.1 especially if different .vs. T_3.6, may need to include T_MM?
 
Hi,
But if someone else has the solution, I welcome them with open arms ;)

@Armadafg:

I can't offer a specific "solution" but you should make sure that you are using the latest Teensyduino 1.55, just to make sure that you have the latest core support (including T_MM). Hope that helps . . .

Mark J Culross
KD5RXT
 
Ok, here's my attempt to offer a "solution".

First, I set this up on my desk with a Teensy 3.6 to run the USB_Tester code and a MicroMod Teensy on Sparkfun's ML Carrier Board connected to the Teensy 3.6 USB host port.

image.jpg

The Teensy 3.6 had an audio shield connected during this test, but it wasn't used in any way. It just happened to be plugged into the board I used the hold the Teensy 3.6 still (otherwise it flops around if the cables move even slightly).

I edited the code in setup() to use the built in SD card, just commenting out the line for CS pin 10 and uncommenting the line for BUILTIN_SDCARD.

Code:
	bool r = SD.begin(BUILTIN_SDCARD);
	//bool r = SD.begin(10);

I copied all the HEX files from the "extras" folder onto a 32GB SD card and put it into the socket. (as you can see in the screenshot below, I didn't not erase the card - it had 6 other files before this test which don't matter)

When I run the program it prints the list of files found on the SD card. Then when I press the "Boot" button the ML Carrier Board, it endlessly prints 5 lines about detecting the device and "Unknown model ID = 0x26".

screenshot1.png

I'm guessing this is the same problem you saw too? So far your questions do not tend to show screenshots or exact copies of the actual messages you saw. In addition to offering you a solution, I'm hoping you can see from this message how screenshots are essential. Please, if this message does not solve every problem, try to show exactly what happened. A screenshot or exact copy-paste of the text is only a small effort.

Then to solve the problem, I edited the identify_teensy_model(). I just copied the line for Teensy 4.0 and changed the number to 0x26.

Code:
bool identify_teensy_model(const char * &filename)
{
	Serial.println("Identify Teensy Model");
	elapsedMillis timeout = 0;
	while (timeout < 250) {
		uint8_t id = bootloader.id();
		switch (id) {
			case 0x00: break;
			case 0x1B: filename = "TEENSY20.HEX"; return true;
			case 0x1C: filename = "TEENSYPP.HEX"; return true;
			case 0x1D: filename = "TEENSY30.HEX"; return true;
			case 0x1E: filename = "TEENSY32.HEX"; return true; // T3.1
			case 0x1F: filename = "TEENSY35.HEX"; return true;
			case 0x20: filename = "TEENSYLC.HEX"; return true;
			case 0x21: filename = "TEENSY32.HEX"; return true;
			case 0x22: filename = "TEENSY36.HEX"; return true;
			case 0x24: filename = "TEENSY40.HEX"; return true;
                        [B][COLOR="#006400"]case 0x26: filename = "TEENSY40.HEX"; return true;[/COLOR][/B]
			default:
				Serial.printf("Unknown model ID = 0x%02X\n", id);
				return false; // unknown
		}
	}
	return false;
}

This will cause the Teensy 3.6 to program TEENSY40.HEX into the MicroMod's flash memory. Not ideal, but the code is simple and doesn't use any MicroMod specific pins, so it will work. A better approach would be to rebuild the HEX file from the source code and put it on the SD card, but hopefully this is enough to illustrate the solution you seek?

This this 1 line added to the program, here's the result I see when I upload and then press the Boot button the ML Carrier board.

screenshot2.jpg


You can see in the screenshot, it does indeed program the TEENSY40.HEX file onto the MicroMod board. Then it tries to do the various tests which depend on analog circuitry to measure the USB cable current. Those fail because this was done with only a Teensy 3.6 having none of that other hardware connected.

But I can confirm the MicroMod board is indeed blinking its blue LED after running this. Previously it was written with code to talk to the ILI9341 display. So this did reprogram the MicroMod board with the TEENSY40.HEX file.

I changed exactly 3 lines.

1: commented out the SD.begin for pin 10
2: uncommented SD.begin for BUILTIN_SDCARD
3: added case 0x26: filename = "TEENSY40.HEX"; return true; in identify_teensy_model()

That is it. As you can see in the these screenshots this does work. You're going to have to trust me on the blue LED blinking - not set up right now to do a timed photo or video to show it.... and so many other things needing my attention. But I did take the time to write this message with a photo of the hardware setup, screenshots of the serial monitor, and the exact edits I made to the program. Hopefully that is enough to solve the problem?

Just for completeness, here is the full modified USB_Tester.ino file.

Code:
// AREF = 2.5V reference
// 24 = Fail LED
// 25 = Pass LED
// 2 = Power enable, high=on
// 3 = Overcurrent detect, low=overcurrent, open collector
// A10 = Amplifier signal
// A11 = Amplifier reference

// build with Teensyduino 1.41-beta or later

#include <SD.h>
#include <Wire.h>
#include <USBHost_t36.h>
#include "bootloader.h"
#include "ihex.h"

USBHost usb;
USBHub hub1(usb);
TeensyBootloader bootloader(usb);
TeensyRawhid rawhid(usb);

#if F_CPU != 120000000
#error "Please compile with Tools > CPU set to 120 MHz"
#endif

const uint8_t unused_pins[] = {0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
	14, 15, 16, 17, 18, 19, 20, /*21,*/ 22, 26, 27, 28, 29, 30, 31, 32,
	33, 34, 35, 36, 37, 38, 39};

uint8_t usbdata[1088];
uint8_t hexdata[1024];
uint8_t serdata[64];
uint32_t priorsercount=0;
uint8_t priorserdata[72*999];


bool virgin_teensy2=false;
elapsedMillis testElapsedTime;

void setup()
{
	pinMode(2, OUTPUT);
	pinMode(3, INPUT_PULLUP);
	pinMode(8, OUTPUT);
	pinMode(9, OUTPUT);
	pinMode(24, OUTPUT);
	pinMode(25, OUTPUT);
	digitalWrite(5, LOW);
	digitalWrite(24, LOW);
	digitalWrite(25, LOW);
	analogWrite(A21, 0);
	analogWrite(A22, 0);
	for (unsigned int i=0; i < sizeof(unused_pins); i++) {
		pinMode(unused_pins[i], OUTPUT);
		digitalWrite(unused_pins[i], LOW);
	}
	analogReadResolution(16);
	analogReadAveraging(32);
	analogReference(EXTERNAL);
	digitalWrite(8, LOW);
	digitalWrite(9, LOW);
	delay(100);
	bool r = SD.begin(BUILTIN_SDCARD);
	//bool r = SD.begin(10);
	while (!Serial && millis() < 1500) ; // wait
	ht16k33_config();
	Serial.println("USB Tester, files present:");
	if (!r) sd_error();
	File rootdir = SD.open("/");
	if (!rootdir) sd_error();
	while (1) {
		File f = rootdir.openNextFile();
		if (!f) break;
		Serial.print("  ");
		Serial.println(f.name());
		f.close();
	}
	rootdir.close();
	digitalWrite(2, HIGH); // power on to USB
	usb.begin();
	delay(50);
}



float read_current(void)
{
	// returns current in mA
	// anything below 2mA should be considered zero
	//  new hardware has more accurate 1N190A1 current sense amp, lower values should be better

	float range = 200.0;
	int a10=0, a11=0;
	//int a7=0;
	for (int i=0; i<10; i++) {
		a10 += analogRead(A10);
		a11 += analogRead(A11);
		//a7 += analogRead(A7);
	}
	//Serial.printf("a10 = %d\n", a10 / 10);
	//Serial.printf("a11 = %d\n", a11 / 10);
	//Serial.printf("a7  = %d\n", a7 / 10);
	return (float)(a10 - a11) * range * (1.0 / 65536.0 / 10.0);
// A10 = Amplifier signal
// A11 = Amplifier reference
}


// wait for bootloader to appear (requires user to press button)
bool wait_for_bootloader()
{
	int undercurrent=0;

	while (undercurrent < 15) {
		if (bootloader) {
			return true;
		}
		float mA = read_current();
		if (mA < 0.2) {
			undercurrent++;
			Serial.printf("  undercurrent #%d, mA = %.2f\n", undercurrent, mA);
		} else {
			undercurrent = 0;
		}
	}
	return false;
}

bool wait_for_not_bootloader()
{
	int undercurrent=0;

	while (undercurrent < 15) {
		if (!bootloader) {
			return true;
		}
		float mA = read_current();
		if (mA < 0.2) {
			undercurrent++;
			Serial.printf("  undercurrent #%d, mA = %.2f\n", undercurrent, mA);
		} else {
			undercurrent = 0;
		}
	}
	return false;
}

bool identify_teensy_model(const char * &filename)
{
	Serial.println("Identify Teensy Model");
	elapsedMillis timeout = 0;
	while (timeout < 250) {
		uint8_t id = bootloader.id();
		switch (id) {
			case 0x00: break;
			case 0x1B: filename = "TEENSY20.HEX"; return true;
			case 0x1C: filename = "TEENSYPP.HEX"; return true;
			case 0x1D: filename = "TEENSY30.HEX"; return true;
			case 0x1E: filename = "TEENSY32.HEX"; return true; // T3.1
			case 0x1F: filename = "TEENSY35.HEX"; return true;
			case 0x20: filename = "TEENSYLC.HEX"; return true;
			case 0x21: filename = "TEENSY32.HEX"; return true;
			case 0x22: filename = "TEENSY36.HEX"; return true;
			case 0x24: filename = "TEENSY40.HEX"; return true;
      case 0x26: filename = "TEENSY40.HEX"; return true;
			default:
				Serial.printf("Unknown model ID = 0x%02X\n", id);
				return false; // unknown
		}
	}
	return false;
}

// program blink firmware
bool program_teensy(const char *filename)
{
	Serial.print("Program Teensy with ");
	if (!bootloader || bootloader.status() != 1) {
		Serial.println(" error, not running bootloader");
		return false;
	}
	Serial.println(filename);
	bool is_teensy20 = false;
	bool is_teensypp = false;
	uint32_t blocksize = 1024;
	uint32_t writesize;
	if (strcmp(filename, "TEENSY20.HEX") == 0) {
		is_teensy20 = true;
		blocksize = 128;
	}
	if (strcmp(filename, "TEENSYPP.HEX") == 0) {
		is_teensypp = true;
		blocksize = 256;
	}
	if (strcmp(filename, "TEENSYLC.HEX") == 0) {
		blocksize = 512;
	}

	if (!ihex_open(filename)) {
		Serial.println(" error opening file from SD card");
		return false;
	}
	memset(usbdata, 0, sizeof(usbdata));
	uint32_t address=0;
	// pre-read the first block
	bool ok = ihex_read(address, hexdata, blocksize);
	if (!ok) Serial.printf("Error reading data from %s\n", filename);
	bool last = false;
	bool complete = false;
	bool first_write = true;
	while (ok && !complete) {
		Serial.printf("hex address %x\n", address);
		//for (uint32_t i=0; i < 1024; i++) {
			//Serial.printf(" %02X", mydata[i+64]);
			//if ((i & 15) == 15) Serial.println();
		//}
		// send the data to USB
		if (is_teensy20) {
			usbdata[0] = address;
			usbdata[1] = address >> 8;
			memcpy(usbdata+2, hexdata, blocksize);
			writesize = blocksize + 2;
			bootloader.write(usbdata, writesize);
		} else if (is_teensypp) {
			usbdata[0] = address >> 8;
			usbdata[1] = address >> 16;
			memcpy(usbdata + 2, hexdata, blocksize);
			writesize = blocksize + 2;
			bootloader.write(usbdata, writesize);
		} else {
			usbdata[0] = address;
			usbdata[1] = address >> 8;
			usbdata[2] = address >> 16;
			memset(usbdata + 3, 0, 61);
			memcpy(usbdata + 64, hexdata, blocksize);
			writesize = blocksize + 64;
			bootloader.write(usbdata, writesize);
		}
		Serial.print(".");
		// read the next block from the file while USB sends
		if (last) {
			complete = true;
		} else {
			if (ihex_read(address + blocksize, hexdata, blocksize)) {
				if (ihex_end()) {
					//Serial.print(" end of file");
					last = true;
				}
			} else {
				Serial.print(" error reading file");
				ok = false;
			}
		}
		// wait for USB write
		elapsedMillis timeout = 0;
		uint32_t maxtime = 1000;
		if (first_write) {
			maxtime = 5000;
			first_write = false;
		}
		while (ok) {
			int status;
			do {
				status = bootloader.status();
				if (timeout > maxtime) {
					ok = false; // timeout
					break;
				}
			} while (status == 3);
			if (status == 1) {
				// successful write
				break;
			} else if (status == 2) { // teensy is busy
				if (timeout <= maxtime) {
					// keep retring every 10 ms
					delay(10);
					bootloader.write(usbdata, writesize);
				} else {
					// give up if too long
					ok = false;
				}
			} else {
				// USB disconnected, or other error
				ok = false;
			}
		}
		address += blocksize;
	}
	ihex_close();
	Serial.println();
	return ok;
}

// send reboot command, wait for bootloader disconnect
bool reboot_teensy(const char *filename)
{
	Serial.println("Reboot Teensy");
	if (!bootloader || bootloader.status() != 1) {
		Serial.println(" error, not running bootloader");
		return false;
	}
	uint32_t writesize;
	if (strcmp(filename, "TEENSY20.HEX") == 0) {
		writesize = 128 + 2;
	} else if (strcmp(filename, "TEENSYPP.HEX") == 0) {
		writesize = 256 + 2;
	} else if (strcmp(filename, "TEENSYLC.HEX") == 0) {
		writesize = 512 + 64;
	} else {
		writesize = 1024 + 64;
	}
	usbdata[0] = 0xFF;
	usbdata[1] = 0xFF;
	usbdata[2] = 0xFF;
	memset(usbdata + 3, 0, writesize - 3);

	bootloader.write(usbdata, writesize);
	elapsedMillis timeout = 0;
	while (1) {
		int status;
		do {
			status = bootloader.status();
			if (timeout > 500) return false;
		} while (status == 3);
		if (status == 1 || status == 0) {
			break;
		} else if (status == 2) { // teensy is busy
			if (timeout <= 500) {
				// keep retring every 10 ms
				delay(10);
				bootloader.write(usbdata, writesize);
			} else {
				// give up if too long
				return false;
			}
		} else {
			return false;
		}
	}
	while (timeout < 500) {
		if (!bootloader) return true;
	}
	Serial.println(" timeout waiting for bootloader offline");
	return false;
}

// wait for rawhid to appear
bool wait_for_rawhid()
{
	Serial.println("Wait for RawHID Device");
	elapsedMillis timeout = 0;
	while (timeout < 700) {
		if (rawhid) return true;
	}
	Serial.println(" timeout waiting for rawhid");
	return false;
}

// use rawhid to test LED, turn on/off and measure current
bool test_led()
{
	Serial.println("Test LED");
	if (!rawhid) return false;

	usbdata[0] = 0;
	memset(usbdata + 1, 0, 63);
	rawhid.write(usbdata);
	for (int i=0; i < 50; i++) { read_current(); delay(1); }
	float led_off_mA = read_current();
	Serial.print("  off mA: ");
	Serial.println(led_off_mA);
	usbdata[0] = 1;
	memset(usbdata + 1, 0, 63);
	rawhid.write(usbdata);
	for (int i=0; i < 50; i++) { read_current(); delay(1); }
	float led_on_mA = read_current();
	Serial.print("   on mA: ");
	Serial.println(led_on_mA);
	float diff = led_on_mA - led_off_mA;
	if (diff < 2.0 || diff > 4.0) return false;
	return true;
}

// read serial number and Freescale ID number
bool read_id_bytes()
{
	Serial.println("Read ID Bytes");
	if (!rawhid) return false;
	usbdata[0] = 1;
	usbdata[1] = 0x5A;
	memset(usbdata + 2, 0, 62);
	rawhid.write(usbdata);
	elapsedMillis timeout = 0;
	while (1) {
		if (rawhid.read(serdata)) break;
		if (timeout > 400) return false;
	}
	uint32_t len = serdata[0];
	if (len < 12 || len > 48) return false;
	for (unsigned int i=0; i < len; i++) {
		Serial.print(serdata[i+1], HEX);
		if (i < len-1) Serial.print(",");
	}
	Serial.println();
	return true;
}

char hex(uint32_t n) {
	n &= 15;
	if (n < 10) return '0' + n;
	return 'A' + n - 10;
}

// copy the filename and id bytes to "hexdata" in ascii format
void format_id_bytes(const char *filename)
{
	memset(hexdata, 0, sizeof(hexdata));

	if (search_priorser(filename)) {
		hexdata[0] = 0;
		Serial.println("previously tested, no need to log");
		return;
	}
	strcpy((char *)hexdata, filename);
	int len = strlen(filename);
	int datalen = serdata[0];
	for (int i=0; i < datalen; i++) {
		hexdata[len++] = ',';
		hexdata[len++] = hex(serdata[i+1] >> 4);
		hexdata[len++] = hex(serdata[i+1]);
	}
	hexdata[len++] = 13;
	hexdata[len++] = 10;
	hexdata[len++] = 0;
	Serial.print("log: ");
	Serial.print((char *)hexdata);
	if (priorsercount < 999) {
		uint8_t *p = priorserdata + (priorsercount * 72);
		memcpy(p, filename, 8);
		memcpy(p + 8, serdata, 64);
		priorsercount++;
		sevenseg(priorsercount);
	}
}

//uint8_t serdata[64];
//uint32_t priorsercount=0;
//uint8_t priorserdata[72*999];

bool search_priorser(const char *filename)
{
	if (!filename) return false;
	for (uint32_t i=0; i < priorsercount; i++) {
		const uint8_t *p = priorserdata + (i * 72);
		if (memcmp(p, filename, 8) == 0 && memcmp(p + 8, serdata, 64) == 0) return true;
	}
	return false;
}

void store_id_bytes(const char *filename)
{
	if (!hexdata[0]) return;
	File logfile = SD.open("log.txt", FILE_WRITE);
	if (!logfile) sd_error();
	logfile.write(hexdata, strlen((char *)hexdata));
	logfile.close();
}

// 1 = pass, 0 = fail, -1 = aborted, no usb ever seen
int runtest()
{
	const char *filename;

	virgin_teensy2 = false;
	testElapsedTime = 0;
	if (!wait_for_bootloader()) return -1;
	if (!identify_teensy_model(filename)) return 0;
	if (testElapsedTime < 350 &&
	  (strcmp(filename, "TEENSY20.HEX") == 0 || strcmp(filename, "TEENSYPP.HEX") == 0)) {
		// virgin Teensy 2.0 & Teensy++ 2.0 come up quickly
		// in bootloader mode, without button press.
		Serial.printf("Virgin Teensy2, %u ms\n", (uint32_t)testElapsedTime);
		if (!wait_for_not_bootloader()) return 0;
		Serial.println("  Button pressed");
		if (!wait_for_bootloader()) return 0;
		Serial.println("  Button released");
		if (!identify_teensy_model(filename)) return 0;
	}
	if (!program_teensy(filename)) return 0;
	if (!reboot_teensy(filename)) return 0;
	if (!wait_for_rawhid()) return 0;
	if (!test_led()) return 0;
	if (!read_id_bytes()) return 0;
	format_id_bytes(filename);
	return 1;
}

void loop()
{
	// wait for a device to appear
	float mA = read_current();
	static unsigned int testcount=0;

	if (mA > 0.5 || bootloader || rawhid) {
		Serial.println();
		//uint32_t d, p, t, s;
		//usb.countFree(d, p, t, s);
		//Serial.printf("memory = %d,%d,%d,%d\n", d, p, t, s);
		Serial.print("USB Device Detected, test #");
		Serial.println(++testcount);
		// turn off the LEDs
		digitalWrite(24, LOW);
		digitalWrite(25, LOW);
		// run the tests
		int r = runtest();

		if (r == 1) {
			digitalWrite(25, HIGH); // Green LED
			Serial.println("Pass");
		} else if (r == 0) {
			digitalWrite(24, HIGH); // Red LED
			Serial.println("Fail");
		} else {
			// TODO: remove this and turn on red LED
			// when Teensy 2.0 is discontinued
			Serial.println("Aborted - no USB ever seen");
		}
#if 1
		// write serial number to log file
		store_id_bytes("log.txt");
		// wait for no current (cable unplug)
		int undercurrent=0;
		while (1) {
			mA = read_current();
			//Serial.println(mA);
			if (mA < 0.3) {
				if (++undercurrent > 15) break;
			} else {
				undercurrent = 0;
			}
		}
		Serial.println("USB unplugged");
#endif
	}
	//Serial.printf("current = %.2f\n", read_current());
	//delay(1000);
}

void sd_error(void)
{
	digitalWrite(25, LOW);
	while (1) {
		//Serial.println("can't access SD card");
		digitalWrite(24, HIGH);
		delay(100);
		digitalWrite(24, LOW);
		delay(150);
	}
}

void sevenseg(int num)
{
	Serial.printf("sevenseg %d\n", num);
	static const uint8_t segments[10] = {
		//.AFBGCDE
		0b01110111, // 0
		0b00010100, // 1
		0b01011011, // 2
		0b01011110, // 3
		0b00111100, // 4
		0b01101110, // 5
		0b01101111, // 6
		0b01010100, // 7
		0b01111111, // 8
		0b01111110, // 9
	};
	uint8_t leddata[16];
	memset(leddata, 0, sizeof(leddata));
	if (num > 999) num = 999;
	if (num < 0) num = 0;
	int hundreds = num / 100;
	int tens = (num % 100) / 10;
	int ones = (num % 100) % 10;
	if (num >= 100) {
		leddata[2] = segments[hundreds];
		leddata[0] = segments[hundreds];
	}
	if (num >= 10) {
		leddata[6] = segments[tens];
		leddata[4] = segments[tens];
	}
	leddata[10] = segments[ones];
	leddata[8] = segments[ones];
	Wire.beginTransmission(0x70);
	Wire.write(0);
	Wire.write(leddata, 16);
	Wire.endTransmission();
}

void ht16k33_config()
{
	Wire.begin();
	Wire.beginTransmission(0x70);
	for (int i=0; i < 17; i++) {
		Wire.write(0); // zero display memory
	}
	Wire.endTransmission();
	Wire.beginTransmission(0x70);
	Wire.write(0x21); // turn clock on
	Wire.endTransmission();
	Wire.beginTransmission(0x70);
	Wire.write(0x81); // display on, no blinking
	Wire.endTransmission();
	Wire.beginTransmission(0x70);
	Wire.write(0xEF); // dimming, 16/16 duty
	Wire.endTransmission();
	sevenseg(0);
}




// prior hardware
// 23 = current measurement, 100 mA reads as 1.0V
// PTE6 = USB power, high = enable
// A21 = overcurrent threshold (DAC voltage)
// 4 = overcurrent alert, open collector, low=alert
// 5 = overcurrent reset, low=direct, high=latch any alert
 
I quickly tried running USB_Tester.ino on a Teensy 4.1 rather than Teensy 3.6. So many things go wrong. This code was only tested on Teensy 3.6, specifically the hardware in the readme photo.

To make this work easily, run it only on Teensy 3.6.
 
Back
Top