QT Py SAMD21 Bootloader Protection
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- danhalbert
- Posts: 4655
- Joined: Tue Aug 08, 2017 12:37 pm
Re: QT Py SAMD21 Bootloader Protection
I will be working on enabling BOD; feel free to subscribe to the issue if you have not already.
- danhalbert
- Posts: 4655
- Joined: Tue Aug 08, 2017 12:37 pm
Re: QT Py SAMD21 Bootloader Protection
Update:
I got a couple of QT Py M0's of about the same vintage as what you have. They came with the bootloader unprotected, BOOTPROT = 0x7. They came with bootloader 3.14.0. Loading update-bootloader-QTPy_m0-v3.14.0.uf2 on them successfully changes BOOTPROT to 0x2.
I should be receiving your RMA'd QT Py's very soon, and will take a look at them.
I am testing some BOD33 code for the bootloader right now.
I got a couple of QT Py M0's of about the same vintage as what you have. They came with the bootloader unprotected, BOOTPROT = 0x7. They came with bootloader 3.14.0. Loading update-bootloader-QTPy_m0-v3.14.0.uf2 on them successfully changes BOOTPROT to 0x2.
I should be receiving your RMA'd QT Py's very soon, and will take a look at them.
I am testing some BOD33 code for the bootloader right now.
- danhalbert
- Posts: 4655
- Joined: Tue Aug 08, 2017 12:37 pm
Re: QT Py SAMD21 Bootloader Protection
Hi leafon,
I received your two RMA's QT Py M0's. They are packaged identically to the two I got from Mouser: same kind of bag, exact same label.
I understand you are probably using a Mac, so I tested this on a Mac Mini M1 running Ventura 13.2.
1. The Qt Py out of the bag runs a NeoPixel "swirl" program that changes the color of the NeoPixel rapidly.
2. I loaded the print_samd21_fuses.uf2 file attached in a post above, by double-clicking and then dragging in the Finder to QTPY_BOOT. Then I used tio to monitor the serial port to see what the fuse printer was printing. As with the previous samples I found, the fuses show no BOOTPROT protection (which is a mistake):
3. I then double-clicked again, and dragged https://github.com/adafruit/uf2-samdx1/ ... 3.14.0.uf2 to QTPY_BOOT.
4. After step 3, I waited about 10 seconds until the NeoPixel turned from off to green, showing that the bootloader had restarted.
5. I reloaded print_samd21_fuses.uf2. It prints
showing that BOOTPROT is now set correctly.
I repeated the above with the second RMA'd QT Py, except that I used `cp` instead of the Finder. I got the same result.
If I understand correctly, you did the same thing as above, but when you loaded print_samd21_fuses.uf2, it showed no change. If you did what I did, I am at loss to explain why it consistently does not fix BOOTPROT for you, and it consistently does fix BOOTPROT for me.
A few questions:
a. Are you waiting in step 4 for the NeoPixel to turn green? This takes a little while.
b. Are you on a Mac as described? Is it running Ventura 13.2 or something else? There was a bug in 13.0 and 13.01 related to copying UF2's via the Finder, but it's fairly obvious: you would have seen an error. See https://blog.adafruit.com/2022/10/31/up ... uitpython/ for background on this.
I received your two RMA's QT Py M0's. They are packaged identically to the two I got from Mouser: same kind of bag, exact same label.
I understand you are probably using a Mac, so I tested this on a Mac Mini M1 running Ventura 13.2.
1. The Qt Py out of the bag runs a NeoPixel "swirl" program that changes the color of the NeoPixel rapidly.
2. I loaded the print_samd21_fuses.uf2 file attached in a post above, by double-clicking and then dragging in the Finder to QTPY_BOOT. Then I used tio to monitor the serial port to see what the fuse printer was printing. As with the previous samples I found, the fuses show no BOOTPROT protection (which is a mistake):
Code: Select all
0x804000: 0xD8E0C7FF
0x804004: 0xFFFFFC5D
4. After step 3, I waited about 10 seconds until the NeoPixel turned from off to green, showing that the bootloader had restarted.
5. I reloaded print_samd21_fuses.uf2. It prints
Code: Select all
0x804000: 0xD8E0C7FA
0x804004: 0xFFFFFC5D
I repeated the above with the second RMA'd QT Py, except that I used `cp` instead of the Finder. I got the same result.
If I understand correctly, you did the same thing as above, but when you loaded print_samd21_fuses.uf2, it showed no change. If you did what I did, I am at loss to explain why it consistently does not fix BOOTPROT for you, and it consistently does fix BOOTPROT for me.
A few questions:
a. Are you waiting in step 4 for the NeoPixel to turn green? This takes a little while.
b. Are you on a Mac as described? Is it running Ventura 13.2 or something else? There was a bug in 13.0 and 13.01 related to copying UF2's via the Finder, but it's fairly obvious: you would have seen an error. See https://blog.adafruit.com/2022/10/31/up ... uitpython/ for background on this.
- leafon
- Posts: 32
- Joined: Thu Sep 22, 2022 12:40 am
Re: QT Py SAMD21 Bootloader Protection
Hi Dan,
Thank you very much for looking into this issue on a weekend!
I repeated exactly what you did and confirmed the SAMD21 fuses changed to:
0x804000: 0xD8E0C7FA
0x804004: 0xFFFFFC5D
What I did incorrectly previously was not waiting long enough after step 3. I only waited a few seconds after copying the uf2 file over and the drive disappears from Finder. Previously, when I modified and compiled the uf2-samdx1 source code and copied the uf2 file (using the uf2conv.py script on the bin file) to the QT Py, I didn't need to wait ~10 seconds for the bootloader to update.
On this particular machine, I'm using Monterey (12.6.2).
After step 5, I flashed the QT Py with my own uf2 file and confirmed with JLink the fuses are still
0x804000: 0xD8E0C7FA
0x804004: 0xFFFFFC5D
So for the next step, after you make the changes to BOD33, do I need to update every QT Py board twice?
1. Update with the update-bootloader-QTPy_m0-v3.15.0.uf2 file to enable BOD33 and bootloader protection.
2. Update with my own uf2 file
Thank you very much for looking into this issue on a weekend!
I repeated exactly what you did and confirmed the SAMD21 fuses changed to:
0x804000: 0xD8E0C7FA
0x804004: 0xFFFFFC5D
What I did incorrectly previously was not waiting long enough after step 3. I only waited a few seconds after copying the uf2 file over and the drive disappears from Finder. Previously, when I modified and compiled the uf2-samdx1 source code and copied the uf2 file (using the uf2conv.py script on the bin file) to the QT Py, I didn't need to wait ~10 seconds for the bootloader to update.
On this particular machine, I'm using Monterey (12.6.2).
After step 5, I flashed the QT Py with my own uf2 file and confirmed with JLink the fuses are still
0x804000: 0xD8E0C7FA
0x804004: 0xFFFFFC5D
So for the next step, after you make the changes to BOD33, do I need to update every QT Py board twice?
1. Update with the update-bootloader-QTPy_m0-v3.15.0.uf2 file to enable BOD33 and bootloader protection.
2. Update with my own uf2 file
- danhalbert
- Posts: 4655
- Joined: Tue Aug 08, 2017 12:37 pm
Re: QT Py SAMD21 Bootloader Protection
Yes, because the update-bootloader uf2 in 1. will overwrite whatever program is there.
Here is a PR that adds the BOD33 protection and removes that long delay before restarting for update-bootloader:
https://github.com/adafruit/uf2-samdx1/pull/198
And here are test builds for you: Do you have an easy way to test the BOD33 enabling? I tested it with a Nordic PPK2 power profiler on a Feather M0, lowering the voltage until it did not restart. I have a minor thing to fix there, because it left the NeoPixel on, which isn't great if the battery is low.
- leafon
- Posts: 32
- Joined: Thu Sep 22, 2022 12:40 am
Re: QT Py SAMD21 Bootloader Protection
Thank you Dan!
I'll try the test build right away!
What's the threshold level you set for the BOD33? Perhaps we can test it by try another build that enables the BOD33 and disables the bootloader protection, then methodically power cycles the SAMD21.
I'll try the test build right away!
What's the threshold level you set for the BOD33? Perhaps we can test it by try another build that enables the BOD33 and disables the bootloader protection, then methodically power cycles the SAMD21.
- danhalbert
- Posts: 4655
- Joined: Tue Aug 08, 2017 12:37 pm
Re: QT Py SAMD21 Bootloader Protection
The BOD33 level is 39, which is about 2.8V. External flash chips, like the one on the QT Py, are usually specified foto require at least 2.7V.
Here is a build that has BOD33 but leaves the bootloader unprotected: With the SAMD51, without BOD33, we still got internal flash erases, but they did not erase the BOOTPROT region. They did erase the beginning of the program, just past the BOOTPROT area.
Here is a build that has BOD33 but leaves the bootloader unprotected: With the SAMD51, without BOD33, we still got internal flash erases, but they did not erase the BOOTPROT region. They did erase the beginning of the program, just past the BOOTPROT area.
- leafon
- Posts: 32
- Joined: Thu Sep 22, 2022 12:40 am
Re: QT Py SAMD21 Bootloader Protection
Hi Dan,
Regarding the files you provided earlier: QTPy-BOD33.zip.
I noticed if I flash a QT Py board with corrupted bootloader with the "bootloader-QTPy_m0-v3.14.0-12-g6451787.bin" file, it doesn't update the fuses. Is that the correct behavior?
Only after I copy the "update-bootloader-QTPy_m0-v3.14.0-12-g6451787.uf2" to QT Py, it updates the fuses to enable the bootloader protection.
Regarding the files you provided earlier: QTPy-BOD33.zip.
I noticed if I flash a QT Py board with corrupted bootloader with the "bootloader-QTPy_m0-v3.14.0-12-g6451787.bin" file, it doesn't update the fuses. Is that the correct behavior?
Only after I copy the "update-bootloader-QTPy_m0-v3.14.0-12-g6451787.uf2" to QT Py, it updates the fuses to enable the bootloader protection.
- danhalbert
- Posts: 4655
- Joined: Tue Aug 08, 2017 12:37 pm
Re: QT Py SAMD21 Bootloader Protection
That's right, the bootloader itself only updates the fuses if the first fuse word has been reset to all ones (0xffffffff). This would reflect that the fuse page has been completely erased but not rewritten. If the fuses are all ones, it enables the watchdog timer with a short period, which will cause a boot loop after a few seconds. So we check for that, but not other things. We don't necessarily want to second-guess the user who may have wanted to undo the BOOTPROT for other reasons, such as rewriting the bootloader without erasing the whole chip.
The bootloader updater also only resets the fuses to "reasonable values" if the first fuse word is 0xffffffff. Again this is to handle the case that the user wants an unusual fuse configuration. But it does always set the BOOTPROT properly, because that's usually what people want, and because uploading the updater replaces any existing program.
The bootloader updater also only resets the fuses to "reasonable values" if the first fuse word is 0xffffffff. Again this is to handle the case that the user wants an unusual fuse configuration. But it does always set the BOOTPROT properly, because that's usually what people want, and because uploading the updater replaces any existing program.
- danhalbert
- Posts: 4655
- Joined: Tue Aug 08, 2017 12:37 pm
Re: QT Py SAMD21 Bootloader Protection
https://github.com/adafruit/uf2-samdx1/ ... ag/v3.15.0 has the changes in the test version I gave you.
- leafon
- Posts: 32
- Joined: Thu Sep 22, 2022 12:40 am
Re: QT Py SAMD21 Bootloader Protection
The v3.15.0 bootloader does not have code to set the bootloader protection if it is off. There is a catch-22 with how the update-bootloader UF2 works. However, if you update with any update-bootloader UF2, it will enable the bootloader protection. The v3.15.0 update-bootloader does not spend time flashing the status LED and waiting until the flashing is done before writing the BOOTPROT, which is what was confusing before. So it will finish much faster. When you see QTPY_BOOT again, BOOTPROT will be enabled.So the bootloader protection is still off by default in v3.15.0?
Please be positive and constructive with your questions and comments.