EDBG driver implementation of the AvrIspInterface
This commit is contained in:
@@ -109,6 +109,7 @@ add_executable(Bloom
|
|||||||
src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.cpp
|
src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.cpp
|
||||||
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.cpp
|
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.cpp
|
||||||
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.cpp
|
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.cpp
|
||||||
|
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvrIspInterface.cpp
|
||||||
|
|
||||||
# Targets
|
# Targets
|
||||||
src/Targets/TargetDescription/TargetDescriptionFile.cpp
|
src/Targets/TargetDescription/TargetDescriptionFile.cpp
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
#include "EdbgAvrIspInterface.hpp"
|
||||||
|
|
||||||
|
#include "src/TargetController/Exceptions/TargetOperationFailure.hpp"
|
||||||
|
#include "src/Logger/Logger.hpp"
|
||||||
|
|
||||||
|
// Command frames
|
||||||
|
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVRISP/EnterProgrammingMode.hpp"
|
||||||
|
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVRISP/LeaveProgrammingMode.hpp"
|
||||||
|
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVRISP/ReadSignature.hpp"
|
||||||
|
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVRISP/ReadFuse.hpp"
|
||||||
|
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVRISP/ReadLock.hpp"
|
||||||
|
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVRISP/ProgramFuse.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||||
|
{
|
||||||
|
using namespace Targets::Microchip::Avr;
|
||||||
|
|
||||||
|
using CommandFrames::AvrIsp::EnterProgrammingMode;
|
||||||
|
using CommandFrames::AvrIsp::LeaveProgrammingMode;
|
||||||
|
using CommandFrames::AvrIsp::ReadSignature;
|
||||||
|
using CommandFrames::AvrIsp::ReadFuse;
|
||||||
|
using CommandFrames::AvrIsp::ReadLock;
|
||||||
|
using CommandFrames::AvrIsp::ProgramFuse;
|
||||||
|
|
||||||
|
using ResponseFrames::AvrIsp::StatusCode;
|
||||||
|
|
||||||
|
using Exceptions::TargetOperationFailure;
|
||||||
|
|
||||||
|
void EdbgAvrIspInterface::setIspParameters(const Targets::Microchip::Avr::IspParameters& ispParameters) {
|
||||||
|
this->ispParameters = ispParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdbgAvrIspInterface::activate() {
|
||||||
|
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(
|
||||||
|
EnterProgrammingMode(
|
||||||
|
this->ispParameters.programModeTimeout,
|
||||||
|
this->ispParameters.programModeStabilizationDelay,
|
||||||
|
this->ispParameters.programModeCommandExecutionDelay,
|
||||||
|
this->ispParameters.programModeSyncLoops,
|
||||||
|
this->ispParameters.programModeByteDelay,
|
||||||
|
this->ispParameters.programModePollValue,
|
||||||
|
this->ispParameters.programModePollIndex
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.getStatusCode() != StatusCode::OK) {
|
||||||
|
throw TargetOperationFailure(
|
||||||
|
"Failed to enable programming mode via the ISP interface - check target's SPI connection "
|
||||||
|
"and/or its SPIEN fuse bit."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdbgAvrIspInterface::deactivate() {
|
||||||
|
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(
|
||||||
|
LeaveProgrammingMode(
|
||||||
|
this->ispParameters.programModePreDelay,
|
||||||
|
this->ispParameters.programModePostDelay
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.getStatusCode() != StatusCode::OK) {
|
||||||
|
throw TargetOperationFailure("Failed to disable programming mode via the ISP interface.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetSignature EdbgAvrIspInterface::getDeviceId() {
|
||||||
|
// The read signature command only allows us to read one signature byte at a time.
|
||||||
|
return TargetSignature(
|
||||||
|
this->readSignatureByte(0),
|
||||||
|
this->readSignatureByte(1),
|
||||||
|
this->readSignatureByte(2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fuse EdbgAvrIspInterface::readFuse(FuseType fuseType) {
|
||||||
|
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(
|
||||||
|
ReadFuse(fuseType, this->ispParameters.readFusePollIndex)
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto& payload = response.getPayload();
|
||||||
|
if (response.getStatusCode() != StatusCode::OK
|
||||||
|
|| payload.size() < 4
|
||||||
|
|| static_cast<StatusCode>(payload[3]) != StatusCode::OK
|
||||||
|
) {
|
||||||
|
throw TargetOperationFailure(
|
||||||
|
"Failed to read fuse via ISP - response frame status code/size indicates a failure."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Fuse(fuseType, payload[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char EdbgAvrIspInterface::readLockBitByte() {
|
||||||
|
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(
|
||||||
|
ReadLock(this->ispParameters.readLockPollIndex)
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto& payload = response.getPayload();
|
||||||
|
if (response.getStatusCode() != StatusCode::OK
|
||||||
|
|| payload.size() < 4
|
||||||
|
|| static_cast<StatusCode>(payload[3]) != StatusCode::OK
|
||||||
|
) {
|
||||||
|
throw TargetOperationFailure(
|
||||||
|
"Failed to read lock bit byte via ISP - response frame status code/size indicates a failure."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdbgAvrIspInterface::programFuse(Targets::Microchip::Avr::Fuse fuse) {
|
||||||
|
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(
|
||||||
|
ProgramFuse(fuse.type, fuse.value)
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto& payload = response.getPayload();
|
||||||
|
if (response.getStatusCode() != StatusCode::OK || payload.size() < 2) {
|
||||||
|
throw TargetOperationFailure(
|
||||||
|
"Failed to program fuse via ISP - response frame status code/size indicates a failure."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char EdbgAvrIspInterface::readSignatureByte(std::uint8_t signatureByteAddress) {
|
||||||
|
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(
|
||||||
|
ReadSignature(signatureByteAddress, this->ispParameters.readSignaturePollIndex)
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto& payload = response.getPayload();
|
||||||
|
|
||||||
|
if (response.getStatusCode() != StatusCode::OK
|
||||||
|
|| payload.size() < 4
|
||||||
|
|| static_cast<StatusCode>(payload[3]) != StatusCode::OK
|
||||||
|
) {
|
||||||
|
throw TargetOperationFailure(
|
||||||
|
"Failed to read signature byte (address: " + std::to_string(signatureByteAddress)
|
||||||
|
+ ") via ISP - response frame status code/size indicates a failure."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "src/DebugToolDrivers/TargetInterfaces/Microchip/AVR/AvrIspInterface.hpp"
|
||||||
|
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The EdbgAvrIspInterface implements the AVRISP EDBG/CMSIS-DAP protocol, as an AvrIspInterface.
|
||||||
|
*
|
||||||
|
* See the "AVR ISP Protocol" section in the DS50002630A document by Microchip, for more information on the
|
||||||
|
* protocol.
|
||||||
|
*
|
||||||
|
* This implementation should work with any Microchip EDBG-based CMSIS-DAP debug tool with ISP support (such as
|
||||||
|
* the Atmel-ICE, Power Debugger, the MPLAB SNAP debugger (in "AVR mode"), etc).
|
||||||
|
*/
|
||||||
|
class EdbgAvrIspInterface: public TargetInterfaces::Microchip::Avr::AvrIspInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit EdbgAvrIspInterface(EdbgInterface& edbgInterface)
|
||||||
|
: edbgInterface(edbgInterface) {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The EdbgAvrIspInterface doesn't actually require any config from the user, at this point in time. So this
|
||||||
|
* function does nothing, for now.
|
||||||
|
*
|
||||||
|
* @param targetConfig
|
||||||
|
*/
|
||||||
|
void configure(const TargetConfig& targetConfig) override {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts the target's ISP parameters. These should be extracted from the target's TDF.
|
||||||
|
*
|
||||||
|
* @param ispParameters
|
||||||
|
*/
|
||||||
|
void setIspParameters(const Targets::Microchip::Avr::IspParameters& ispParameters) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the ISP interface by enabling "programming mode" on the debug tool. This will activate the
|
||||||
|
* physical (SPI) interface between the debug tool and AVR target.
|
||||||
|
*/
|
||||||
|
void activate() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables "programming mode" on the debug tool, which subsequently deactivates the SPI interface between the
|
||||||
|
* debug tool and AVR target.
|
||||||
|
*/
|
||||||
|
void deactivate() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the AVR signature from the connected AVR.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Targets::Microchip::Avr::TargetSignature getDeviceId() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a particular fuse byte from the AVR target.
|
||||||
|
*
|
||||||
|
* @param fuseType
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Targets::Microchip::Avr::Fuse readFuse(Targets::Microchip::Avr::FuseType fuseType) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the lock bit byte from the AVR target.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
unsigned char readLockBitByte() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Programs a particular fuse on the AVR target.
|
||||||
|
*
|
||||||
|
* @param fuse
|
||||||
|
*/
|
||||||
|
void programFuse(Targets::Microchip::Avr::Fuse fuse) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* The AVRISP protocol is a sub-protocol of the EDBG AVR protocol, which is served via CMSIS-DAP vendor
|
||||||
|
* commands.
|
||||||
|
*
|
||||||
|
* Every EDBG based debug tool that utilises this implementation must provide access to its EDBG interface.
|
||||||
|
*/
|
||||||
|
EdbgInterface& edbgInterface;
|
||||||
|
|
||||||
|
Targets::Microchip::Avr::IspParameters ispParameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The EDBG AVRISP protocol only allows us to read a single signature byte at a time.
|
||||||
|
* This function will read a single signature byte. See implementation of EdbgAvrIspInterface::getDeviceId()
|
||||||
|
* for more.
|
||||||
|
*
|
||||||
|
* @param signatureByteAddress
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
[[nodiscard]] unsigned char readSignatureByte(std::uint8_t signatureByteAddress);
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user