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

Jon,

OK, loaded FlasherX.ino with all default settings on a T3.5, and got the serial port printout - "waiting for hex lines...", but I'm not quite sure how to proceed from there. I tried loading up another Teensy 3.5 program (via the same USB connection that I used to load FlasherX.ino) that just blinked the LED and reported the blink count via serial. This worked, but I don't see that it did anything differently than a normal program load.

Do I need to change the 'Stream* serial = &Serial to' &Serial1 or &Serial2 and use that port to load the new program?

TIA,

Frank
 
Instead of using the standard serial monitor, you must use a terminal program, such as TeraTerm, which will display the messages, just like the serial monitor, but also has a “send file” capability.
 
So use the default serial port (in this case the USB port), but use a terminal program to send the .HEX file produced by compiling the desired Teensy 3.5 program?

TIA,

Frank
 
Yes, load the FlasherX sketch into the T35, then use TeraTerm to connect to the USB serial and use the Send File feature to send the same hex file. You can repeat this multiple times if you want.
 
OK, I used Tera Term to send the FlasherX.hex file to the T3.5 several times, and it appears to have succeeded - get the same 'waiting for hex lines' prompt as before each time. (It took me a few minutes to figure out how to use Tera Term, as I have been using PuTTY). One minor nit with Tera Term and FlasherX: If I set Tera Term Terminal config to 'local echo' so I can see the numbers I type in (2962 in this case), then the hex blocks are doubled. If I disable 'local echo' to avoid this and get a nice scrolling display of hex blocks as they are transmitted, then I can't see what value I'm sending to initiate the flash procedure.



So now that I have this working, how do I go from here to flashing my own sketch?

TIA,

Frank
 
Did you read message #85? In general, if you want to add OTA capability to an application, you must:

(a) add files FlashTXX.cpp/h to the sketch, which provide the low-level OTA capability
(b) provide a way within the sketch to enter a "flasher mode", receive the new firmware, and write to the flash

If you have FlasherX running in your Teensy, you only have to do (a), and then you can use TeraTerm to send the new sketch to the Teensy. After the reboot, the Teensy will be running your sketch. If you have your own sketch in the Teensy, and you want to update to a new version of your own sketch, your sketch must also have (b). Think of FlasherX.ino as an example, where (b) is accomplished via function update_firmware().
 
OK, I think I have it working now. I have a 'Teensy Flash Demo V1' sketch (it simply toggles the built-in LED every 500mSec) with a 'CheckForUserInput()' function I use in other sketches that require user input. When the proper character ('c' in this case) is received, the serial buffer is cleared and then 'update_firmware()' (copied from FlasherX) is called. At the 'waiting for hex lines' prompt, I then use the 'Send file..' feature of Tera Term to transfer Teensy Flash Demo V1.HEX over the USB serial port. At the end of the transfer I get:

Code:
hex file: 2973 lines 47532 bytes (00000000 - 0000B9AC)
new code contains correct FSEC value FFFFF9DE
new code contains correct target ID fw_teensy35
enter 2973 to flash or 0 to abort

when I enter the correct value, the Teensy reboots and runs the same program, and the LED continues to blink, confirming (I think) that the program flash was successful.

Does this all sound reasonable?

TIA,

Frank
 
Yes, that's correct. Nice work. If you put something like the line below into your setup() function, and you rebuild your program between updates, you'll be able to see that the build time changes. When you're flashing the same sketch, that's one way to be sure that the update worked.

Code:
  serial->printf( "\nFlasherX OTA firmware update v1 %s %s\n", __DATE__, __TIME__ );
 
Nice addition - makes it much easier to have confidence in the updates.

So, not quite as convenient as my current setup with a two-Wixel serial over wireless setup with Arduino, as that is pretty much transparent to the user, but still pretty easy. The Tera Term 'send file...' feature is 'sticky' in that it goes back to the last folder used, so that's pretty easy too. Maybe if TT has an API, it could be automated via VS2019's post processing?

Frank
 
