Moved programming mode requirement for fuse programming into EDBG driver, as it is specific to that driver
This commit is contained in:
@@ -1670,6 +1670,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto managingProgrammingMode = type == Avr8MemoryType::FUSES && !this->programmingModeEnabled;
|
||||||
|
if (managingProgrammingMode) {
|
||||||
|
this->enableProgrammingMode();
|
||||||
|
}
|
||||||
|
|
||||||
if (!excludedAddresses.empty() && (this->avoidMaskedMemoryRead || type != Avr8MemoryType::SRAM)) {
|
if (!excludedAddresses.empty() && (this->avoidMaskedMemoryRead || type != Avr8MemoryType::SRAM)) {
|
||||||
/*
|
/*
|
||||||
* Driver-side masked memory read.
|
* Driver-side masked memory read.
|
||||||
@@ -1770,6 +1775,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (managingProgrammingMode) {
|
||||||
|
this->disableProgrammingMode();
|
||||||
|
}
|
||||||
|
|
||||||
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
||||||
throw Avr8CommandFailure("AVR8 Read memory command failed", responseFrame);
|
throw Avr8CommandFailure("AVR8 Read memory command failed", responseFrame);
|
||||||
}
|
}
|
||||||
@@ -1794,6 +1803,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto managingProgrammingMode = type == Avr8MemoryType::FUSES && !this->programmingModeEnabled;
|
||||||
|
if (managingProgrammingMode) {
|
||||||
|
this->enableProgrammingMode();
|
||||||
|
}
|
||||||
|
|
||||||
const auto bytes = static_cast<TargetMemorySize>(buffer.size());
|
const auto bytes = static_cast<TargetMemorySize>(buffer.size());
|
||||||
|
|
||||||
if (this->alignmentRequired(type)) {
|
if (this->alignmentRequired(type)) {
|
||||||
@@ -1852,6 +1866,16 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// We must disable and re-enable programming mode, in order for the changes to the fuse bit to take effect.
|
||||||
|
if (type == Avr8MemoryType::FUSES) {
|
||||||
|
this->disableProgrammingMode();
|
||||||
|
|
||||||
|
if (!managingProgrammingMode) {
|
||||||
|
this->enableProgrammingMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
if (responseFrame.id == Avr8ResponseId::FAILED) {
|
||||||
throw Avr8CommandFailure("AVR8 Write memory command failed", responseFrame);
|
throw Avr8CommandFailure("AVR8 Write memory command failed", responseFrame);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
|
|
||||||
void Avr8::writeMemory(TargetMemoryType memoryType, std::uint32_t startAddress, const TargetMemoryBuffer& buffer) {
|
void Avr8::writeMemory(TargetMemoryType memoryType, std::uint32_t startAddress, const TargetMemoryBuffer& buffer) {
|
||||||
if (memoryType == TargetMemoryType::FLASH && !this->programmingModeEnabled()) {
|
if (memoryType == TargetMemoryType::FLASH && !this->programmingModeEnabled()) {
|
||||||
throw Exception("Attempted FLASH memory write with no active programming session.");
|
throw Exception("Attempted Flash memory write with no active programming session.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this->avr8DebugInterface->writeMemory(memoryType, startAddress, buffer);
|
this->avr8DebugInterface->writeMemory(memoryType, startAddress, buffer);
|
||||||
@@ -348,17 +348,26 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this->programmingModeEnabled()) {
|
||||||
|
throw Exception("Attempted Flash memory erase with no active programming session.");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For JTAG and UPDI targets, we must perform a chip erase. This means we could end up erasing EEPROM,
|
* For JTAG and UPDI targets, we must perform a chip erase. This means we could end up erasing EEPROM,
|
||||||
* unless the EESAVE fuse bit has been programmed.
|
* unless the EESAVE fuse bit has been programmed.
|
||||||
*
|
*
|
||||||
* If configured to do so, we will ensure that the EESAVE fuse bit has been programmed when we start a
|
* If configured to do so, we will ensure that the EESAVE fuse bit has been programmed before we perform
|
||||||
* programming session. See Avr8::enableProgrammingMode() for more.
|
* the chip erase. The fuse will be restored to its original value at the end of the programming session.
|
||||||
*/
|
*/
|
||||||
if (
|
if (
|
||||||
this->targetConfig.physicalInterface == PhysicalInterface::JTAG
|
this->targetConfig.physicalInterface == PhysicalInterface::JTAG
|
||||||
|| this->targetConfig.physicalInterface == PhysicalInterface::UPDI
|
|| this->targetConfig.physicalInterface == PhysicalInterface::UPDI
|
||||||
) {
|
) {
|
||||||
|
if (this->targetConfig.preserveEeprom) {
|
||||||
|
Logger::debug("Inspecting EESAVE fuse bit");
|
||||||
|
this->activeProgrammingSession->managingEesaveFuseBit = this->updateEesaveFuseBit(true);
|
||||||
|
}
|
||||||
|
|
||||||
return this->avr8DebugInterface->eraseChip();
|
return this->avr8DebugInterface->eraseChip();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,26 +581,6 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
|
|
||||||
this->avr8DebugInterface->enableProgrammingMode();
|
this->avr8DebugInterface->enableProgrammingMode();
|
||||||
this->activeProgrammingSession = ProgrammingSession();
|
this->activeProgrammingSession = ProgrammingSession();
|
||||||
|
|
||||||
if (
|
|
||||||
this->targetConfig.preserveEeprom
|
|
||||||
&& (
|
|
||||||
this->targetConfig.physicalInterface == PhysicalInterface::JTAG
|
|
||||||
|| this->targetConfig.physicalInterface == PhysicalInterface::UPDI
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Logger::debug("Inspecting EESAVE fuse bit");
|
|
||||||
this->activeProgrammingSession->managingEesaveFuseBit = this->updateEesaveFuseBit(true);
|
|
||||||
|
|
||||||
if (this->activeProgrammingSession->managingEesaveFuseBit) {
|
|
||||||
/*
|
|
||||||
* We must disable and re-enable programming mode, in order for the changes to the EESAVE fuse bit to
|
|
||||||
* take effect.
|
|
||||||
*/
|
|
||||||
this->avr8DebugInterface->disableProgrammingMode();
|
|
||||||
this->avr8DebugInterface->enableProgrammingMode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avr8::disableProgrammingMode() {
|
void Avr8::disableProgrammingMode() {
|
||||||
@@ -923,76 +912,66 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
throw Exception("Could not find JTAGEN bit field in TDF.");
|
throw Exception("Could not find JTAGEN bit field in TDF.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const auto ocdenFuseByteValue = this->avr8DebugInterface->readMemory(
|
||||||
this->enableProgrammingMode();
|
TargetMemoryType::FUSES,
|
||||||
|
ocdenFuseBitsDescriptor->byteAddress,
|
||||||
const auto ocdenFuseByteValue = this->avr8DebugInterface->readMemory(
|
1
|
||||||
|
).at(0);
|
||||||
|
const auto jtagenFuseByteValue = jtagenFuseBitsDescriptor->byteAddress == ocdenFuseBitsDescriptor->byteAddress
|
||||||
|
? ocdenFuseByteValue
|
||||||
|
: this->avr8DebugInterface->readMemory(
|
||||||
TargetMemoryType::FUSES,
|
TargetMemoryType::FUSES,
|
||||||
ocdenFuseBitsDescriptor->byteAddress,
|
jtagenFuseBitsDescriptor->byteAddress,
|
||||||
1
|
1
|
||||||
).at(0);
|
).at(0)
|
||||||
const auto jtagenFuseByteValue = jtagenFuseBitsDescriptor->byteAddress == ocdenFuseBitsDescriptor->byteAddress
|
;
|
||||||
? ocdenFuseByteValue
|
|
||||||
: this->avr8DebugInterface->readMemory(
|
|
||||||
TargetMemoryType::FUSES,
|
|
||||||
jtagenFuseBitsDescriptor->byteAddress,
|
|
||||||
1
|
|
||||||
).at(0)
|
|
||||||
;
|
|
||||||
|
|
||||||
Logger::debug("OCDEN fuse byte value (before update): 0x" + StringService::toHex(ocdenFuseByteValue));
|
Logger::debug("OCDEN fuse byte value (before update): 0x" + StringService::toHex(ocdenFuseByteValue));
|
||||||
|
|
||||||
if (!this->isFuseEnabled(*jtagenFuseBitsDescriptor, jtagenFuseByteValue)) {
|
if (!this->isFuseEnabled(*jtagenFuseBitsDescriptor, jtagenFuseByteValue)) {
|
||||||
/*
|
/*
|
||||||
* If we get here, something has gone wrong. The JTAGEN fuse should always be programmed by this point.
|
* If we get here, something has gone wrong. The JTAGEN fuse should always be programmed by this point.
|
||||||
* We wouldn't have been able to activate the JTAG physical interface if the fuse wasn't programmed.
|
* We wouldn't have been able to activate the JTAG physical interface if the fuse wasn't programmed.
|
||||||
*
|
*
|
||||||
* This means the data we have on the JTAGEN fuse bit, from the TDF, is likely incorrect. And if that's
|
* This means the data we have on the JTAGEN fuse bit, from the TDF, is likely incorrect. And if that's
|
||||||
* the case, we cannot rely on the data for the OCDEN fuse bit being any better.
|
* the case, we cannot rely on the data for the OCDEN fuse bit being any better.
|
||||||
*/
|
*/
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid JTAGEN fuse bit value - suspected inaccuracies in TDF data. Please report this to "
|
"Invalid JTAGEN fuse bit value - suspected inaccuracies in TDF data. Please report this to "
|
||||||
"Bloom developers as a matter of urgency, via " + PathService::homeDomainName() + "/report-issue"
|
"Bloom developers as a matter of urgency, via " + PathService::homeDomainName() + "/report-issue"
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->isFuseEnabled(*ocdenFuseBitsDescriptor, ocdenFuseByteValue) == enable) {
|
|
||||||
Logger::debug("OCDEN fuse bit already set to desired value - aborting update operation");
|
|
||||||
|
|
||||||
this->disableProgrammingMode();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto newValue = this->setFuseEnabled(*ocdenFuseBitsDescriptor, ocdenFuseByteValue, enable);
|
|
||||||
|
|
||||||
Logger::debug("New OCDEN fuse byte value (to be written): 0x" + StringService::toHex(newValue));
|
|
||||||
|
|
||||||
Logger::warning("Updating OCDEN fuse bit");
|
|
||||||
this->avr8DebugInterface->writeMemory(
|
|
||||||
TargetMemoryType::FUSES,
|
|
||||||
ocdenFuseBitsDescriptor->byteAddress,
|
|
||||||
{newValue}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Logger::debug("Verifying OCDEN fuse bit");
|
|
||||||
const auto postUpdateOcdenByteValue = this->avr8DebugInterface->readMemory(
|
|
||||||
TargetMemoryType::FUSES,
|
|
||||||
ocdenFuseBitsDescriptor->byteAddress,
|
|
||||||
1
|
|
||||||
).at(0);
|
|
||||||
|
|
||||||
if (postUpdateOcdenByteValue != newValue) {
|
|
||||||
throw Exception("Failed to update OCDEN fuse bit - post-update verification failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::info("OCDEN fuse bit updated");
|
|
||||||
|
|
||||||
this->disableProgrammingMode();
|
|
||||||
|
|
||||||
} catch (const Exception& exception) {
|
|
||||||
this->disableProgrammingMode();
|
|
||||||
throw exception;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->isFuseEnabled(*ocdenFuseBitsDescriptor, ocdenFuseByteValue) == enable) {
|
||||||
|
Logger::debug("OCDEN fuse bit already set to desired value - aborting update operation");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto newValue = this->setFuseEnabled(*ocdenFuseBitsDescriptor, ocdenFuseByteValue, enable);
|
||||||
|
|
||||||
|
Logger::debug("New OCDEN fuse byte value (to be written): 0x" + StringService::toHex(newValue));
|
||||||
|
|
||||||
|
Logger::warning("Updating OCDEN fuse bit");
|
||||||
|
this->avr8DebugInterface->writeMemory(
|
||||||
|
TargetMemoryType::FUSES,
|
||||||
|
ocdenFuseBitsDescriptor->byteAddress,
|
||||||
|
{newValue}
|
||||||
|
);
|
||||||
|
|
||||||
|
Logger::debug("Verifying OCDEN fuse bit");
|
||||||
|
const auto postUpdateOcdenByteValue = this->avr8DebugInterface->readMemory(
|
||||||
|
TargetMemoryType::FUSES,
|
||||||
|
ocdenFuseBitsDescriptor->byteAddress,
|
||||||
|
1
|
||||||
|
).at(0);
|
||||||
|
|
||||||
|
if (postUpdateOcdenByteValue != newValue) {
|
||||||
|
throw Exception("Failed to update OCDEN fuse bit - post-update verification failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::info("OCDEN fuse bit updated");
|
||||||
|
|
||||||
|
this->disableProgrammingMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Avr8::updateEesaveFuseBit(bool enable) {
|
bool Avr8::updateEesaveFuseBit(bool enable) {
|
||||||
@@ -1004,68 +983,44 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
throw Exception("Could not find EESAVE bit field in TDF.");
|
throw Exception("Could not find EESAVE bit field in TDF.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto managingProgrammingMode = !this->programmingModeEnabled();
|
const auto eesaveFuseByteValue = this->avr8DebugInterface->readMemory(
|
||||||
|
TargetMemoryType::FUSES,
|
||||||
|
eesaveFuseBitsDescriptor->byteAddress,
|
||||||
|
1
|
||||||
|
).at(0);
|
||||||
|
|
||||||
try {
|
Logger::debug("EESAVE fuse byte value (before update): 0x" + StringService::toHex(eesaveFuseByteValue));
|
||||||
if (managingProgrammingMode) {
|
|
||||||
this->enableProgrammingMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto eesaveFuseByteValue = this->avr8DebugInterface->readMemory(
|
if (this->isFuseEnabled(*eesaveFuseBitsDescriptor, eesaveFuseByteValue) == enable) {
|
||||||
TargetMemoryType::FUSES,
|
Logger::debug("EESAVE fuse bit already set to desired value - aborting update operation");
|
||||||
eesaveFuseBitsDescriptor->byteAddress,
|
return false;
|
||||||
1
|
|
||||||
).at(0);
|
|
||||||
|
|
||||||
Logger::debug("EESAVE fuse byte value (before update): 0x" + StringService::toHex(eesaveFuseByteValue));
|
|
||||||
|
|
||||||
if (this->isFuseEnabled(*eesaveFuseBitsDescriptor, eesaveFuseByteValue) == enable) {
|
|
||||||
Logger::debug("EESAVE fuse bit already set to desired value - aborting update operation");
|
|
||||||
|
|
||||||
if (managingProgrammingMode) {
|
|
||||||
this->disableProgrammingMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto newValue = this->setFuseEnabled(*eesaveFuseBitsDescriptor, eesaveFuseByteValue, enable);
|
|
||||||
|
|
||||||
Logger::debug("New EESAVE fuse byte value (to be written): 0x" + StringService::toHex(newValue));
|
|
||||||
|
|
||||||
Logger::warning("Updating EESAVE fuse bit");
|
|
||||||
this->avr8DebugInterface->writeMemory(
|
|
||||||
TargetMemoryType::FUSES,
|
|
||||||
eesaveFuseBitsDescriptor->byteAddress,
|
|
||||||
{newValue}
|
|
||||||
);
|
|
||||||
|
|
||||||
Logger::debug("Verifying EESAVE fuse bit");
|
|
||||||
const auto postUpdateEesaveByteValue = this->avr8DebugInterface->readMemory(
|
|
||||||
TargetMemoryType::FUSES,
|
|
||||||
eesaveFuseBitsDescriptor->byteAddress,
|
|
||||||
1
|
|
||||||
).at(0);
|
|
||||||
|
|
||||||
if (postUpdateEesaveByteValue != newValue) {
|
|
||||||
throw Exception("Failed to update EESAVE fuse bit - post-update verification failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::info("EESAVE fuse bit updated");
|
|
||||||
|
|
||||||
if (managingProgrammingMode) {
|
|
||||||
this->disableProgrammingMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
} catch (const Exception& exception) {
|
|
||||||
if (managingProgrammingMode) {
|
|
||||||
this->disableProgrammingMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw exception;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto newValue = this->setFuseEnabled(*eesaveFuseBitsDescriptor, eesaveFuseByteValue, enable);
|
||||||
|
|
||||||
|
Logger::debug("New EESAVE fuse byte value (to be written): 0x" + StringService::toHex(newValue));
|
||||||
|
|
||||||
|
Logger::warning("Updating EESAVE fuse bit");
|
||||||
|
this->avr8DebugInterface->writeMemory(
|
||||||
|
TargetMemoryType::FUSES,
|
||||||
|
eesaveFuseBitsDescriptor->byteAddress,
|
||||||
|
{newValue}
|
||||||
|
);
|
||||||
|
|
||||||
|
Logger::debug("Verifying EESAVE fuse bit");
|
||||||
|
const auto postUpdateEesaveByteValue = this->avr8DebugInterface->readMemory(
|
||||||
|
TargetMemoryType::FUSES,
|
||||||
|
eesaveFuseBitsDescriptor->byteAddress,
|
||||||
|
1
|
||||||
|
).at(0);
|
||||||
|
|
||||||
|
if (postUpdateEesaveByteValue != newValue) {
|
||||||
|
throw Exception("Failed to update EESAVE fuse bit - post-update verification failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::info("EESAVE fuse bit updated");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramMemorySection Avr8::getProgramMemorySectionFromAddress(std::uint32_t address) {
|
ProgramMemorySection Avr8::getProgramMemorySectionFromAddress(std::uint32_t address) {
|
||||||
|
|||||||
Reference in New Issue
Block a user