OCDEN fuse bit management

This commit is contained in:
Nav
2023-05-07 16:49:45 +01:00
parent e2f202d5c9
commit 6ae1ef1be2
11 changed files with 253 additions and 19 deletions

View File

@@ -8,6 +8,7 @@
#include "src/Logger/Logger.hpp"
#include "src/Services/PathService.hpp"
#include "src/Services/StringService.hpp"
#include "src/Exceptions/InvalidConfig.hpp"
#include "Exceptions/DebugWirePhysicalInterfaceError.hpp"
@@ -92,7 +93,8 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
}
if (
this->targetConfig->manageDwenFuseBit && this->avrIspInterface == nullptr
this->targetConfig->manageDwenFuseBit
&& this->avrIspInterface == nullptr
&& this->targetConfig->physicalInterface == PhysicalInterface::DEBUG_WIRE
) {
Logger::warning(
@@ -101,10 +103,19 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
);
}
this->avr8DebugInterface->configure(this->targetConfig.value());
if (
this->targetConfig->manageOcdenFuseBit
&& this->targetConfig->physicalInterface != PhysicalInterface::JTAG
) {
Logger::warning(
"The 'manageOcdenFuseBit' parameter only applies to JTAG targets. It will be ignored in this session."
);
}
this->avr8DebugInterface->configure(*(this->targetConfig));
if (this->avrIspInterface != nullptr) {
this->avrIspInterface->configure(targetConfig);
this->avrIspInterface->configure(*(this->targetConfig));
}
}
@@ -211,13 +222,34 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
this->avr8DebugInterface->activate();
}
if (
this->targetConfig->physicalInterface == PhysicalInterface::JTAG
&& this->targetConfig->manageOcdenFuseBit
) {
Logger::debug("Attempting OCDEN fuse bit management");
this->updateOcdenFuseBit(true);
}
this->activated = true;
this->avr8DebugInterface->reset();
}
void Avr8::deactivate() {
try {
this->avr8DebugInterface->deactivate();
this->stop();
this->clearAllBreakpoints();
if (
this->targetConfig->physicalInterface == PhysicalInterface::JTAG
&& this->targetConfig->manageOcdenFuseBit
) {
Logger::debug("Attempting OCDEN fuse bit management");
this->updateOcdenFuseBit(false);
} else {
this->avr8DebugInterface->deactivate();
}
this->activated = false;
} catch (const Exception& exception) {
@@ -946,6 +978,110 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
}
}
void Avr8::updateOcdenFuseBit(bool enable) {
using Services::PathService;
using Services::StringService;
if (!this->targetDescriptionFile.has_value() || !this->id.has_value()) {
throw Exception(
"Insufficient target information for managing OCDEN fuse bit - do not use the generic \"avr8\" "
"target name in conjunction with the \"manageOcdenFuseBit\" function. Please update your target "
"configuration."
);
}
if (!this->supportedPhysicalInterfaces.contains(PhysicalInterface::JTAG)) {
throw Exception(
"Target does not support JTAG physical interface - check target configuration or "
"report this issue via " + PathService::homeDomainName() + "/report-issue"
);
}
const auto ocdenFuseBitsDescriptor = this->targetDescriptionFile->getOcdenFuseBitsDescriptor();
const auto jtagenFuseBitsDescriptor = this->targetDescriptionFile->getJtagenFuseBitsDescriptor();
if (!ocdenFuseBitsDescriptor.has_value()) {
throw Exception("Could not find OCDEN bit field in TDF.");
}
if (!jtagenFuseBitsDescriptor.has_value()) {
throw Exception("Could not find JTAGEN bit field in TDF.");
}
try {
this->enableProgrammingMode();
const auto ocdenFuseByteValue = this->avr8DebugInterface->readMemory(
TargetMemoryType::FUSES,
ocdenFuseBitsDescriptor->byteAddress,
1
).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));
if ((jtagenFuseByteValue & jtagenFuseBitsDescriptor->bitMask) != 0) {
/*
* 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.
*
* 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.
*/
throw Exception(
"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"
);
}
if (!static_cast<bool>(ocdenFuseByteValue & ocdenFuseBitsDescriptor->bitMask) == enable) {
Logger::debug("OCDEN fuse bit already set to desired value - aborting update operation");
this->disableProgrammingMode();
return;
}
const auto newValue = (enable)
? static_cast<unsigned char>(ocdenFuseByteValue & ~(ocdenFuseBitsDescriptor->bitMask))
: static_cast<unsigned char>(ocdenFuseByteValue | ocdenFuseBitsDescriptor->bitMask);
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;
}
}
ProgramMemorySection Avr8::getProgramMemorySectionFromAddress(std::uint32_t address) {
return this->targetParameters->bootSectionStartAddress.has_value()
&& address >= this->targetParameters->bootSectionStartAddress.value()