QT Py SAMD21 Bootloader Protection

For Adafruit customers who seek help with microcontrollers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
leafon
 
Posts: 32
Joined: Thu Sep 22, 2022 12:40 am

QT Py SAMD21 Bootloader Protection

Post by leafon »

Hi,

I came across this blog yesterday.

https://blog.thea.codes/sam-d21-brown-out-detector/

It appears the bootloader protection on the QT Py SAMD21 isn't enabled by default.

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: QT Py SAMD21 Bootloader Protection

Post by adafruit_support_mike »

That's correct.

It's a design tradeoff: with memory protection enabled, the bootloader wouldn't be able to update itself when a newer version is released. You'd have to use a JTAG programmer to disable memory protection, then flash the new bootloader.

User avatar
leafon
 
Posts: 32
Joined: Thu Sep 22, 2022 12:40 am

Re: QT Py SAMD21 Bootloader Protection

Post by leafon »

Thanks Mike.

So when I use the uf2conv.py script (from https://github.com/microsoft/uf2/tree/master/utils) to generate the uf2 files from the bin file, and update a QT Py, does the bootloader get updated?

Is there a way to enable to the bootloader protection and enable the brown-out detector without using the SAMD21's SWD interface?

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: QT Py SAMD21 Bootloader Protection

Post by adafruit_support_mike »

leafon wrote: Mon Jan 23, 2023 9:06 pm So when I use the uf2conv.py script (from https://github.com/microsoft/uf2/tree/master/utils) to generate the uf2 files from the bin file, and update a QT Py, does the bootloader get updated?
Yes.
leafon wrote: Mon Jan 23, 2023 9:06 pm Is there a way to enable to the bootloader protection and enable the brown-out detector without using the SAMD21's SWD interface?
Nope. You have to set fuses to enable those features, and that can only be done through the JTAG interface.

User avatar
leafon
 
Posts: 32
Joined: Thu Sep 22, 2022 12:40 am

Re: QT Py SAMD21 Bootloader Protection

Post by leafon »

According to this blog: https://blog.thea.codes/sam-d21-brown-out-detector/

"I had assumed that the bootloader we use, uf2-samdx1, would enable bootloader protection automatically. It turns out that isn't the whole story- it only enables bootloader protection in two cases:

The bootloader protection configuration is invalid
The bootloader has updated itself"

So if I update the bootloader with a new uf2 file, wouldn't the bootloader protection be turned on?

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: QT Py SAMD21 Bootloader Protection

Post by adafruit_support_mike »

The chip can't write new data to the bootloader memory if protection for that block is turned on.

By that definition, it's impossible for the bootloader to update itself if the memory is protected. The goals are mutually exclusive. You can have one or the other, but not both.

User avatar
leafon
 
Posts: 32
Joined: Thu Sep 22, 2022 12:40 am

Re: QT Py SAMD21 Bootloader Protection

Post by leafon »

Thank you.

On a related topic, how do I enable the brown-out detector on SAMD21?
Do I modify this file: https://github.com/adafruit/uf2-samdx1/ ... src/main.c

It appears the brown-out detector is enabled for SAMD51 and disabled for SAMD21 by default. Why is that the case?

User avatar
adafruit2
 
Posts: 22111
Joined: Fri Mar 11, 2005 7:36 pm

Re: QT Py SAMD21 Bootloader Protection

Post by adafruit2 »

we dont recall - it could have been an error in programming. we can look to see if its possible to enable it post-install!

User avatar
leafon
 
Posts: 32
Joined: Thu Sep 22, 2022 12:40 am

Re: QT Py SAMD21 Bootloader Protection

Post by leafon »

To summarize, could you please answer the following questions?

1. On the existing QT Py M0 boards, is the only way to enable the bootloader protection is to use the SWD interface and set the fuses?
2. Is it possible to use the .uf2 file update method to enable the brown out detector?
3. If we were to update the QT Py M0 boards using the SWD interface to flash the .bin file, how do we modify the files at https://github.com/adafruit/uf2-samdx1
to enable the brown out detector and boot loader protection?

User avatar
danhalbert
 
Posts: 4613
Joined: Tue Aug 08, 2017 12:37 pm

Re: QT Py SAMD21 Bootloader Protection

Post by danhalbert »

I would suggest doing #2, since that should enable the bootloader protect fuse. If you do #3, just use the updater UF2 as you would do for #2, and rewrite the bootloader. That is easier than building a new bootloader.

I looked at the three QT Py M0's that I have, and they all have these fuse values:

Code: Select all

D800C772
FFFF005D
It's been a while since I looked at this, but I believe the '2' indicates BOOTPROT is set to protect the first 8kB, as described in the datasheet. Here is a short Arduino program to report the current fuse values:

Code: Select all

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
}

void loop() {
  // Reasonable fuse values, set by the fuse repairer in the UF2 bootloader,
  // but not necessarily what you will encounter from the factory.
  // [0] 0xD8E0C7FA
  // [1] 0xFFFFFC5D

  uint32_t fuse0 = ((uint32_t *)NVMCTRL_AUX0_ADDRESS)[0];
  uint32_t fuse1 = ((uint32_t *)NVMCTRL_AUX0_ADDRESS)[1];

  Serial.println(fuse0, HEX);
  Serial.println(fuse1, HEX);
  Serial.println();
  delay(2000);
}

User avatar
danhalbert
 
Posts: 4613
Joined: Tue Aug 08, 2017 12:37 pm

Re: QT Py SAMD21 Bootloader Protection

Post by danhalbert »

Mike, I believe we do enable BOOTPROT, since the bootloader updater can turn it off if desired.

User avatar
danhalbert
 
Posts: 4613
Joined: Tue Aug 08, 2017 12:37 pm

Re: QT Py SAMD21 Bootloader Protection

Post by danhalbert »

Re the brownout detector: we saw the spurious write problems that smashed things on low-voltage power up only on the SAMD51. One the SAMD21, enabling the brownout detector might cause the board not to boot when voltage was marginal, and some people might want to operate at marginal voltage. So if I remember right, we decided not to eliminate that possibility for the SAMD21, since we hadn't seen any bootloader smashing on SAMD21.

But it appears from your experiences and Thea's, that was an incorrect assumption.
https://github.com/adafruit/uf2-samdx1/issues/170

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: QT Py SAMD21 Bootloader Protection

Post by adafruit_support_mike »

danhalbert wrote: Wed Jan 25, 2023 10:53 pm Mike, I believe we do enable BOOTPROT, since the bootloader updater can turn it off if desired.
Thanks for the correction Dan!

User avatar
leafon
 
Posts: 32
Joined: Thu Sep 22, 2022 12:40 am

Re: QT Py SAMD21 Bootloader Protection

Post by leafon »

Dan,

Thank you for looking into this.

I can assure you that the BOOTPROT is disabled on the QT Py M0 boards.

I connected a brand new QT Py M0 board to a J-Link and dumped its flash content. As you can see, the BOOTPROT[2:0] is 0x7.
QT Py NVM.png
QT Py NVM.png (14.78 KiB) Viewed 231 times
This matches what's on line 73 to 75 of the selfmain.c file:
https://github.com/adafruit/uf2-samdx1/ ... selfmain.c

#if defined(SAMD21)
fuses[0] = 0xD8E0C7FF;
fuses[1] = 0xFFFFFC5D;

User avatar
danhalbert
 
Posts: 4613
Joined: Tue Aug 08, 2017 12:37 pm

Re: QT Py SAMD21 Bootloader Protection

Post by danhalbert »

Hmm, yes, but further down in selfmain.c, the FF value is changed to the passed in `bootprot` value:
https://github.com/adafruit/uf2-samdx1/ ... .c#L96-L97

Code: Select all

    // Update fuses BOOTPROT value with desired value.
    fuses[0] = (fuses[0] & ~NVMCTRL_FUSES_BOOTPROT_Msk) | (new_bootprot << NVMCTRL_FUSES_BOOTPROT_Pos);
Further down, in `main()`, at line 147, this routine is called to turn off BOOTPROT:

Code: Select all

#ifdef SAMD21
    // Disable BOOTPROT while updating bootloader.
    set_fuses_and_bootprot(7); // 0k - See "Table 22-2 Boot Loader Size" in datasheet.
#endif
Then, after the updated bootloader is written, BOOTPROT is set to 8k (line 204 ff.)

Code: Select all

#ifdef SAMD21
    // Re-enable BOOTPROT
    set_fuses_and_bootprot(2); // 8k
#endif
In any case, this code is in selfmain.c, which is used only by the update-bootloader UF2. If you load one of those UF2's, you'll find that the fuses are set properly. I ran https://github.com/adafruit/uf2-samdx1/ ... 3.14.0.uf2 on on one my QT Py's, and after running, the fuses are:

Code: Select all

D800C772
FFFF005D
-------------------------------------

The code above is not used at the factory when the initial bootloader is programmed. There is a separate non-published program that takes the original bootloader .bin file. It is supposed to fix up BOOTPROT afterwards, and it appears it is not. I will investigate that. Thank you very much for finding this.

In the meantime, you can fix BOOTPROT all your QT Py M0's by running the update-bootloader .UF2 linked to above. I realize this is tedious, and am sorry for this. Of course try one or two to confirm.

-------------------------------------

This does not address the brownout issue. That is something separate we perhaps should address in the bootloader, or in startup code. What code are you running on these QT Py's? Is it Arduino-based, or is it custom ASF3 or ASF4 or other firmware?

Locked
Please be positive and constructive with your questions and comments.

Return to “Microcontrollers”