Simple utility to field upload firmware.bin without the IDE

I’m looking for a simple-to-use utility to field upload firmware.bin without the IDE, something appropriate for a customer with minimum of computing skills. Specifically, I mean binary executable for Atmel SAMD microcontroller on Adafruit Feather M0.

See Compile and save file for future upload? - #2 by maxgerhardt and Pack binaries for distribution - #2 by maxgerhardt.

The simplest way you can do it with PlatformIO is building the firmware once (generates .pio\build\<env>\firmware.bin and other object files), then delete all the source files (if you don’t want to disclose the sourec), package that folder, then unpackage that on the custom site, have them install PlatformIO and run the command line command for uploading without building (since the source code files are gone and no rebuild is wanted) in the project folder. You can also build a simple batch script that execute pio run -t nobuild -t upload to make that simpler.

I think though this is still too technical for non-techincal users, they still would have to install PlatformIO. However, there are multiple ways other ways to do it.

For example, you can first of all grab the upload command / procedure that PlatformIO does with a project task “Advanced → Verbose Upload”. This will e.g. reveal for a Adafruit Feather M0 project…

RAM:   [=         ]  10.3% (used 3380 bytes from 32768 bytes)
Flash: [          ]   4.1% (used 10868 bytes from 262144 bytes)
.pio\build\adafruit_feather_m0\firmware.elf  :
section            size        addr
.text             10612        8192
.data               256   536870912
.bss               3124   536871168
.ARM.attributes      40           0
.comment             67           0
.debug_frame        692           0
Total             14791

<lambda>(["upload"], [".pio\build\adafruit_feather_m0\firmware.bin"])
AVAILABLE: atmel-ice, blackmagic, jlink, sam-ba
CURRENT: upload_protocol = sam-ba
BeforeUpload(["upload"], [".pio\build\adafruit_feather_m0\firmware.bin"])
Auto-detected: COM11
Forcing reset using 1200bps open/close on port COM11
Waiting for the new upload port...
bossac --info --debug --port "COM12" --write --verify --reset --erase -U true .pio\build\adafruit_feather_m0\firmware.bin
Set binary mode
readWord(addr=0)=0x20007ffc
readWord(addr=0xe000ed00)=0x410cc601
readWord(addr=0x41002018)=0x10010305
version()=v2.0 [Arduino:XYZ] Mar  5 2016 17:46:52
chipId=0x10010005
Connected at 921600 baud
readWord(addr=0)=0x20007ffc
readWord(addr=0xe000ed00)=0x410cc601
readWord(addr=0x41002018)=0x10010305
Atmel SMART device 0x10010005 found
write(addr=0x20004000,size=0x34)
writeWord(addr=0x20004030,value=0x10)
writeWord(addr=0x20004020,value=0x20008000)
Device       : ATSAMD21G18A
readWord(addr=0)=0x20007ffc
readWord(addr=0xe000ed00)=0x410cc601
readWord(addr=0x41002018)=0x10010305
Chip ID      : 10010005
version()=v2.0 [Arduino:XYZ] Mar  5 2016 17:46:52
Version      : v2.0 [Arduino:XYZ] Mar  5 2016 17:46:52
Address      : 8192
Pages        : 3968
Page Size    : 64 bytes
Total Size   : 248KB
Planes       : 1
Lock Regions : 16
Locked       : readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
readWord(addr=0x41004020)=0xffff
none
readWord(addr=0x41004018)=0
Security     : false
Boot Flash   : true
readWord(addr=0x40000834)=0x7000a
BOD          : true
readWord(addr=0x40000834)=0x7000a
BOR          : true
Arduino      : FAST_CHIP_ERASE
Arduino      : FAST_MULTI_PAGE_WRITE
Arduino      : CAN_CHECKSUM_MEMORY_BUFFER
Erase flash
chipErase(addr=0x2000)
done in 0.831 seconds

Write 10868 bytes to flash (170 pages)
write(addr=0x20005000,size=0x1000)
writeBuffer(scr_addr=0x20005000, dst_addr=0x2000, size=0x1000)

[===========                   ] 37% (64/170 pages)write(addr=0x20005000,size=0x1000)
writeBuffer(scr_addr=0x20005000, dst_addr=0x3000, size=0x1000)

[======================        ] 75% (128/170 pages)write(addr=0x20005000,size=0xa80)
writeBuffer(scr_addr=0x20005000, dst_addr=0x4000, size=0xa80)

[==============================] 100% (170/170 pages)
done in 0.079 seconds

Verify 10868 bytes of flash with checksum.
checksumBuffer(start_addr=0x2000, size=0x1000) = 5295
checksumBuffer(start_addr=0x3000, size=0x1000) = d875
checksumBuffer(start_addr=0x4000, size=0xa74) = c2f9
Verify successful
done in 0.007 seconds
CPU reset.
readWord(addr=0)=0x20007ffc
readWord(addr=0xe000ed00)=0x410cc601
readWord(addr=0x41002018)=0x10010305
writeWord(addr=0xe000ed0c,value=0x5fa0004)
================= [SUCCESS] Took 7.23 seconds ================= 

You can see here that the critical actions are:

  • detect existing COM ports
  • do a reset-into-bootloader procedure by opening the (virtual) COM port at 1200 baud (the bootloader on the Feather M0 will interprete this)
  • detect the newly opened COM port (for the device that is now in bootloader mode)
  • execute the bossac tool to write the actual firmware, with

bossac --info --debug --port “COM12” --write --verify --reset --erase -U true .pio\build\adafruit_feather_m0\firmware.bin

You can write a script in any language you like to do the same thing, and you can package bossac.exe (or the version for your target operating system, local one is at C:\Users\<user>\.platformio\packages\tool-bossac\bossac.exe) with the firmware executable and the upload script.

With the Adafruit Feather M0 and that bootloader however, also one step can be skipped: The reset into bootloader mode can also be done manually by the customer by quickly double-pressing the reset button (and if that button is exposed of course). Then the upload logic becomes a bit simpler.

Example: Using this for getting the last COM port, a prebuilt firmware.bin and bossac.exe and the following script saved as upload.batin the same folder

@echo off
setlocal

rem get last COM port
for /f "delims=" %%I in ('wmic path Win32_SerialPort get DeviceID^,Caption^,Description^,Name^,ProviderType /format:list ^| find "="') do (
    set "%%I"
)

echo Using %DeviceID% for upload
echo Executing "bossac --info --port "%DeviceID%" --write --verify --reset --erase -U true firmware.bin"
bossac --info --port "%DeviceID%" --write --verify --reset --erase -U true firmware.bin

if %ERRORLEVEL% EQU 0 (
   echo Firmware uploaded successfully!
) else (
   echo Error uploading firmware! Code: %errorlevel%
   exit /b %errorlevel%
)

pause

grafik

Double-cliking the batch script will e.g. give

You could also add the 1200bps-reset logic into it, or write it as a Python script to make it portable, or have them use a GUI upload program (most recent version here). You get the gist.

2 Likes

Installing the PlatformIO is definitely too technical. Scripting looks much more approachable, thank you for the details.