Added AVR8 fuse enable strategy
This commit is contained in:
@@ -14,8 +14,6 @@
|
|||||||
#include "Exceptions/DebugWirePhysicalInterfaceError.hpp"
|
#include "Exceptions/DebugWirePhysicalInterfaceError.hpp"
|
||||||
#include "src/Targets/TargetRegister.hpp"
|
#include "src/Targets/TargetRegister.hpp"
|
||||||
|
|
||||||
#include "src/Targets/Microchip/AVR/Fuse.hpp"
|
|
||||||
|
|
||||||
namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
||||||
{
|
{
|
||||||
using namespace Exceptions;
|
using namespace Exceptions;
|
||||||
@@ -54,6 +52,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
TargetRegisterAccess(true, true)
|
TargetRegisterAccess(true, true)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
, fuseEnableStrategy(this->targetDescriptionFile.getFuseEnableStrategy().value_or(FuseEnableStrategy::CLEAR))
|
||||||
{
|
{
|
||||||
if (!this->supportedPhysicalInterfaces.contains(this->targetConfig.physicalInterface)) {
|
if (!this->supportedPhysicalInterfaces.contains(this->targetConfig.physicalInterface)) {
|
||||||
/*
|
/*
|
||||||
@@ -648,6 +647,28 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Avr8::isFuseEnabled(const FuseBitsDescriptor& descriptor, unsigned char fuseByteValue) const {
|
||||||
|
const auto programmedValue = static_cast<unsigned char>(
|
||||||
|
this->fuseEnableStrategy == FuseEnableStrategy::SET
|
||||||
|
? (0xFF & descriptor.bitMask)
|
||||||
|
: 0
|
||||||
|
);
|
||||||
|
|
||||||
|
return (fuseByteValue & descriptor.bitMask) == programmedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char Avr8::setFuseEnabled(
|
||||||
|
const FuseBitsDescriptor& descriptor,
|
||||||
|
unsigned char fuseByteValue,
|
||||||
|
bool enabled
|
||||||
|
) const {
|
||||||
|
return static_cast<unsigned char>(
|
||||||
|
this->fuseEnableStrategy == FuseEnableStrategy::SET
|
||||||
|
? enabled ? (fuseByteValue | descriptor.bitMask) : fuseByteValue & ~(descriptor.bitMask)
|
||||||
|
: enabled ? fuseByteValue & ~(descriptor.bitMask) : (fuseByteValue | descriptor.bitMask)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void Avr8::updateDwenFuseBit(bool enable) {
|
void Avr8::updateDwenFuseBit(bool enable) {
|
||||||
if (this->avrIspInterface == nullptr) {
|
if (this->avrIspInterface == nullptr) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
@@ -750,7 +771,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
* cleared bit (0b0), means the fuse/lock is set.
|
* cleared bit (0b0), means the fuse/lock is set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((spienFuseByte & spienFuseBitsDescriptor->bitMask) != 0) {
|
if (!this->isFuseEnabled(*spienFuseBitsDescriptor, spienFuseByte)) {
|
||||||
/*
|
/*
|
||||||
* If we get here, something is very wrong. The SPIEN (SPI enable) fuse bit appears to be cleared, but
|
* If we get here, something is very wrong. The SPIEN (SPI enable) fuse bit appears to be cleared, but
|
||||||
* this is not possible because we're connected to the target via the SPI (the ISP interface uses a
|
* this is not possible because we're connected to the target via the SPI (the ISP interface uses a
|
||||||
@@ -771,7 +792,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
|
|
||||||
Logger::info("Current SPIEN fuse bit value confirmed");
|
Logger::info("Current SPIEN fuse bit value confirmed");
|
||||||
|
|
||||||
if (!static_cast<bool>(dwenFuseByte & dwenFuseBitsDescriptor->bitMask) == enable) {
|
if (this->isFuseEnabled(*dwenFuseBitsDescriptor, dwenFuseByte) == enable) {
|
||||||
/*
|
/*
|
||||||
* The DWEN fuse appears to already be set to the desired value. This may be a result of incorrect data
|
* The DWEN fuse appears to already be set to the desired value. This may be a result of incorrect data
|
||||||
* in the TDF, but we're not taking any chances.
|
* in the TDF, but we're not taking any chances.
|
||||||
@@ -801,8 +822,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
|
|
||||||
const auto newFuse = Fuse(
|
const auto newFuse = Fuse(
|
||||||
dwenFuseBitsDescriptor->fuseType,
|
dwenFuseBitsDescriptor->fuseType,
|
||||||
(enable) ? static_cast<unsigned char>(dwenFuseByte & ~(dwenFuseBitsDescriptor->bitMask))
|
this->setFuseEnabled(*dwenFuseBitsDescriptor, dwenFuseByte, enable)
|
||||||
: static_cast<unsigned char>(dwenFuseByte | dwenFuseBitsDescriptor->bitMask)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Logger::warning("Updating DWEN fuse bit");
|
Logger::warning("Updating DWEN fuse bit");
|
||||||
@@ -876,7 +896,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
|
|
||||||
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 ((jtagenFuseByteValue & jtagenFuseBitsDescriptor->bitMask) != 0) {
|
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.
|
||||||
@@ -890,16 +910,14 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!static_cast<bool>(ocdenFuseByteValue & ocdenFuseBitsDescriptor->bitMask) == enable) {
|
if (this->isFuseEnabled(*ocdenFuseBitsDescriptor, ocdenFuseByteValue) == enable) {
|
||||||
Logger::debug("OCDEN fuse bit already set to desired value - aborting update operation");
|
Logger::debug("OCDEN fuse bit already set to desired value - aborting update operation");
|
||||||
|
|
||||||
this->disableProgrammingMode();
|
this->disableProgrammingMode();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto newValue = (enable)
|
const auto newValue = this->setFuseEnabled(*ocdenFuseBitsDescriptor, ocdenFuseByteValue, 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::debug("New OCDEN fuse byte value (to be written): 0x" + StringService::toHex(newValue));
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
#include "TargetParameters.hpp"
|
#include "TargetParameters.hpp"
|
||||||
#include "PadDescriptor.hpp"
|
#include "PadDescriptor.hpp"
|
||||||
#include "ProgramMemorySection.hpp"
|
#include "ProgramMemorySection.hpp"
|
||||||
|
|
||||||
|
#include "src/Targets/Microchip/AVR/Fuse.hpp"
|
||||||
#include "src/Targets/TargetRegister.hpp"
|
#include "src/Targets/TargetRegister.hpp"
|
||||||
|
|
||||||
#include "TargetDescription/TargetDescriptionFile.hpp"
|
#include "TargetDescription/TargetDescriptionFile.hpp"
|
||||||
@@ -116,6 +118,16 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
TargetRegisterDescriptor stackPointerRegisterDescriptor;
|
TargetRegisterDescriptor stackPointerRegisterDescriptor;
|
||||||
TargetRegisterDescriptor statusRegisterDescriptor;
|
TargetRegisterDescriptor statusRegisterDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On some AVR8 targets, like the ATmega328P, a cleared fuse bit means the fuse is "programmed" (enabled).
|
||||||
|
* And a set bit means the fuse is "un-programmed" (disabled). But on others, like the ATmega4809, it's the
|
||||||
|
* other way around (set bit == enabled, cleared bit == disabled).
|
||||||
|
*
|
||||||
|
* The FuseEnableStrategy specifies the strategy of enabling a fuse. It's extracted from the TDF.
|
||||||
|
* See TargetDescription::getFuseEnableStrategy() for more.
|
||||||
|
*/
|
||||||
|
FuseEnableStrategy fuseEnableStrategy;
|
||||||
|
|
||||||
std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor> targetRegisterDescriptorsById;
|
std::map<TargetRegisterDescriptorId, TargetRegisterDescriptor> targetRegisterDescriptorsById;
|
||||||
|
|
||||||
std::map<TargetMemoryType, TargetMemoryDescriptor> targetMemoryDescriptorsByType;
|
std::map<TargetMemoryType, TargetMemoryDescriptor> targetMemoryDescriptorsByType;
|
||||||
@@ -130,6 +142,33 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
|
|
||||||
void loadTargetMemoryDescriptors();
|
void loadTargetMemoryDescriptors();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a particular fuse is enabled in the given fuse byte value. Takes the target's fuse enable strategy
|
||||||
|
* into account.
|
||||||
|
*
|
||||||
|
* @param descriptor
|
||||||
|
* @param fuseByteValue
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool isFuseEnabled(const FuseBitsDescriptor& descriptor, unsigned char fuseByteValue) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables/disables a fuse within the given fuse byte, using the target's fuse enable strategy.
|
||||||
|
*
|
||||||
|
* @param descriptor
|
||||||
|
* @param fuseByteValue
|
||||||
|
* @param enabled
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The updated fuse byte value.
|
||||||
|
*/
|
||||||
|
unsigned char setFuseEnabled(
|
||||||
|
const FuseBitsDescriptor& descriptor,
|
||||||
|
unsigned char fuseByteValue,
|
||||||
|
bool enabled
|
||||||
|
) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the debugWire enable (DWEN) fuse bit on the AVR target.
|
* Updates the debugWire enable (DWEN) fuse bit on the AVR target.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -339,6 +339,32 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<FuseEnableStrategy> TargetDescriptionFile::getFuseEnableStrategy() const {
|
||||||
|
static const auto fuseEnableStrategies = std::map<std::string, FuseEnableStrategy>({
|
||||||
|
{"0", FuseEnableStrategy::CLEAR},
|
||||||
|
{"1", FuseEnableStrategy::SET},
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto programmingInfoPropertyGroupIt = this->propertyGroupsMappedByName.find("programming_info");
|
||||||
|
|
||||||
|
if (programmingInfoPropertyGroupIt != this->propertyGroupsMappedByName.end()) {
|
||||||
|
const auto& programmingInfoParamsByName = programmingInfoPropertyGroupIt->second.propertiesMappedByName;
|
||||||
|
const auto fuseEnabledValuePropertyIt = programmingInfoParamsByName.find("fuse_enabled_value");
|
||||||
|
|
||||||
|
if (fuseEnabledValuePropertyIt != programmingInfoParamsByName.end()) {
|
||||||
|
const auto fuseEnableStrategyIt = fuseEnableStrategies.find(
|
||||||
|
fuseEnabledValuePropertyIt->second.value.toStdString()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fuseEnableStrategyIt != fuseEnableStrategies.end()) {
|
||||||
|
return fuseEnableStrategyIt->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<FuseBitsDescriptor> TargetDescriptionFile::getDwenFuseBitsDescriptor() const {
|
std::optional<FuseBitsDescriptor> TargetDescriptionFile::getDwenFuseBitsDescriptor() const {
|
||||||
return this->getFuseBitsDescriptorByName("dwen");
|
return this->getFuseBitsDescriptorByName("dwen");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,14 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] IspParameters getIspParameters() const;
|
[[nodiscard]] IspParameters getIspParameters() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the target's fuse enable strategy.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* std::nullopt if the TDF doesn't contain a fuse enable strategy.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::optional<FuseEnableStrategy> getFuseEnableStrategy() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a FuseBitDescriptor for the debugWire enable (DWEN) fuse bit, with information extracted from
|
* Constructs a FuseBitDescriptor for the debugWire enable (DWEN) fuse bit, with information extracted from
|
||||||
* the TDF.
|
* the TDF.
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ namespace Bloom::Targets::Microchip::Avr
|
|||||||
EXTENDED,
|
EXTENDED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class FuseEnableStrategy: std::uint8_t
|
||||||
|
{
|
||||||
|
CLEAR,
|
||||||
|
SET,
|
||||||
|
};
|
||||||
|
|
||||||
struct Fuse
|
struct Fuse
|
||||||
{
|
{
|
||||||
FuseType type;
|
FuseType type;
|
||||||
|
|||||||
Reference in New Issue
Block a user