adafruit / uf2-samdx1

MSC bootloader (based on UF2) for SAMD21
Other
214 stars 187 forks source link

running SAMD21 lower than 2.2v #119

Closed humansthatmake closed 3 years ago

humansthatmake commented 4 years ago

Hi there,

I'm using a feather board, and I'm trying to run the SAMD21 at lower voltages (1.8v), but when I try lower than 2.2v the chips locks (bricks). I then went for Atmel Studio and used a programmer to try to disable the BOD33 fuses and the same result happened. Is there something on this bootloader that limits the SAMD operation to a minimum of 2.2v? Is this bootloader trying to set the fuses as well?

thank you for your support

dhalbert commented 4 years ago

The Feather is not designed for operation below 3.3V, Are you feeding the 3V pin directly? Otherwise you'll be running your low voltage through the regulator, the protection diodes, etc.

We have not tested the board running at such low voltages and make no guarantees about taht.

The bootloader for SAMD21 doesn't set the fuses unless the first fuse word is 0xFFFFFFFF, which is an indicator that the fuses have been erased and not reset to a reasonable value. The SAMD51 code waits for the voltage to be at least 2.7V, because we have seen bad behavior at lower voltages (internal flash sporadically has certain locations cleared to zeroes).

humansthatmake commented 4 years ago

Hi Dhalbert,

I understand Feather might not be designed in theory for that, but in reality, from your online schematics, I saw that we can feed the SAMD21 directly using the 3v pin on the feather.

Also, the SAMD21 datasheet refers that the chip works between 1.6 and 3.6v. So, it should be possible to make it work at 1.8v, even on the feather, as I saw no limitation to that on the schematic design.

The only limitation I was able to foresee was the BOD33 limiting the lower threshold, which I also disabled using a programmer.

So, now, I ran out of ideas to run the SAMD21 at lower voltages...

Is there a way we can thinker a way of working at lower voltages? I'm saying this because 1.8v is the new low power standard and some people might benefit from having this capability.

dhalbert commented 4 years ago

If you are feeding into the 3V pin, that's correct. And if you have cleared the BOD33 ENABLEfuse flag as listed below that would be what to do.

Power cycle the board and try to read back the fuse values. Below is a simple Arduino sketch that will print the fuse values. Make sure BOD33 ENABLE is really 0. I have had trouble with J-LInk not writing the fuse values correctly. After consulting with them say you must write a quadword to the fuses all at once. My dialogue with them is ongoing.

1.8V should work, but are you testing with, say a simple Blink-style program, or do you have peripherals connected? Are you using Arduino? Looking in the Arduino core, I don't see that Arduino cares about BOD33 at all.

uint32_t* NVMCTRL_USER_PAGE_32P = (uint32_t*) NVMCTRL_USER;

void setup() {
  while (!Serial) {}
  Serial.begin(9600);
}

void loop() {
  for (size_t i = 0; i <= 3; i++) {
    Serial.println(NVMCTRL_USER_PAGE_32P[i], HEX);
  }
  Serial.println();
  delay(1000);
}

image

humansthatmake commented 4 years ago

These are the fuses I read from SAMD21 using Atmel-ICE with Atmel Studio:
Capturar

If you look under USER_WORD_0.BOD33USERLEVEL the value is 0x07 which according to SAMD21 datasheet is around 1.7v.
Screenshot 2020-05-15 at 20 11 06

Then, on the same SAMD21, I ran your code and got these values on the serial monitor:

D8E007FA FFFFFC5D FFFFFFFF FFFFFFFF

By converting the first byte (D8E007FA) to binary I got this: 11011000111000000000011111111010

Which, according to the datasheet it should breakdown like this:

Screenshot 2020-05-15 at 20 23 39

BOD33 level is now 38. Let me know if I'm seeing this right.

If so, the value on the Atmel Studio is not the same when running Arduino IDE. This leads me to think that fuses are being changed along the way.

dhalbert commented 4 years ago

Then, on the same SAMD21, I ran your code and got these values on the serial monitor:

D8E007FA FFFFFC5D FFFFFFFF FFFFFFFF

By converting the first byte (D8E007FA) to binary I got this: 11011000111000000000011111111010

Which, according to the datasheet it should breakdown like this:

Screenshot 2020-05-15 at 20 23 39

BOD33 level is now 38. Let me know if I'm seeing this right.

I think you are numbering the bits backwards in your table image. bit 0 is the least-significant, rightmost bit.

The bootloader only changes the fuses if they are all ones.

humansthatmake commented 4 years ago

Ok, so everything is fine here. Is it something in the arduino core?

I recently found this post on arduino forum. It seems like its the same issue, but unfortunately, there was no disclosure for that. https://forum.arduino.cc/index.php?topic=554165.0

dhalbert commented 4 years ago

Just to put the fuses issue to bed, let's reinterpret 0xD8E007FA the bits in the correct order, and we get

32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 
 0  1  1  0  1  1  0  0  0  1  1  1  0  0  0  0  0  0  0  0  0  0  1  1  1  1  1  1  1  1  0  1  0 
BOOTPROT (2:0) = 010
reserved (3) = 1
EEPROM (6:4) = 111
reserved (7) = 1
BOD33 level (13:8) = 000111 = 7
BOD33 enable (14) = 0

This is matching what Atmel Studio shows.

dhalbert commented 4 years ago

HOWEVER, I think I've figured out the problem. When running at 1.8V, you must increase the number of NVM wait states, past what is typical, if you want to run at 48MHz. From the datasheet: image

The bootloader sets the number of wait states for the NVM to 1. This is insuffi

https://github.com/adafruit/uf2-samdx1/blob/6785401969be1affa6b76e2cd018325c6c6d66e6/src/init_samd21.c#L29

This is insufficient when running at 48MHz and 1.8V. This value should be 3 instead of 1.

The same is true in both the Arduino Zero bootloader and the Arduino core code: https://github.com/arduino/ArduinoCore-samd/blob/d72f11735d3588f4128b016b346f41ef9812b060/cores/arduino/startup.c#L50 https://github.com/arduino/ArduinoCore-samd/blob/020b419fc1dbca49b23b7c0b5e47d50fb2a04485/bootloaders/zero/board_init.c#L45

So you'd need to fix this in all these places for it to work all the way through.

humansthatmake commented 4 years ago

@dhalbert Sorry for the late reply. I tried to spend some time working with the SAMD21 just to make sure there were no other caveats, and everything seems to work nicely at 1.8v now.

So, to operate SAMD21 at lower voltages we need to: 1 - disable BOD33 fuse 2 - increase NVM wait states to 3.

thank you very much for your support!

dhalbert commented 4 years ago

That is it! Glad it's working!