Arduino SAMD21 bootloader protection

At IoT – exploration of LoRaWAN – part 2 I reported some quality issues with two low cost SAMD21 Arduino Zero like boards.

In both cases, the bootloader did not work. I did not investigate further but did note that the NVM user row looked like it had been cleared, but just wrote a new bootloader and restored a default user row with protection for the 8192 length bootloader.

Above is one of the culprit boards.

Now I hasten to add that I did not corrupt the bootloader, the boards never enumerated properly on Windows so they arrived with a non-functioning bootloader… but protecting a good bootloader is an important measure for reliability.

Following this up, Arduino 1.8.7 on writing a new bootloader for an Arduino/Genuino Zero using the Atmel-ICE, leaves the bootloader unprotected.

I have listed this as an issue on Github, but it may or may not be fixed, and it might happen sooner or later. (Update 25/10/18: Arduino used protect the bootloader, but a defect in openocd sometimes resulted in an unrecoverable board so they ceased that operation. Later, the underlying defect in openocd was fixed and it properly updates the userrow, but they have chosen to not restore bootloader protection.)

The matter of hardware protection of a bootloader is often discussed, and some argue that not protecting it allows update of the bootloader in place without using special programmer hardware (as would be required with the SMD21). It is this ability of the normal firmware to update the bootloader that is at the risk of ‘bricking’ the device, though some devices thought to be bricked can be recovered with a device programmer.

I consider bootloader protection an important reliability measure, and so I separately apply it using openocd (part of the Arduino install) to run the command sequence:

halt; at91samd nvmuserrow; at91samd nvmuserrow 0xFFFFFC5DD8E0C7FA; reset; at91samd nvmuserrow;

The first nvmuserrow command will display the existing value, the next changes it, and the last reports it back after reset. (You can scrape the command to run openocd from the Arduino IDE log when you install the bootloader, just change the -c parameter as above.

I have decided to reinstall the boot loader and protection on any cheap Chinese SAMD21 boards I buy. Of course that means to buy only boards with the SWD interface conveniently accessible.

J-link solution

If you have a J-link handy, the following is a J-link commander script to unprotect the bootloader, write a new bootloader, and write default userrow with 8k bootloader protection (change the path to the hex file as appropriate).

//display userrow
mem8 0x804000 0x10
//remove boot protection
w1 0x804000 0xff
r
erase
loadfile C:\Users\owen\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.6.19\bootloaders\zero\samd21_sam_ba.hex
// write default userrow with 8k boot protection
w4 0x804000 0xd8e0c7fa
w4 0x804004 0xfffffc5d
w4 0x804008 0xffffffff
w4 0x80400c 0xffffffff
r
mem8 0x804000 0x10

The following is the console output from the script.

J-Link>//display userrow
Unknown command. '?' for help.
J-Link>mem8 0x804000 0x10
00804000 = FA C7 E0 D8 5D FC FF FF FF FF FF FF FF FF FF FF
J-Link>//remove boot protection
Unknown command. '?' for help.
J-Link>w1 0x804000 0xff
Writing FF -> 00804000
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
J-Link: Flash download: Bank 1 @ 0x00804000: 1 range affected (16 bytes)
J-Link: Flash download: Total time needed: 0.077s (Prepare: 0.048s, Compare: 0.002s, Erase: 0.000s, Program: 0.003s, Verify: 0.000s, Restore: 0.022s)
J-Link>erase
Erasing device...
J-Link: Flash download: Total time needed: 0.832s (Prepare: 0.074s, Compare: 0.000s, Erase: 0.709s, Program: 0.000s, Verify: 0.000s, Restore: 0.048s)
J-Link: Flash download: Total time needed: 0.070s (Prepare: 0.046s, Compare: 0.000s, Erase: 0.002s, Program: 0.000s, Verify: 0.000s, Restore: 0.021s)
Erasing done.
J-Link>loadfile C:\Users\owen\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.6.19\bootloaders\zero\samd21_sam_ba.hex
Downloading file [C:\Users\owen\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.6.19\bootloaders\zero\samd21_sam_ba.hex]...
J-Link: Flash download: Bank 0 @ 0x00000000: 1 range affected (6656 bytes)
J-Link: Flash download: Total time needed: 0.210s (Prepare: 0.051s, Compare: 0.017s, Erase: 0.000s, Program: 0.109s, Verify: 0.006s, Restore: 0.025s)
O.K.
J-Link>// write default userrow with 8k boot protection
Unknown command. '?' for help.
J-Link>w4 0x804000 0xd8e0c7fa
Writing D8E0C7FA -> 00804000
J-Link>w4 0x804004 0xfffffc5d
Writing FFFFFC5D -> 00804004
J-Link>w4 0x804008 0xffffffff
Writing FFFFFFFF -> 00804008
J-Link>w4 0x80400c 0xffffffff
Writing FFFFFFFF -> 0080400C
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
J-Link: Flash download: Bank 1 @ 0x00804000: 1 range affected (16 bytes)
J-Link: Flash download: Total time needed: 0.077s (Prepare: 0.048s, Compare: 0.002s, Erase: 0.000s, Program: 0.003s, Verify: 0.000s, Restore: 0.022s)
J-Link>mem8 0x804000 0x10
00804000 = FA C7 E0 D8 5D FC FF FF FF FF FF FF FF FF FF FF
J-Link>

Update 12/11: I have since received two more Wemos SAMD21 mini boards, and neither was recognised by Windows. Replacing and protecting the boot loader rendered the boards usable.