'Over the Air' firmware updates, changes for flashing Teensy 3.5 & 3.6

I've built a new version of Flasher to allow the largest possible upload by identifying empty sectors from the top of existing firmware to the bottom of flash reserve. This eliminates the need to explicitly specify the flash buffer location when building "small" or "large" programs, which gets very confusing. If an upload will not fit in the available space, you can use the two-step process of uploading a small program, and then uploading the larger one. The largest possible upload is FLASH_SIZE - smallest possible "flasher" program.

There was one important change required to make this work. At the end of flash_move(), after the new firmware has overwritten the old, and before the reboot, flash is erased sector-by-sector from the top of the new firmware to the bottom of the flash reserve. This leaves the flash in the same condition as if the upload had been done with the Teensy loader, which seems like a good thing. Prior versions left the upper flash un-erased, so the first step for an upload was to call flash_erase_upper(), and that is no longer necessary. Other changes include adding a new argument uint32_t flash_buffer_addr to several functions.

Let me know your thoughts, and I'll post the new version if you agree it sounds okay.
 
@gonzales, yes, you're right. I simply replaced FLASH_SIZE/2 with FLASH_BUF_ADDR everywhere. In that case, the original code should have been (FLASH_SIZE - FLASH_SIZE/2 - RESERVE_FLASH) and the new code (FLASH_SIZE - FLASH_BUF_ADDR - RESERVE_FLASH).

Let us know if it works correctly for you and I will upload another ZIP file with the correction.

I tryed many times to flash my teensy 3.5. Work fine!!!

joepasquariello - Thanks a lot!!!

One more extension: for Teensy 3.5 you can use #define FLASH_BUFFER_ADDR (FLASH_SIZE/8) for small loader and #define FLASH_BUFFER_ADDR (7 * FLASH_SIZE/8) for large program, so you have 7/8 of flash size for you program/
 
How can i use flasher over Ethernet?

I have the Teensy Ethernet kit and want to try to update my firmware over ethernet.

Ty :)
 
Over Ethernet is something I'm working on, have not been able to finish it yet. lots of other stuff todo.
The path I'm on is sending the flash data in the body of a post request, then code the teensy side to strip the data out of the body.
Sending the data is easy, Using curl to send the hex file in the body but I still need to write teensy code to handle the data.
 
Hi everyone

I have one question, why are we using flasher4 or flasher3 is it because of that its not possible to write a new bootloader or modify the existing bootloader or is it because of its the only way for new methods for firmware updates
 
Hi everyone

I have one question, why are we using flasher4 or flasher3 is it because of that its not possible to write a new bootloader or modify the existing bootloader or is it because of its the only way for new methods for firmware updates

I answered your question about a month ago...
No, it's not possible to write a new bootloader or to modify the existing one. It is protected.
No you don't need flasher for firmware updates. Just use the bootloader ;)
Flasher is only needed if you don't want to use the default bootloader.
 
What Frank said. If you need to do updates via Ethernet, work on getting Ethernet communication working, and you'll be able to combine with Flasher to do firmware updates that way.
 
OK... trying to grok this...

I'd like to Over-the-Air (OTA) update using BLE on a custom Teensy-3.2-designed board that has a Teensy Bootloader.
The board also has an internal uSD card for temporary storage of a HEX if needed.

My users will want the OTA nearly all of the time (from their phones) unless my OTA process "bricks" the Teensy while flashing...

Than I'd love it if the user could connect the USB cable and use a TyCmd-wrapped PC/Mac app to initiate an "un-bricking".
Most users would never need the PC/Mac app.

Again, I have the Teensy bootloader chip on my board... I just want OTA as the routine solution.

Is this a reasonable solution?
Should I dig in to the Flasher option, knowing I can recover from a "Brick" with TyCmd, USB and a Teensy Bootloader?
 
