Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 28

Thread: Program Teensy from another Teensy?

  1. #1

    Program Teensy from another Teensy?

    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

  2. #2
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    4,090
    Quote Originally Posted by David M. Kramer View Post
    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.

  3. #3
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,626
    Is it possible to use another Teensy or another microprocessor to send the code, essentially replacing the computer?
    Yes, definitely. I did a quick feasibiltiy test some weeks ago: https://forum.pjrc.com/threads/47783...369#post159369

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,082
    It is possible using Teensy 3.6, which can act as a USB host. This cable is needed to connect the other Teensy.

  5. #5
    Quote Originally Posted by luni View Post
    Yes, definitely. I did a quick feasibiltiy test some weeks ago: https://forum.pjrc.com/threads/47783...369#post159369
    Thanks all for the help and guidance! If I succeed, I will post my step-by-step methods.

    Dave

  6. #6
    Quote Originally Posted by PaulStoffregen View Post
    It is possible using Teensy 3.6, which can act as a USB host. This cable is needed to connect the other Teensy.
    Hi Paul, in a previous post, you mentioned that you wrote a driver for this application for the 3.6. Can you point me to any documentation so I can see if it would work for us?
    Thanks again!
    Dave

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,082
    I've uploaded code here. It's pretty far from what you might call "documentation", but that's all I have available at this point.

    https://github.com/PaulStoffregen/USB_Tester

  8. #8
    Member
    Join Date
    Dec 2017
    Location
    France, Paris
    Posts
    77
    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.

  9. #9
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,108
    Quote Originally Posted by Armadafg View Post
    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

  10. #10
    Member
    Join Date
    Dec 2017
    Location
    France, Paris
    Posts
    77
    Yes sorry I am talking about the program that allows you to program another teensy card.
    That one : https://github.com/PaulStoffregen/USB_Tester

    I'm sorry but I didn't quite understand your last sentence

  11. #11
    Member
    Join Date
    Dec 2017
    Location
    France, Paris
    Posts
    77
    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;

  12. #12
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,108
    Quote Originally Posted by Armadafg View Post
    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.

  13. #13
    Member
    Join Date
    Dec 2017
    Location
    France, Paris
    Posts
    77
    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

  14. #14
    Member
    Join Date
    Dec 2017
    Location
    France, Paris
    Posts
    77
    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;

  15. #15
    Member
    Join Date
    Dec 2017
    Location
    France, Paris
    Posts
    77
    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.

  16. #16
    Member
    Join Date
    Dec 2017
    Location
    France, Paris
    Posts
    77
    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 !!!

  17. #17
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,108
    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;

  18. #18
    Member
    Join Date
    Dec 2017
    Location
    France, Paris
    Posts
    77
    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".

  19. #19
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,108
    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.

  20. #20
    Member
    Join Date
    Dec 2017
    Location
    France, Paris
    Posts
    77
    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

  21. #21
    Member
    Join Date
    Dec 2017
    Location
    France, Paris
    Posts
    77
    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

  22. #22
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,108
    Not ever looked - but anything with #ifdef T_4.1 especially if different .vs. T_3.6, may need to include T_MM?

  23. #23
    Senior Member
    Join Date
    Apr 2020
    Location
    DFW area in Texas
    Posts
    298
    Quote Originally Posted by Armadafg View Post
    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

  24. #24
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,082
    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.

    Click image for larger version. 

Name:	image.jpg 
Views:	13 
Size:	86.8 KB 
ID:	25956

    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".

    Click image for larger version. 

Name:	screenshot1.png 
Views:	15 
Size:	63.1 KB 
ID:	25957

    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;
                            case 0x26: filename = "TEENSY40.HEX"; return true;
    			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.

    Click image for larger version. 

Name:	screenshot2.jpg 
Views:	12 
Size:	74.3 KB 
ID:	25958


    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

  25. #25
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,082
    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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •