SD Bootloader

Status
Not open for further replies.

Frank B

Senior Member
Hi,

i wrote a "Bootloader" which reads a HEX-File from a SD-Card and writes it's contents to the flash-memory of the Teensy 3.1 / 3.2.
The maximum binary size is 128KB (this is NOT the size of the "*.hex"-file)

It is not very well tested, so be careful.

Don't press the button while flashing, and don't disconnect the power - a bricked Teensy will be the result.
Again, be careful.

There is no chance to rescue a bricked Teensy - don't ask the forum - really, there is no chance. Buy a new one. I can not help you, Paul can not help you.
Be careful :)

The usage is easy, please try the included example, with "blink.hex"

https://github.com/FrankBoesing/Bootloader_HEX

Please note: The license is GPL V3.

Have fun,
Frank.

p.s.: "Pullrequests" welcome.
 
Last edited:
I got this working and made a sample that looks like I coded to run 16+ hours and then auto Bootloader() a HEX file. I use EEPROM addr 1999 for storage, and increments it on each Bootloader event. My sample sketch runs as two versions based on the EEprom values as ODD or EVEN.

Code:
    if ( ODD )
      ret = bootloader_hex("qBlinkB2.hex");
    else
      ret = bootloader_hex("qBlinkB1.hex");

If it fails to load either of those by name it tries to load a non auto bootloader version: qBlink.hex.

If you compile attached INO to HEX and then copy it to 'qBlinkB1.hex' and 'qBlinkB2.hex' on the SD card - then use IDE to upload that or TeensyLoader to HEX load it starts the chain off. One will USB print '.' on each blink the other when loaded (based on EEprom value) will print "~" as it blinks toward reloading.

If either of those are missing when it tries it will use my standby 'qBlink.hex' file, it runs showing ":" on each blink.

I put in three USB commands:
B: BootLoader Swap now
S: EEprom & time to re-Bootload Show
Z: Zero EEPROM counter toggle

I'll attach my source for the safe non-Bootloader() 'qBlink.ino' - if you dare to try this - you'll need to find your own HEX output from the IDE for 'qBlink_BL1_Oct11b.ino' and rename as indicated and put it on your SD card - in so doing you acknowledge the risks of being so clever as to get that far.

Frank's sample worked for me in Beta - and without change I migrated that to my samples.

View attachment qBlink.ino
See later post for 'improved' version


<edit - see post #3 - removed SPI contention over pin 13 - LED_BUILTIN >
 
Last edited:
Update: The point of qBlink is a sign of life heartbeat - but it seems using SPI and :: "#define SDCARD_SCK_PIN 13" redefines that pin from OUTPUT and prevents the use of LED_BUILTIN.

So qBlink on LED_BUILTIN stops working after the SD.begin(), I've commented it out after that - you can put an LED on another pin if you need more feedback than USB.

NOTE: I also moved auto Bootloader timing to two hours - make that 2 minutes at 120,000 milliseconds. It just ran 10 times on me while I stepped away.

Here is the updated "qBlink_BL1_Oct11b.ino", where I also moved EEPROM to one byte at addr to 1996, before I saw the reason the qBlink stopped.

See later post for 'improved' version

It also adds a USB "Q" command to bootloader_hex("qBlink.hex"); to the non-auto Bootloader() version (to show versatility)- any USB entry not known prints the command list:
B: BootLoader Swap now
S: EEprom & time to re-Bootload Show
Q: re-Bootload to qBlink and stop auto Bootloader
Z: Zero EEPROM counter toggle
 

Attachments

  • qBlink_BL1_Oct11b.ino
    4.8 KB · Views: 220
Last edited:
I'm guessing it would be a bad Idea to attempt to run this on a Teensy 3.0 or aTeensy LC due to memory limitations?
 
bad Idea to attempt to run this on a Teensy 3.0 or aTeensy LC

Both cause the IDE to report: "#error CPU NOT SUPPORTED"

FrankB better to answer - Definitely not on Teensy_LC - the code used I think precludes that. And on a T_3 it may have the instruction set - but untested I assume and indeed lower memory space and the utility work areas of FlexRam might be an issue. This may be covered in the package - which I tried as a Beta without taking time to read after it worked.

For my qBlink contention - I'm wondering if I could simply put off the SPI and SD.begin() until they are needed at Bootloader call time? I left it up front to assure the SD card was ready, though it doesn't stop execution when it fails.

<edit>: Moved the SPI & SD init from setup with bootloader() call to a function together and it works with a file list - and I can qBlink() until then.
 
Last edited:
First of all, thank you Tim for testing !

Both cause the IDE to report: "#error CPU NOT SUPPORTED".
The Teensy 3.0 might work, if someone adds the missing #defines.
I have no Teensy 3.0, and so i can't test anything.

I did'nt look at Teensy LC, and i don't know if it is useful there, because only the half of the flash can be used. In addition, the flashmodule might be different.
 
Last edited:
Okay this pig has some fresh liptstick - Not Frank's work - but my sample! According to my EEPROM value I've done this perhaps 4 dozen times. The current REV 'c' version has a timeout of 2 minutes.

Rather than fight the pin 13 issue - I went to pin 14 as used with the PJRC audio Adapter - The blink is back in qBlink! But I did delay the SPI & SD init until the actual effort to execute the bootloader_hex() call.

I FATTENED up the HEX ( reports as 122K) by using .printf , the IDE reports 44K as noted - much prettier output - I display the file name to be loaded! Also added a few better breadcrumb USB prints on the process.
Sketch uses 44,328 bytes (16%) of program storage space. Maximum is 262,144 bytes.

When I was looking to work around the pin 13 I decided to add the filenames as strings, which makes them printable rather than hardcode within the code. That would allow a user to pick their own 3 filenames easily - and it could be extended beyond 3 by removing the tie to the EEPROM value ODD or EVEN. A dirlist could be done of .HEX files and the array filled and offered for selection of whatever file is on the SD disk. My example swaps between two booltloader() capable files so it can test 'perpetually' - it has done that 5 times as I type this post.

View attachment qBlink_BL1_Oct11c.ino

Here is a view of the debug SPEW - one instance prints '.' the other '~' and when the time elapsed is updates the EEPROM and auto loads the other file:
BootLoader file to load: qBlinkB1.hex
SD initialization WORKED!
OK
......................................
......................................
......................................
..............................AUTO BootLoader Swap AHEAD!
BootLoader file to load: qBlinkB2.hex
SD initialization WORKED!
OK
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
Last edited:
This is a very interesting development, but I want to understand a few things... after using this boot method (assuming it is done correctly) are you still able to later reprogram the Teensy normally via USB, or is the first SD card flash a "point of no return" ?
 
@defragster,
It would be interesting to know how often the flash can *really* be rewritten. If i remember correctly, the manual says something like 10.000
Maybe it's much more ?
 
It would be interesting to know the expected longevity - my AutoFB flash count is at 99 now - some are false starts as it updates before it tried to exit - and I made some skip the bootloader. But I was using another counter location before that had more than a few. It was posted I think that the T_LC flash is less durable than the T_3 family - I thought I saw it in excess of 10K though?

For a lib name how about Auto Flash Bootloader - or AutoFB { just happens to be Auto Frank B too }

@JBeale : Indeed this works without any change in Teensy behavior - before and after the self programming {just not during!} - I can program the device over USB - I've done this a couple dozen times during my development & adjustment on the primary app.

Since my last post I left it running on 2 minute re-flash and some 30 plus AutoFB iterations happened toggling between B1 and B2 HEX files - with nothing but ongoing operation. BTW I see about 5 seconds for the program request and the USB being back online after Flash and Boot completes.

