Last active
December 6, 2020 09:18
-
-
Save cmaglie/c411621b8d49494faeb7869ad59aa6b6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This sketch should fix a "bricked" Arduino Zero board due to a bug in "Burn bootloader" command. | |
// For more information see: https://github.com/arduino/ArduinoCore-samd/issues/137 | |
// **IMPORTANT**: After running the sketch, you must power cycle the board. | |
// This code is freely inspired from Atmel Application Note: | |
// http://atmel.force.com/support/articles/en_US/FAQ/SAMD20-SAMD21-Programming-the-fuses-from-application-code | |
void setup() { | |
Serial.begin(115200); | |
uint32_t old_fusebits[2]; | |
read_fuse_bits(old_fusebits); | |
Serial.println("Current NVM User Row value is:"); | |
Serial.println(old_fusebits[0], HEX); | |
Serial.println(old_fusebits[1], HEX); | |
if (old_fusebits[0] == 0xFFFFFFFA && old_fusebits[1] == 0xFFFFFFFF) { | |
Serial.println("-> Fixing..."); | |
fix_fuses(); | |
Serial.print("DONE"); | |
} | |
} | |
void loop() { | |
} | |
static void read_fuse_bits(uint32_t *data) | |
{ | |
/* Make sure the module is ready */ | |
/* Wait for NVM command to complete */ | |
while (!(NVMCTRL->INTFLAG.reg & NVMCTRL_INTFLAG_READY)); | |
/* Read the fuse settings in the user row, 64 bit */ | |
data[0] = *((uint32_t *)NVMCTRL_AUX0_ADDRESS); | |
data[1] = *(((uint32_t *)NVMCTRL_AUX0_ADDRESS) + 1); | |
} | |
void fix_fuses() { | |
#define NVM_COMMAND_ERASE_AUX_ROW 0x05 | |
#define NVM_COMMAND_PAGE_BUFFER_CLEAR 0x44 | |
#define NVM_COMMAND_WRITE_AUX_ROW 0x06 | |
uint32_t new_fusebits[2]; | |
new_fusebits[0] = 0xD8E0C7FF; // Default values | |
new_fusebits[1] = 0xFFFFFC5D; // | |
/* Auxiliary space cannot be accessed if the security bit is set */ | |
if (NVMCTRL->STATUS.reg & NVMCTRL_STATUS_SB) { | |
return; | |
} | |
/* Disable Cache */ | |
uint32_t temp = NVMCTRL->CTRLB.reg; | |
NVMCTRL->CTRLB.reg = temp | NVMCTRL_CTRLB_CACHEDIS; | |
/* Clear error flags */ | |
NVMCTRL->STATUS.reg |= NVMCTRL_STATUS_MASK; | |
/* Set address, command will be issued elsewhere */ | |
NVMCTRL->ADDR.reg = NVMCTRL_AUX0_ADDRESS / 2; | |
/* Erase the user page */ | |
NVMCTRL->CTRLA.reg = NVM_COMMAND_ERASE_AUX_ROW | NVMCTRL_CTRLA_CMDEX_KEY; | |
/* Wait for NVM command to complete */ | |
while (!(NVMCTRL->INTFLAG.reg & NVMCTRL_INTFLAG_READY)); | |
/* Clear error flags */ | |
NVMCTRL->STATUS.reg |= NVMCTRL_STATUS_MASK; | |
/* Set address, command will be issued elsewhere */ | |
NVMCTRL->ADDR.reg = NVMCTRL_AUX0_ADDRESS / 2; | |
/* Erase the page buffer before buffering new data */ | |
NVMCTRL->CTRLA.reg = NVM_COMMAND_PAGE_BUFFER_CLEAR | NVMCTRL_CTRLA_CMDEX_KEY; | |
/* Wait for NVM command to complete */ | |
while (!(NVMCTRL->INTFLAG.reg & NVMCTRL_INTFLAG_READY)); | |
/* Clear error flags */ | |
NVMCTRL->STATUS.reg |= NVMCTRL_STATUS_MASK; | |
/* Set address, command will be issued elsewhere */ | |
NVMCTRL->ADDR.reg = NVMCTRL_AUX0_ADDRESS / 2; | |
*((uint32_t *)NVMCTRL_AUX0_ADDRESS) = new_fusebits[0]; | |
*(((uint32_t *)NVMCTRL_AUX0_ADDRESS) + 1) = new_fusebits[1]; | |
/* Write the user page */ | |
NVMCTRL->CTRLA.reg = NVM_COMMAND_WRITE_AUX_ROW | NVMCTRL_CTRLA_CMDEX_KEY; | |
/* Restore the settings */ | |
NVMCTRL->CTRLB.reg = temp; | |
} |
Just to make it clear to people viewing this page: auxiliary space can indeed be accessed, fuses can't be reprogrammed when security bit is set.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Also, try a 1k resistor from 3V3 pin to RESET pin...