Yes, you can use the approach within Flasher3 for your OTA solution. Think of Flasher3 not as a production solution, but as an example of how to write new firmware to Flash once you have (somehow) transferred the new code to your board. Flasher3 does the transfer via USB serial and buffers the new code in unused (upper) program flash. If your application occupies less than 1/2 of the 256K T3.2 program flash, you can use this method, and I see no reason to use the SD card. If your program is larger than 128K (half of T3.2 program flash), you can still use Flasher3, but you have to do 2-step updates. Step 1 would be to write a small program to flash to make more flash available for buffering, and step 2 would be to send your new application using the now-larger available flash buffer. If you choose to buffer your code in the SD card rather than flash, you have some more development to do, but I think there are threads on the forum about other people doing that. Whichever way you buffer the new program, the code to erase the existing program and write the new program to Flash must be executed from RAM, with interrupts disabled. Flasher3 shows how to do that. Study it carefully before you try a new method, because there are ways that you can brick your board that are NOT recoverable via the Teensy bootloader. Specifically, when you write new code to T3.2 program flash, you MUST be certain to write the correct value to the FSEC and FOPT locations. If you fail to do that, you can brick your T3.2 in a way that is unrecoverable.
 
FlasherX - OTA updates for Teensy LC, 3.x, 4.x

FlasherX is a merge of Flasher3 and Flasher4 by Jon Zeeff, with some new features and updates. It works for Teensy LC, 3.2, 3.5, 3.6, 4.0, and 4.1, with a few caveats. I tested 3 transfer methods for each Teensy:

1) hex file transfer via Serial (USB) using terminal emulator
2) hex file transfer via Serial1 (UART) using terminal emulator
3) block file transfer via Serial1 (UART) using custom client

My objective was to support #3, transfer via custom client, so everything common to the 3 transfer methods is in file FlashTxx.cpp, and FlasherX.ino contains everything specific to hex file transfer via USB or UART. My platform was TeensyDuino 1.53 and Arduino 1.8.13 on Windows 7 Pro 64-bit, and I used TeraTerm for the file transfers.

For method #1, hex file transfer via USB, I found that the reliability of transfer was improved if each hex line was echoed back by the Teensy, while for method #2, hex file transfer via UART, the transfers were most reliable without this echo. I don't know why this is the case, perhaps Paul or someone else can explain it.

All of my testing with Serial1 was done at 115200 baud.

For Teensy LC, reliable updates via file transfer required a 1 ms delay after each hex line. TeraTerm supports this option.

For Teensy 3.6, clock frequency had to be reduced to 120 MHz for reliable file transfers. With the custom client the T3.6 is okay at 180 MHz.

FlasherX buffers the new code in flash by default, and automatically defines the largest possible flash buffer, from the top of existing code to the bottom of FLASH_RESERVE (settable in FlashTxx.h). After moving the new code from the buffer to the program flash, the flash buffer is erased. This leaves the flash in the same state as if the code was uploaded via TeensyDuino. If the new code to be sent via FlasherX is smaller than the available buffer, the update can be done in one step. If the new code is larger than the available flash, a two-step process can be used. Step 1 would be to send a minimal application with "Flasher" capability, and step2 would be to send the new, larger application.

|<------------------------------ FLASH_SIZE ------------------------------>|
^FLASH_BASE_ADDR
|<------- code ------->|<--------- buffer ---------->|<-- FLASH_RESERVE -->|

For T4.x, new code can optionally be buffered in RAM by setting macro RAM_BUFFER_SIZE in FlashTxx.h to a value > 0. For my testing I used RAM_BUFFER_SIZE (256*1024).

To switch between Serial USB and Serial1 (or any UART), just change the "serial" variable definition in FlasherX.ino. This variable, along with buffer_addr and buffer_size, are arguments to update_firmware(). update_firmware() is substantially rewritten from Flasher3/4, but does the same things. There is hex_info_t data structure, which I think makes it easier to see what's going on and what we need to keep track of during the file transfer. When the file transfer is complete, the number of lines received is displayed and the user is prompted to enter that value to trigger the udpate, or enter 0 to cancel.

For transfers via custom clients, these functions in FlashTxx.cpp provide the necessary API within your Teensy application:

flash_buffer_init -- determine the address and size of the flash buffer
flash_write_block -- write each received "block" of new code to the flash buffer
flash_check_id -- confirm that the new code was built for the intended target
flash_move -- move the (complete) new code from buffer to program flash
flash_buffer_free -- erase the flash buffer or free the RAM buffer in the event of error/abort

The flash write/erase primitives for all Teensy are also in FlashTxx.cpp, conditionally compiled by target. As in Flasher4, the write/erase functions are taken from Teensy4 core file eeprom.c. For Flasher3, the write/erase functions are based on Frank B's KinetisFlash module, with changes required to keep interrupts disabled during flash_move(). Note that kinetis_hsrun_disable/enable are called in flash_exec(), which I found was necessary to avoid baud rate issues with T3.6. Again, why T3.6 is different isn't clear to me.