Sending the hex file via TeraTerm is just a way to get new firmware to the Teensy for demo purposes. I don't know how you want to be able to update your Teensy, but my goal was to be able to update Teensy applications remotely over UART or Ethernet. To do that, I include FlashTXX.cpp in my sketch, but rather than sending a hex file via TeraTerm, I use a custom Windows program that loads the hex file, converts to binary, and sends commands to enter flash mode, send code, confirm good, write to flash, reboot.
 
Yes, that's sort of the decision I came to as well, after thinking it over last night. Would you mind sharing your Windows program? If it's on GitHub I'll be happy to clone it.

TIA

Frank
 
Unfortunately I don't have a way to do that at the moment. The Windows programs rely on a large code base and a UI specific to Embarcadero (formerly Borland) C++ Builder.
 
Hmm, interesting. IIRC I did an entire research radar control program using Borland C++ Builder and Delphi when I was a research scientist at The Ohio State University here in Columbus OH. It was installed at the MIT Lincoln Labs facility near Boston, and AFAK is still operational.

Would you mind expanding a bit on the steps you mentioned above? Why the 'convert to binary' step? I thought it was the HEX file that is used for the flash operation, and that is certainly the way it (at least seemed) to work here.

I have no problem building a custom console application in C#/C++, but I'd rather not re-invent the wheel in terms of the algorithm ;-).

Frank
 
I was porting embedded code from a platform where the binary block format had been used. There's no reason for you not to use Intel Hex since you already have working code for the Teensy side. Your Windows client can just (a) send a command to put the Teensy into download mode, (b) send the lines of Intel Hex, (c) confirm that all lines got there okay, and (d) send a command to write to flash and reboot.
 
a) Send command to put Teensy into download mode: This would be whatever is needed to call update_firmware()?
b) send the lines of hex: self-explanatory
c) send a command to write to flash and boot: right now this is part of update_firmware() - where it compares user input to the size of the hex upload?
 
I'll explain what I do, and maybe that will help. On the Teensy side, I have a task that receives commands from a UART serial port, parses the data into opcodes and data, and executes the commands if they are valid. With respect to firmware update, the commands are:

- enter update mode and init buffer
- write a record to buffer (address + code bytes)
- compute and return CRC of buffer
- write new firmware to flash and reboot

On the Windows client side I have a UI where I select a hex file with the new firmware I want to send to the Teensy. When I press the "Go" button, the windows client uses a state machine to go through the steps below. The Teensy replies to each command.

- send command to enter update mode
- send commands containing the new code
- send command to requests CRC of the buffer
- send command to write to flash (assuming CRC matches)

You haven't said anything about your objective, what type of connection will you have with the Teensy, whether you want to do the update remotely, etc. I assume so, otherwise you would just make the local connection and upload via Arduino or whatever IDE you are using.
 
Thanks for the nice explanation - that helps a lot.

Currently I am working with a wheeled robot that uses a Mega 2560 for control, and I update its firmware 'over the air' using a Pololu Wixel pair configured as a serial-over-RF pipe. The Wixel shows up as a COM port on my Win10 box, so I simply select that port in my development IDE (Visual Studio Community Edition with Micro Visual Arduino IDE extension) and do a compile-with-upload (F5). The rest is completely transparent. I have used this technique for several years and it works great.

I would like to replace the Mega 2560 controller with a Teensy product (probably a T4.x), but I want to retain the convenience of seamless OTA firmware updates - thus the current push to understand and utilize your cool FlasherX package.

Currently I have been able to do the firmware update over wired serial (USB port) with a T3.5 using a 'Flasher Demo' project that incorporates the FlasherX features. Then I created a Windows console app and figured out how to call it using the post-build command features supported by the Visual Micro extension. Right now the console app doesn't do anything but echo the arguments it receives, and the post-build commands don't do anything but call the console app with the current project path as a string argument, but the plan is to have the console app follow the same workflow you described above.

I still have a lot of work to do to make this process as convenient as my current update process with the Wixel/Arduino combination.