Worst Case so far:: Frank: [ got email with my HEX files and INO's to look at tomorrow. ]
To exit my Auto cycle I hit "Q" for Quit - which AutoFB loads the static qBlink.HEX. 2-3 times now (maybe more oddities ) - ONLY ON LOADING qBlink it won't restart and I've found TeensyLoader reprogram after a close TeensyDuino then Verify (re-open TeensyDuino) then "button hold USB powerup" to work fine. It will not restart on re-power and will not take an upload from TeensyLoader otherwise.

Note I've just done this 3 times and it worked each time properly doing a TeensyLoader app upload, then entering "Q" before it does the AutoFB Toggle.
My random speculation:
1:> is that after a series of the Toggle B1::B2 AutoFB's the load of the shorter qBlink HEX file leaves something unclean?
2:> more likely - this is similar to recent behavior I've seen on Win10 where I've needed to do this a couple times doing development on sketches wholly unrelated to this. Perhaps it is a 'shock' to the USB system to have the device talk (it just got the "Q" input) one second and gone the next - versus output only during the auto timeout Toggle? [Though to test this I just programmed 3 times and then entered three "s"'s to show status followed by 'q' - and they worked to bring up qBlink]
 
I saw the 'Reset Reason' code and thought it might add a clue.

I added it to my sketches - the 400 looks Good for AutoFB - but I am alternatively seeing "200 CoreLockup".

It shows these codes - with my comment added:
40 ExtResetPin // This is a RESET as applied with TYQT or TeensyDuino UPLOAD
82 LowVoltage PwrOn // Kill Teensy power and restart
200 CoreLockup // This doesn't seem right but happens most often - and comes up running
400 Software // This is from a normal "B" when I short circuit the timer wait, and sometime from the Toggle.

Frank - I'll ZIP up and resend my updated work in case it relates.

The output could be cleaner I bolded the reason feedback:

AUTO BootLoader Swap AHEAD!
BootLoader file to load: qBlinkB2.hex
SD initialization WORKED!
OK
200
CoreLockup
done Reason
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~AUTO BootLoader Swap AHEAD!
BootLoader file to load: qBlinkB1.hex
SD initialization WORKED!
OK
200
CoreLockup
done Reason
..................2 bytes >>b

BootLoader Swap now
AUTO BootLoader Swap AHEAD!
BootLoader file to load: qBlinkB2.hex
SD initialization WORKED!
OK
400
SoftWare
done Reason
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~AUTO BootLoader Swap AHEAD!
BootLoader file to load: qBlinkB1.hex
SD initialization WORKED!
OK
400
SoftWare
done Reason
......................................
......................................
......................................
..............................AUTO BootLoader Swap AHEAD!
BootLoader file to load: qBlinkB2.hex
SD initialization WORKED!
OK
400
SoftWare
done Reason
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
Update - I left my Toggle sample running and looked over and after what looks like 13 cycles continuing from the above it was halted.

NO BRICKING - Just unclean behavior from my sketch!

I closed TeensyLoader - hit Verify - hit BUTTON and it came back to life just fine - I thought - now I see this NEW devolution in my code from it failing - when it prints ":" that should be the non-AutoFB code - The event I recovered from left the SD/SPI system not properly working : the USB notes "SD initialization failed!"

There is more - attached annotated TXT file of the USB spew I captured: View attachment AutoFB_13times.txt

OK
40
ExtResetPindone Reason
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~AUTO BootLoader Swap AHEAD!
BootLoader file to load: qBlinkB1.hex
SD initialization failed!
Bootloader not successful, return code :-10
BootLoader file to load: qBlink.hex
SD initialization failed!
Bootloader not successful, return code :-10
Hello - Try again later . . .
:
::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::QUIT BootLoader Swap AHEAD!
BootLoader file to load: qBlink.hex
SD initialization failed!
Bootloader not successful, return code :-10
Hello - Try again later . . .
::::::
::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::QUIT BootLoader Swap AHEAD!
BootLoader file to load: qBlink.hex
SD initialization failed!
Bootloader not successful, return code :-10
Hello - Try again later . . .
 
Last edited:
Bad news.

I managed to brick a Teensy.
After hundrets of reprogrammings via SD, the last one has gone wrong.

I don't know why.

@Paul, question: What does the mini-bootloader do, when the teensy resets with
*(uint32_t *)0xE000ED0C = 0x5FA0004; ?

@all, i deleted the repository, to be sure. If i can find the reason and a way to prevent this, i upload it again.
 
Last edited:
phew..

now after several minutes without power, and pressing the button while connecting usb it's living again.
so NO brick.

But still do not know the reason for that - and i don't know the reason for the "LockUp" state after reset.
 
@Paul: When code is flashed - what is the same and what different when the new code is about the same size as the last upload versus going to a grossly larger or smaller HEX image being flashed? i.e. are there any 'fixups' of any sort that differ based on code size (or similar things I know nothing about)?

@Frank: when it restarted with button held did you have to push in new code ( I always do as the prior flash was non operative ) - or did the prior flashed code function?

I ran into that state over a dozen times running this AutoFB code - but the process I used to get out of it was the same I used doing code prior to ever working with this (though more rarely). I have left notes on the forum as I saw these - it is nebulous but I suspect it is related but not 'on demand' reproducible. Though last night with AutoFB I got it to fail after 2 and 3 iterations of AutoFB (never worked beyond 3 on 6 tries) with a change in the code size that was flashed - before it was running 10-30 or more times toggling the same HEX over itself time after time. [it was the same INO one compiled optimized was 125KB HEX and non-optimized was 67KB HEX] I got this idea because I had a non AutoFB version of qBlink that was 52KB hex and when I did an AutoFB of that it would fails about 50%.

<edit>: I have just created two variant of my qBlink code that are 5% and 15% of Teensy 3.1 code space and alternating between then a few times with Button press or TYQT upload causes no problems. MORE IN FOLLOW UP post.

As noted above I found and implemented the ResetReason() code and it does not point to a specific value preceding the halt of normal operations - sometimes "200-CoreLockup" but almost as likely it is preceded by a "400-Software", and more than a few times after an AutoFB operation the "200-CoreLockup" appears and the process completes normally.
 
Last edited:
Using the UPLOAD NEW FIRMWARE feature of TYQT:

When TeensyLoader does the uploads as noted above it also ran 10 times no problem.

When TeensyLoader is closed TYQT ran over 15 times alternating big small on the HEX file. TYQT seems to have the USB programming code from a HEX built in and it works stand alone.

PROBLEM:
Twice when TeensyLoader was open it failed after two tries - in what seems to be the same way AutoFB fails, and I have seen on prior sketches. I have to repower the Teensy 3.1 and then hit Button to load in usable code. The device powered up OFFLINE and TYQT could not see it - but it did respond to the button.

After the last reset and TeesnyLoader upload I did a single TYQT Upload New Firmware and it halted. There is observable 'crosstalk' as TYQT is programming the T3.1 at the same time the open TeensyLoader enters Program mode and does the green progress bar. I am not sure who is talking to the Teensy at this point?

TYQT is not PJRC supported and Paul may not yet have tried it - but this example excludes the AutoFB code and reproduces what I have seen as a nebulous error requiring power off button reprogram - particularly when testing AutoFB. NOTE: None of my Pre AutoFB HALTS have involved using TYQT for 'Upload New Firmware'. I tried it once the other day and got this behavior so I have not used it again until now to test this.

FORUM RULE: Okay so I went to 'HelloSerialMonitor' and did the TeensyUpload using TYQT 10+ times and they all worked while TeensyLoader was active! The first time I uploaded HEX from my qBlink it HALTED. Code below.

View attachment qBlink_sketch_sep17a.ino
 
While developing the low power stuff i thought i bricked my teensy's many times, the most sure fire way i found to bring back the preverbal dead teensy was to:
  1. while it has no power hold down the 'program' button.
  2. plug it in to the computer.
  3. release 'program' button with the teensy loader open.

This seems to be the best way to get it to reprogram. Also I add some sort of delays, even in the startuphook before messing with registers early on in the boot process, what has happened is that the teensy boots up so quick that you don't have time to catch it before it crashes and can't reprogram.
 
You are correct in those steps duff - in my case - a simple power cycle usually worked <edit: to allow TeensyLoader upload>, but the button press process sometimes had to go more than once, sometimes it seemed I needed to close and restart TeensyDuino as well.

RE p#17: I repowered and restarted - initial Teensy load and then with TeensyLoader active I used TYQT and it Halted and failed to program again first time.

I restarted with Teensy as TYQT doesn't recognize and start from a HID device - only USB. Then closed TeensyLoader and the TYQT repeated many times fine - restarted TeensyLoader and TYQT continued to function a few times until I got a phone call.

@Paul: back to my p#16 question - is there any chance it isn't a size or flash state problem - but some other aspect of the 'supported Teensy USB bootloader' programming catching the reset and "doing something"?
 
Last edited:
I really do not know what would happen if both TYQT and Teensy Loader try to talk to the same Teensy. All sorts of wrong things could occur, I would imagine, especially on Windows where the USB stack isn't very robust.

Please keep in mind that Teensy 3.0 & 3.1 use a different bootloader than Teensy LC & 3.2. They're meant to look and work alike, but the code and its specific timing and handling of error conditions are entirely different between the Mini54 and MKL02 chips. Likewise, Windows, Linux and Macintosh all have subtle differences which normally don't matter, but might come into play under exceptional circumstances. Windows 10 has greatly improved USB code. Apple has also changed their USB code a few times over the years. I believe Linux has been pretty consistent, but it too isn't perfect. Normally those differences are of little or no concern, but when you get 2 programs simultaneously accessing the same device (possibly with complex race conditions) through the HID abstraction layers and USB stacks on these operating systems, even very subtle difference could become important.

My point is there's a lot of complex and unknown factors here. And that's before you throw self-modifying flash code into the mix on the Teensy side!

I really can't dedicate my limited dev time to TYQT issues. If there's a potential problem that involves use with only Teensy Loader, please let me know and I'll take a look.

is there any chance it isn't a size or flash state problem - but some other aspect of the 'supported Teensy USB bootloader' programming catching the reset and "doing something"?

Without spending a *lot* of time digging into this, I simply do not know.

@Frank - I want to allow and even encourage experimentation. But this stuff is pretty risky. You did disclose that, but I feel an extra "moderator notice" might be appropriate on this original post. I'll add one in a few minutes....
 
Thanks Paul: If it doesn't spring anything to mind offhand then it will take a better repro case.

I wasn't thinking of DUAL USB directly - TYQT owns the port - I was just wondering if maybe somehow bootloader or some other device descriptor was seeing traffic - somehow they both do a gas gauge . I only presented the TYQT case because it seems to emulate the problem of AutoFB - even with standard USB upload of normal USB I/O apps, not because I ever need to do that. As noted I've had a very few standard uploads do this - and of course my forum notes elsewhere about the odd state the system gets into when you get TeensyLoader confused with misdirected HEX re: TLC .vs. T3.x - that while it never mis-programs does exhibit some 'state stickyness' where backing out of that can get tricky. So much change with Win7 to Win 10, and IDE 1.6.xxx and 3.1 .vs. 3.2 .vs. LC and of course TeensyDuino it is a moving target to keep up, on such a generally stable system. So far other than of bit of reset effort, I've never bricked a Teensy!

I am using a T3.1 just now - good to know the MKL02 interface may be different - I have 2 T3.2's here now, my next test was to have the AutoFB test run on one teensy and serial spew the debug to another to relay to USB. Looking forward to the Touch_ILI9341 - OSH has my ordered boards queued for 10/15 (touch and other) - between those two orders I requested another (3) T3.2's.
 
Let me point out, that - sure - SD reflashing is risky and will ever be risky. But not much more than with usb.
I managed to "Brick" a teensy one time only - and that was completely my fault because i edited my code and wrote zeros to all flashsectors - by mistake.
I had my previous version running several month - it was a more simple version, and for my personal use mainly. but it was published at github, too, and i know people who use it. it read binary files instead of hex, which is a bit more risky because there were'nt any checksums and so on.

Defragster - (thanks!!!) had found a problem with flashing files of very different sizes. (new "HEX"-version of the bootloader)
We're testing a new version, currently.

Of course, flashing a running system is somewhat unusual, and to call the flashing-function in main() too.
I don't recomend that. The preferred way is to call the bootloader in setup() - directly after power-on or reset and initializing SPI and SD.
The tests we are doing dont work this way. But i want to bootloader stable as possible, so why not. It should work this way too, but, remember - i don't recomend that. Then, if possible, do a manual power-cycle or reset after flashing. I don't trust the Software-reset (anymore).
 
Last edited:
Paul - per #22 it seems my test sample did zero in on the problem when the HEX size varied - but it was Frank's code not related to PJRC function.

Now I just need to get my SD adapter and samples to work again - I moved it to allow serial debug testing with a second T3.1 . . .

<edit>: I put my SD adapter back on the old breadboard and it works again . . . back to try the new code soon
 
Last edited:
Hy i am very interested in your project.
the github link leads to a page not found side.

Can you reupload it please?
Thank you very much
 
Status
Not open for further replies.
Back
Top