Please give it a try.
 

Attachments

  • FlasherX.ino
    12.4 KB · Views: 157
  • FlashTxx.cpp
    23.3 KB · Views: 141
  • FlashTxx.h
    5.7 KB · Views: 151
Last edited:
Nice work. The intent is that other byte streams as input/out (eg, SPI or CAN bus) will be implemented with a Stream class?
 
Nice work. The intent is that other byte streams as input/out (eg, SPI or CAN bus) will be implemented with a Stream class?

Thanks, Jon. My use of the Stream class was purely to allow switching between Serial (USB) and Serial1 (UART) without touching update_firmware(). I intend to develop Flasher capability for Ethernet via a custom client. I haven't thought at all about SPI or CAN.
 
Not tried - but that indeed seems like nice work.

T_3.6 issues over 120 MHz is the fact that the sketch as compiled sets core clocking based on the compile speed - doing the speed drop to 120 MHz required for FLASH write alters clocks using the core clock, so devices based on those common core clocks ( UART, other ) doing transfers across that 'window' will be garbled by mismatching clocks.

The #3 block transfer it would seem pauses I/O between blocks during the FLASH writes?
 
One thing that might be helpful for some users that want to put Teensies in the field is to add an option to take the firmware image from a SD card. I would imagine in the startup code, there would be a check whether a project specific button was pressed and if so, go and load the firmware. I would imagine, you would want to specify the pin the SD reader is on, and which SPI port to use (including alternate SPI ports for Teensy 3.x using the audio adapter).
 
T_3.6 issues over 120 MHz is the fact that the sketch as compiled sets core clocking based on the compile speed - doing the speed drop to 120 MHz required for FLASH write alters clocks using the core clock, so devices based on those common core clocks ( UART, other ) doing transfers across that 'window' will be garbled by mismatching clocks.

The #3 block transfer it would seem pauses I/O between blocks during the FLASH writes?

defragster, yes, I finally looked at kinetis_hsrun_disable(), and it's only relevant for CPU_F > 120 MHz, so, the calls to hsrun_disable/enable in FlashTxx.cpp don't do anything on LC, T3.2, or T3.5, and won't do anything on T3.6 if the application is built for 120 Mhz.

For the #3 transfer, what I mean by "block" is a block file format as alternative to intel hex. My custom client reads the Teensy Intel Hex file into memory, then sends the code to Teensy in packets, each containing 256 bytes of code. The Teensy replies after each block is received. There is no pause in I/O, if I understand your question correctly.
 
One thing that might be helpful for some users that want to put Teensies in the field is to add an option to take the firmware image from a SD card. I would imagine in the startup code, there would be a check whether a project specific button was pressed and if so, go and load the firmware. I would imagine, you would want to specify the pin the SD reader is on, and which SPI port to use (including alternate SPI ports for Teensy 3.x using the audio adapter).

Michael, yes, I agree. I'll start with the on-board SD for T3.5, T3.6, T4.1. I've barely used SD, so I may leave it to others to go beyond that.
 
...
For the #3 transfer, what I mean by "block" is a block file format as alternative to intel hex. My custom client reads the Teensy Intel Hex file into memory, then sends the code to Teensy in packets, each containing 256 bytes of code. The Teensy replies after each block is received. There is no pause in I/O, if I understand your question correctly.

That pause per packet/block across T_3.6 writing ( where the hsrun speed and chip voltage is dropped ) allows the clocks to be restored before the next transfer when the Teensy issues the 'block received' to the source when the next packet/block is transmitted.

<add edit>: Using RTS/CTS might allow similar behavior when supported for option #2.
And what MichaelM said about SDcard would be cool. Frank B had a scheme worked out for T_3.2 that would read SD card and seeing a 'new firmware' indication would then load the indicated firmware and set the 'new' to 'not new' so it wouldn't repeat endlessly on each restart. That was tested to work with the 'half EEPROM' limit.
 
I wouldn't put any knowledge of SD cards (or any I/O device) into the flasher library itself. SD support would be done in an application code example (implementing a Stream subclass) that reads from a SD card file and calls flasher code.
 