For instance, I still don't know (yet) what RF link to use. In a previous experiment I figured out how to use a HC-05 Bluetooth module for serial transfers, so that's a definite possibility. In another experiment I had figured out how to use an ESP32 DevKitC as a serial bridge using a wireless ethernet connection, so that's a possibility as well. I could also use my current Wixel pair setup, but this might be a bit more complicated. Currently I use the Wixel Shield product from Pololu which is very convenient with the Mega 2560, so I'd probably have to build a custom PCB to match up with the Teensy board layout.

Also I don't yet know how to extract the currently selected port number from the VS2019 setup so I can pass that to the console app, which in turn will use that port to communicate with the Teensy on the other end of the link.

So, that's where I am. Not there yet by a long shot, but I'm having fun and learning a lot ;)

One last thing. As you can see from the embedded links above, I document my projects on my 'Paynter's Palace' blog site. I do this because it might help others with the same issues, and because at my age my memory is so bad that I can't remember what I had for breakfast, let alone the details of a project from years ago. In any case, I plan to create at least one post documenting the effort to achieve seamless Teensy OTA, and I would like to use material from this forum thread. Would you have any objection if I use your posts (with proper attribution of course) in my blog article(s)?

Frank
 
On the Teensy side, I think you need to move to using a UART serial rather than the USB serial. What I would do is:

- modify FlasherX.ino to use a UART serial port and confirm that you can transfer updates via UART serial with TeraTerm
- replace the wired serial link with your Pololu Wixel wireless serial link, still using TeraTerm and doing the update "manually"

You shouldn't expect to be able to integrate the FlasherX update method with your build environment, the way you do with the Mega. For that, you would need a UART serial bootloader on the Teensy side, and that isn't possible.
 
Thanks for the thoughts regarding UART vs USB serial - I will definitely try that (and the Wixel trick) before getting too far ahead of myself ;-)
 
I'm working on my automated Teensy flash routine, and I'm to the point where I open the .HEX file in preparation for sending it to the Teensy. As part of this process I thought I would compute the checksum of each line before sending it, and also add up the number of bytes so I can compare to what the FlasherX code does in the Teensy. When I computed the checksum for each line, I got 00 as the checksum result for each line. Is this correct?

TIA,

Frank
 
Thanks! I actually had that idea as I was drifting off to sleep last night, so it's nice to have my errant thought confirmed ;).
 
Thanks! I actually had that idea as I was drifting off to sleep last night, so it's nice to have my errant thought confirmed ;).

Since you have control of both ends, you might consider computing a 16-bit CRC, or at least a 16-bit or 32-bit sum, of all bytes as you send (on the client side) and receive (in Teensy). That would provide a much better test of whether all bytes arrived correctly than a one-byte sum. When I say "all bytes", I mean the bytes included in the Intel Hex checksum.
 
Hmm, I can see where that might be a very good idea, especially since my plan is to do this OTA using a BT adaptor. Depending on the range, the RF link could be much more error prone than a wired serial link. However, I think I'll wait to do this until I get everything working ;-).
 
I want to use this code on a Teensy MicroMod. This is basically a Teensy 4.1 but in a... teensier package. I think I'll have to add an entry as I'm pretty sure it identifies itself as a micromod not a teensy 4.1. But, no big problem there. My real questions are:

1. It seems like the code as-is allocates no RAM buffer but you need to do so on a Teensy 4.1 / MicroMod. So, I just have to edit things to make it create a buffer, right?
2. Related to the above, the T4.1 has like 8MB of FLASH but you cannot allocate 8MB of RAM to buffer this. So, I think I'd have to do the FLASH write in chunks, correct? On a Teensy 4.1 code is by default run in RAM so it seems like what I should do is allocate a buffer above, say 64k bytes then flash in chunks. The return address will be OK because it'll just return to the RAM resident function, grab the next 64k chunk, and enter flash_move again to write that chunk, over and over until it is done. This means I'd have to remove the REBOOT from the end of flash_move and call it multiple times. Then I could reboot at the end of all the chunks.

Does that all sound like basically what would have to happen?
 
Back
Top