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.
Update: Listing the issue on github was a total waste of space, it was closed within hours with:
we decided to drop protecting the bootloader because
openocd
was bugged and used to write more than the requested register, leading to an unrecoverable board. This is the relevant commit 153d993#diff-d638a47d1ca0e2a5585fb34c7d7fb0f9 . In the meantime we fixed openocd (arduino/OpenOCD@76b0521 and arduino/OpenOCD@76b0521 ) but we decided not to lock the bootloader again so we have the chance to update it on the field without an external programmer.
If you need bootloader protection simply revert the first patch.
So, your could follow that path, or simply done as I have and write the bootloader and protection as decribed above outside of the Arduino IDE.
openocd with ST-LINK V2
There was a problem with openocd until 2017: Arduino Zero – write bootloader leaves bootloader unprotected, this method will work on more recent releases using an inexpensive ST-LINK V2.
Above is the setup to rewrite the bootloader on a Mini M0 clone using a clone ST-LINK V2. The little cable adapter probably cost more than the clone ST-LINK V2.
Start openocd:
set OPENOCD=%USERPROFILE%\.platformio\packages\tool-openocd\bin\openocd.exe %OPENOCD% -f "interface/stlink.cfg" -c "set CHIPNAME at91samd21g18a;set CPUTAPID 0x0bc11477" -f target/at91samdXX.cfg
The following is the console output (via telnet) from the script.
Open On-Chip Debugger > init > halt > at91samd chip-erase chip erase started > reset > halt target halted due to debug-request, current mode: Handler HardFault xPSR: 0x81000003 pc: 0xfffffffe msp: 0xffffffd8 > at91samd nvmuserrow NVMUSERROW: 0xFFFFFC5DD8E0C7FA > at91samd bootloader 0 > reset > halt target halted due to debug-request, current mode: Handler HardFault xPSR: 0x81000003 pc: 0xfffffffe msp: 0xffffffd8 > at91samd nvmuserrow NVMUSERROW: 0xFFFFFC5DD8E0C7FF > > program "C:\\Users\\owen\\.platformio\\packages\\framework-arduino-samd\\bootloaders\\mzero\\Bootloader_D21_M0_150515.hex" verify target halted due to debug-request, current mode: Thread xPSR: 0x81000000 pc: 0xfffffffe msp: 0xfffffffc ** Programming Started ** Flash write discontinued at 0x00003380, next section at 0x00004000 ** Programming Finished ** ** Verify Started ** ** Verified OK ** > > at91samd bootloader 8192 > reset > halt target halted due to debug-request, current mode: Thread xPSR: 0x81000000 pc: 0x000041d8 msp: 0x20007fd0 > at91samd nvmuserrow NVMUSERROW: 0xFFFFFC5DD8E0C7FA > #shutdown
More: Arduino SAMD21 bootloader protection II.