diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.cpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.cpp index 6d208b1f..708c4dc4 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.cpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.cpp @@ -818,13 +818,22 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr * violates the Avr8DebugInterface contract - as this member function should only ever erase program memory. * * All we can do here is take a copy of EEPROM and restore it after the erase operation. + * + * TODO: Look into setting the EESAVE fuse bit as an alternative to the backup-then-restore approach. */ - Logger::debug("Capturing EEPROM data, in preparation for chip erase"); - auto eepromSnapshot = this->readMemory( - TargetMemoryType::EEPROM, - this->targetParameters.eepromStartAddress.value(), - this->targetParameters.eepromSize.value() - ); + auto eepromSnapshot = std::optional(); + + if (this->targetConfig->preserveEeprom) { + Logger::debug("Capturing EEPROM data, in preparation for chip erase"); + eepromSnapshot = this->readMemory( + TargetMemoryType::EEPROM, + this->targetParameters.eepromStartAddress.value(), + this->targetParameters.eepromSize.value() + ); + + } else { + Logger::warning("EEPROM will be erased - use the 'preserveEeprom' parameter to preserve EEPROM"); + } const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame( EraseMemory(Avr8EraseMemoryMode::CHIP) @@ -834,12 +843,14 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr throw Avr8CommandFailure("AVR8 erase memory command failed", responseFrame); } - Logger::debug("Restoring EEPROM data"); - this->writeMemory( - TargetMemoryType::EEPROM, - this->targetParameters.eepromStartAddress.value(), - std::move(eepromSnapshot) - ); + if (eepromSnapshot.has_value()) { + Logger::debug("Restoring EEPROM data"); + this->writeMemory( + TargetMemoryType::EEPROM, + this->targetParameters.eepromStartAddress.value(), + std::move(*eepromSnapshot) + ); + } } TargetState EdbgAvr8Interface::getTargetState() { diff --git a/src/Targets/Microchip/AVR/AVR8/Avr8TargetConfig.cpp b/src/Targets/Microchip/AVR/AVR8/Avr8TargetConfig.cpp index 64bf9ff4..573a8a6f 100644 --- a/src/Targets/Microchip/AVR/AVR8/Avr8TargetConfig.cpp +++ b/src/Targets/Microchip/AVR/AVR8/Avr8TargetConfig.cpp @@ -57,5 +57,9 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit if (targetNode["manageOcdenFuseBit"]) { this->manageOcdenFuseBit = targetNode["manageOcdenFuseBit"].as(); } + + if (targetNode["preserveEeprom"]) { + this->preserveEeprom = targetNode["preserveEeprom"].as(); + } } } diff --git a/src/Targets/Microchip/AVR/AVR8/Avr8TargetConfig.hpp b/src/Targets/Microchip/AVR/AVR8/Avr8TargetConfig.hpp index ae47df67..16725084 100644 --- a/src/Targets/Microchip/AVR/AVR8/Avr8TargetConfig.hpp +++ b/src/Targets/Microchip/AVR/AVR8/Avr8TargetConfig.hpp @@ -76,6 +76,23 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit */ bool manageOcdenFuseBit = false; + /** + * With JTAG and UPDI targets, we have to perform a full chip erase when updating the target's flash memory. + * This means the user will lose their EEPROM data whenever they wish to upload any program changes via Bloom. + * + * The preserveEeprom flag determines if Bloom should preserve the target's EEPROM when performing a full chip + * erase. If enabled, we'll take a backup of the target's EEPROM just before performing the chip erase, then + * restore the backup afterwards. + * + * The backup-then-restore operation can take some time to complete. This can be a source of frustration for + * users who don't care about their EEPROM data being wiped, as it can add minutes to the time it takes to + * upload program changes. This is why the function is optional - setting this flag to false will speed up + * uploads. + * + * This parameter is optional, and the function is enabled by default. + */ + bool preserveEeprom = true; + explicit Avr8TargetConfig(const TargetConfig& targetConfig); private: