ATSAMD21E18A - cannot write user_word_0 when BOOTPROT is on
When BOOTPROT (bits 2:0 of user_word_0) is set to anything other than 7 (default, boot protect off), I cannot write to byte 0 of the user_word. If it is set to 7, I can successfully write a different value to it, for example 0xFA, which enables boot protection for 8192 Bytes. I can change byte 0 back to 0xFF using the Microchip Studio programmer interface, and then can write to it again with pymcuprog.
pymcuprog does not report any error and says the write is complete, but when I read the value back it has not changed. I also confirmed with Microchip Studio that the value did not change.
Testing on Windows 11 with Python 3.13.3. pymcuprog version 3.19.4.61 programmer dongle: Atmel-ICE
Below are the steps to reproduce.
PS C:\Users\russf> pymcuprog -d atsamd21e18a read -m user_row -b 8
Connecting to anything possible
Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700063793)
Debugger firmware version 1.42.161
Debugger hardware revision 0
Pinging device...
Ping response: 1001031C
Reading...
Memory type: user_row
---------------------------------------------------------
0x804000: FF C7 E0 D8 5D FC FF FF xx xx xx xx xx xx xx xx
---------------------------------------------------------
Done.
PS C:\Users\russf> pymcuprog write -U -d atsamd21e18a -m user_row -l 0xFA -v debug
Connecting to anything possible
Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700063793)
Debugger firmware version 1.42.161
Debugger hardware revision 0
pymcuprog.programmer - INFO - Setting up programming session for 'atsamd21e18a'
pymcuprog.deviceinfo.deviceinfo - INFO - Looking for device atsamd21e18a
pymcuprog.nvm - INFO - SAM-M0+ stack is in Beta state
pymcuprog.samtarget - INFO - Target voltage read out: 2.53V
pymcuprog.samtarget - INFO - Connecting to SAMD2x DAP
pymcuprog.samtarget - INFO - Using SWD CLK of 2000000 Hz
pymcuprog.nvm - DEBUG - No specific initializer for this provider
Writing literal values...
pymcuprog.programmer - INFO - Write...
pymcuprog.programmer - INFO - Writing 1 bytes of data to user_row...
pymcuprog.samtarget - DEBUG - Is device locked?
pymcuprog.nvm - DEBUG - Writing 4 bytes to address 0x804000
pymcuprog.programmer - INFO - Write complete.
Done.
PS C:\Users\russf> pymcuprog -d atsamd21e18a read -m user_row -b 8
Connecting to anything possible
Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700063793)
Debugger firmware version 1.42.161
Debugger hardware revision 0
Pinging device...
Ping response: 1001031C
Reading...
Memory type: user_row
---------------------------------------------------------
0x804000: FA C7 E0 D8 5D FC FF FF xx xx xx xx xx xx xx xx
---------------------------------------------------------
Done.
PS C:\Users\russf> pymcuprog write -U -d atsamd21e18a -m user_row -l 0xFF -v debug
Connecting to anything possible
Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700063793)
Debugger firmware version 1.42.161
Debugger hardware revision 0
pymcuprog.programmer - INFO - Setting up programming session for 'atsamd21e18a'
pymcuprog.deviceinfo.deviceinfo - INFO - Looking for device atsamd21e18a
pymcuprog.nvm - INFO - SAM-M0+ stack is in Beta state
pymcuprog.samtarget - INFO - Target voltage read out: 2.56V
pymcuprog.samtarget - INFO - Connecting to SAMD2x DAP
pymcuprog.samtarget - INFO - Using SWD CLK of 2000000 Hz
pymcuprog.nvm - DEBUG - No specific initializer for this provider
Writing literal values...
pymcuprog.programmer - INFO - Write...
pymcuprog.programmer - INFO - Writing 1 bytes of data to user_row...
pymcuprog.samtarget - DEBUG - Is device locked?
pymcuprog.nvm - DEBUG - Writing 4 bytes to address 0x804000
pymcuprog.programmer - INFO - Write complete.
Done.
PS C:\Users\russf> pymcuprog -d atsamd21e18a read -m user_row -b 8
Connecting to anything possible
Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700063793)
Debugger firmware version 1.42.161
Debugger hardware revision 0
Pinging device...
Ping response: 1001031C
Reading...
Memory type: user_row
---------------------------------------------------------
0x804000: FA C7 E0 D8 5D FC FF FF xx xx xx xx xx xx xx xx
---------------------------------------------------------
Done.
PS C:\Users\russf>
After posting this issue I figured out that I can erase the user row first, and then write the complete user row again. So this will accomplish my goal, but I am not sure if this is the intended method or a limitation of the chip. It's possible that the Microchip Studio programmer does an erase and re-writes the whole user row in the background without the user seeing it.
Interesting observation - I would expect that the "failure to fail" is probably that the Atmel-ICE is not picking up the error. In general I would recommend a --verify to post-verify (which should pick up the failure?) We use this for manufacturing of CNANOs (which is really why we have SAMD21 support in the otherwise-8-bit utility), and thus don't exercise all corner cases.
Thanks, I tried the write user row with --verify option and it does return an error, so at least that works. I was using atprogram.exe on Windows and wanted a Linux substitute - that's how I found this utility. Anyway it's working for me now as long as I erase the user row first, then reprogram it.
same problem here, how did you erase the user row?
i used pymcuprog erase -d atsamd21e18a -m user_row
so my device had 0x5D D8 E0 C7 FF
after erase it was 0x5D D8 E0 C7 FA
shouldn't the default value be "0x7 - 0bytes" for bootprot or do i mix something up? and i cannot write 0xFF to the first byte after the erase neither.
pymcuprog write -d atsamd21e18a -m user_row -o 0 -l 0xFF --verify
Connecting to anything possible
Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700037806)
Debugger firmware version 1.41.137
Debugger hardware revision 0
Pinging device...
Ping response: 1001030A
Writing literal values...
Verifying literal values...
pymcuprog.programmer - ERROR - Verify failed for user_row memory:
pymcuprog.programmer - ERROR - Verify mismatch starting at location 0x000000: 0xFF vs 0xFA (is the memory section erased?)
Done.
same problem here, how did you erase the user row? i used
pymcuprog erase -d atsamd21e18a -m user_rowso my device had0x5D D8 E0 C7 FFafter erase it was0x5D D8 E0 C7 FAshouldn't the default value be "0x7 - 0bytes" for bootprot or do i mix something up? and i cannot write 0xFF to the first byte after the erase neither.
pymcuprog write -d atsamd21e18a -m user_row -o 0 -l 0xFF --verify Connecting to anything possible Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700037806) Debugger firmware version 1.41.137 Debugger hardware revision 0 Pinging device... Ping response: 1001030A Writing literal values... Verifying literal values... pymcuprog.programmer - ERROR - Verify failed for user_row memory: pymcuprog.programmer - ERROR - Verify mismatch starting at location 0x000000: 0xFF vs 0xFA (is the memory section erased?) Done.
Hi Knochi, it's working for me using the below commands:
Commands for pymcuprog usage with ATSAMR21e18a:
Read user row: pymcuprog read -d atsamd21e18a -m user_row -b 8
Erase full user row (user_word_0 and user_word_1): pymcuprog erase -d atsamd21e18a -m user_row
write user row with BOOTPROT OFF: pymcuprog write -d atsamd21e18a -m user_row -l 0xFF 0xC7 0xE0 0xD8 0x5D 0xFC 0xFF 0xFF
Program bootloader with erase first and verify: pymcuprog -d atsamd21e18a write --verify --erase -f <PATH TO BL IMAGE>
Program application with verify: pymcuprog -d atsamd21e18a write --verify -f <PATH TO FW IMAGE>
write user row with BOOTPROT ON for 8192 Bytes: pymcuprog write -d atsamd21e18a -m user_row -l 0xFA 0xC7 0xE0 0xD8 0x5D 0xFC 0xFF 0xFF
Doesn't work.. userrow stays at 0xFA ...
PS \GIT> pymcuprog erase -d atsamd21e18a -m user_row
Connecting to anything possible
Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700066741)
Debugger firmware version 1.41.137
Debugger hardware revision 0
Pinging device...
Ping response: 1001030A
Erasing user_row...
Erased.
Done.
PS \GIT> pymcuprog write -d atsamd21e18a -m user_row -l 0xFF 0xC7 0xE0 0xD8 0x5D 0xFC 0xFF 0xFF
Connecting to anything possible
Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700066741)
Debugger firmware version 1.41.137
Debugger hardware revision 0
Pinging device...
Ping response: 1001030A
Writing literal values...
Done.
PS \GIT> pymcuprog read -d atsamd21e18a -m user_row -b 8
Connecting to anything possible
Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700066741)
Debugger firmware version 1.41.137
Debugger hardware revision 0
Pinging device...
Ping response: 1001030A
Reading...
Memory type: user_row
---------------------------------------------------------
0x804000: FA C7 E0 D8 5D FC FF FF xx xx xx xx xx xx xx xx
---------------------------------------------------------
tried to read the current userrow into a file, modify (including checksum) and write that file back with the --erase option.
PS \GIT> pymcuprog write -d atsamd21e18a -f .\user_row_open.hex --erase --verify
Connecting to anything possible
Connected to Atmel-ICE CMSIS-DAP from ATMEL (serial number J42700066741)
Debugger firmware version 1.41.137
Debugger hardware revision 0
Pinging device...
Ping response: 1001030A
Erasing device before writing from hex file...
Writing from hex file...
Writing user_row...
Verifying user_row...
pymcuprog.programmer - ERROR - Verify failed for user_row memory:
pymcuprog.programmer - ERROR - Verify mismatch starting at location 0x000000: 0xFF vs 0xFA (is the memory section erased?)
Verification failed!
Done.
This not only didn't work but it seems that it erased other content as well, since the program, that was previously running, doesn't work.
~Now it worked!~ ~seems like you need to do a reset pymcu reset -d atsamd21e18a after erase~
[Edit] Seems like you have to erase the whole memory to be able to erase the user row. The read command should give an FF for all bytes before you can write the new user_row.
and when writing the bootloader (trinket M0 from adafruit) i need to add the memory address "flash".
So all in all:
#Check connection to target
pymcuprog ping -d atsamd21e18a
#If voltage <3.0V check cabling or replace the ribbon cable
pymcuprog getvoltage
#read 8 bytes from user row - if it starts with FA you have to erase memory and rewrite
pymcuprog read -d atsamd21e18a -m user_row -b 8
#erase all
pymcuprog erase -d atsamd21e18a
#erase user row
pymcuprog erase -d atsamd21e18a -m user_row
#reset target
pymcuprog reset -d atsamd21e18a
#user_row should now be FF on all positions
pymcuprog read -d atsamd21e18a -m user_row -b 8
#write complete userrow with Bootprotection OFF
pymcuprog write -d atsamd21e18a -m user_row -l 0xFF 0xC7 0xE0 0xD8 0x5D 0xFC 0xFF 0xFF
#write trinket bootloader from adafruit to flash memory
pymcuprog write -d atsamd21e18a --verify --erase -f bootloader-trinket_m0-v3.16.0.bin -m flash
#optional. Alternatively you can load the application via UF2 later
pymcuprog -d atsamd21e18a write --verify -f yourProgram.hex
#write complete userrow with Bootprotection ON for 8kB
pymcuprog write -d atsamd21e18a -m user_row -l 0xFA 0xC7 0xE0 0xD8 0x5D 0xFC 0xFF 0xFF
Yes sorry, I cycle the power after erasing and writing the user row (maybe reset works too).
My complete sequence is:
- erase user row
- write user row with boot prot off (must write full user row because it’s been erased)
- cycle power (I think I read in the datasheet that a power cycle is required after user row changes -my python script can control the power supply in my setup)
- write bootloader image with erase first
- write application image
- write full user row with boot prot on
- hardware reset.
Best, Russ
Power cycle doesn't help. I need to erase ALL before i can erase the userrow