That pause per packet/block across T_3.6 writing ( where the hsrun speed and chip voltage is dropped ) allows the clocks to be restored before the next transfer when the Teensy issues the 'block received' to the source when the next packet/block is transmitted.

Interrupts are disabled and hsrun disabled only during the actual flash write/erase operations, which are quite short. When the transfer is complete, interrupts are disabled for the entire duration of flash_move(), and the subsequent reboot.
 
I wouldn't put any knowledge of SD cards (or any I/O device) into the flasher library itself. SD support would be done in an application code example (implementing a Stream subclass) that reads from a SD card file and calls flasher code.

Definitely. I should be able to create FlasherX-SD, FlasherX-Ethernet, etc., with no changes to FlashTxx.cpp/h.

FlashTxx.cpp uses macros FLASH_BASE_ADDR, FLASH_SIZE, FLASH_WRITE_SIZE, and FLASH_RESERVE, but all other addresses are passed to functions as arguments, so flash_move() works for a buffer anywhere in RAM or FLASH.
 
Last edited:
Thank you so much for the hard work so far to get it to this point.

I've been trying to get the FlasherX working on my Teensy 3.5, and I've managed to get to the point now where it's checking the value of the FSEC field, but I get an error indicating it's not set correctly.
Code:
abort - FSEC value FFFFFFFF should be FFFFF9DE

The program I was trying to flash was a simple led blinker that printed "fs_teensy35" to serial before it started.

Is this something I have to set in my code before compiling (i.e. like the FLASH_ID) or is there a step i'm missing.


As a seperate question:
My plan is to have this as a permananet bootloader on my teensy, I was going to modify the flasher to write to an address after where the flasher was stored in flash.
On boot the flasher would start and if it didn't get a program within 10 sec it would then jump to the start of my program (so jump to another address)
Any reason this won't work?
 
Last edited:
The program I was trying to flash was a simple led blinker that printed "fs_teensy35" to serial before it started. Is this something I have to set in my code before compiling (i.e. like the FLASH_ID) or is there a step i'm missing.

My plan is to have this as a permananet bootloader on my teensy, I was going to modify the flasher to write to an address after where the flasher was stored in flash. On boot the flasher would start and if it didn't get a program within 10 sec it would then jump to the start of my program (so jump to another address)
Any reason this won't work?

If you have not simply built and run the FlasherX sketch on your T3.5, that would be my first step. To include flasher capability in your own program, you must have FlashTxx.cpp and FlashTxx.h in your sketch folder and #include <FlashTxx.h> in your INO file (and others if necessary). You haven't said how you are transferring the new code, so I can't comment on why your FSEC value is not correct. In my original FlasherX post, I outline the process of init/upload/write. If you post your code, I will look at it.

Regarding a permanent bootloader, that may be possible, but there is at least one problem you would have to solve. When you build an application with TeensyDuino, it is built to execute from FLASH_BASE_ADDR, and my guess is that it generally uses absolute addressing. If your bootloader is a complete program built by TeensyDuino, I don't think it will run from any location except FLASH_BASE_ADDR, which is 0 for T3.x. There are probably ways to work around that, but they would not be trivial. Flasher is designed to allow an application to be updated. It is not a bootloader.
 
> On boot the flasher would start and if it didn't get a program within 10 sec it would then jump to the start of my program

The flasher code has/had a routine called "boot_check()" for exactly this. All programs loaded must have the flasher code compiled in.
 
Jon,

I've been watching the 'OTA' threads for a while now, and I think it is now developed enough that I would like to try and see if I can do 'OTA' (initially via wired serial, but eventually using a Wixel serial-over-wireless link).

I have dl'd and looked through your FlasherX.ino, FlashTxx.h & FlashTxx.cpp files, but I'm not quite sure how to get started. I have both T3.2 & T3.5 modules to play with, and have used them in many projects over the last half-dozen years so I'm pretty familiar with them from that POV. How would you recommend I start with OTA in mind?

I have teensyduino set up and running on my Win10 laptop with VS2019 community edition and the Visual Micro plugin.

TIA,

Frank
 
@paynterf, you can start by building and running FlasherX.ino on your Teensy to get familiar with what it does. You will need a terminal program with a "send file" capability. I use TeraTerm for Windows. Also, read message #85 in this thread regarding how to use the functions in FlashTXX.cpp/h if you want to integrate OTA capability into Teensy applications and send firmware updates via a custom (Windows) client program.
 
Back
Top