Skip to content

Commit

Permalink
Merge pull request #198 from dhalbert/samd21-bod33
Browse files Browse the repository at this point in the history
Enable BOD33 protection for SAMD21
  • Loading branch information
dhalbert authored Feb 28, 2023
2 parents 7e239a9 + 6451787 commit 979cad0
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 7 deletions.
35 changes: 35 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,41 @@ int main(void) {
}

#if defined(SAMD21)
// Check for voltage too low, and set up brownout protection.
// Code largely taken from https://blog.thea.codes/sam-d21-brown-out-detector/ (thanks!)

// Disable the brown-out detector during configuration, otherwise
// it might misbehave and reset the microcontroller.
SYSCTRL->BOD33.bit.ENABLE = 0;
while (!SYSCTRL->PCLKSR.bit.B33SRDY) {};

// Configure the brown-out detector so that the program can use it to watch the power supply voltage.
SYSCTRL->BOD33.reg = (
// This sets the minimum voltage level to about 2.9V. See datasheet table 37-21.
// Voltage threshold is about 1.5V + LEVEL * 34mV. See "Electrical Characteristics" in datasheet.
// 39 is about 2.8V, and is a standard measured value in the datasheet.
// External flash chips usually require at least 2.7V.
SYSCTRL_BOD33_LEVEL(39) |
// Since the program is waiting for the voltage to rise,
// don't reset the microcontroller if the voltage is too low.
SYSCTRL_BOD33_ACTION_NONE |
// Enable hysteresis to better deal with noisy power supplies and voltage transients.
SYSCTRL_BOD33_HYST);

// Enable the brown-out detector and then wait for the voltage level to settle.
SYSCTRL->BOD33.bit.ENABLE = 1;
while (!SYSCTRL->PCLKSR.bit.BOD33RDY) {}

// BOD33DET is set when the voltage is *too low*, so wait for it to be cleared.
while (SYSCTRL->PCLKSR.bit.BOD33DET) {}

// Let the brown-out detector automatically reset the microcontroller if the voltage drops too low.
SYSCTRL->BOD33.bit.ENABLE = 0;
while (!SYSCTRL->PCLKSR.bit.B33SRDY) {};

SYSCTRL->BOD33.reg |= SYSCTRL_BOD33_ACTION_RESET;
SYSCTRL->BOD33.bit.ENABLE = 1;

// If fuses have been reset to all ones, the watchdog ALWAYS-ON is
// set, so we can't turn off the watchdog. Set the fuse to a
// reasonable value and reset. This is a mini version of the fuse
Expand Down
8 changes: 1 addition & 7 deletions src/selfmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,20 +194,14 @@ int main(void) {
uint32_t zeros[2] = {0, 0};
flash_write_words((void *)(BOOTLOADER_K * 1024), zeros, 2);

for (uint32_t i = 0; i < 8; ++i) {
LED_MSC_TGL();
delay(1000);
}

LED_MSC_OFF();

#ifdef SAMD21
// Re-enable BOOTPROT
set_fuses_and_bootprot(2); // 8k
#endif
// For the SAMD51, the boot protection will automatically be re-enabled on
// reset.

LED_MSC_OFF();
resetIntoBootloader();

// We should not reach here normally.
Expand Down

0 comments on commit 979cad0

Please sign in to comment.