Implemented RiscVProgramInterface in WchLinkInterface
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/DebugToolDrivers/WCH/Protocols/WchLink/Commands/Command.hpp"
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
|
||||
namespace DebugToolDrivers::Wch::Protocols::WchLink::Commands
|
||||
{
|
||||
class PreparePartialFlashPageWrite: public Command<std::array<unsigned char, 5>>
|
||||
{
|
||||
public:
|
||||
PreparePartialFlashPageWrite(
|
||||
Targets::TargetMemoryAddress startAddress,
|
||||
std::uint8_t bytes
|
||||
)
|
||||
: Command(0x0A)
|
||||
{
|
||||
this->payload = {
|
||||
static_cast<unsigned char>(startAddress >> 24),
|
||||
static_cast<unsigned char>(startAddress >> 16),
|
||||
static_cast<unsigned char>(startAddress >> 8),
|
||||
static_cast<unsigned char>(startAddress),
|
||||
static_cast<unsigned char>(bytes),
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Commands/Control/DetachTarget.hpp"
|
||||
#include "Commands/SetClockSpeed.hpp"
|
||||
#include "Commands/DebugModuleInterfaceOperation.hpp"
|
||||
#include "Commands/PreparePartialFlashPageWrite.hpp"
|
||||
|
||||
#include "src/Helpers/BiMap.hpp"
|
||||
#include "src/Services/StringService.hpp"
|
||||
@@ -108,6 +109,58 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
|
||||
}
|
||||
}
|
||||
|
||||
void WchLinkInterface::writeFlashMemory(
|
||||
Targets::TargetMemoryAddress startAddress,
|
||||
const Targets::TargetMemoryBuffer& buffer
|
||||
) {
|
||||
const auto packetSize = Targets::TargetMemorySize{this->dataEndpointMaxPacketSize};
|
||||
const auto bufferSize = static_cast<Targets::TargetMemorySize>(buffer.size());
|
||||
const auto packetsRequired = static_cast<std::uint32_t>(
|
||||
std::ceil(static_cast<float>(bufferSize) / static_cast<float>(packetSize))
|
||||
);
|
||||
|
||||
for (std::uint32_t i = 0; i < packetsRequired; ++i) {
|
||||
const auto segmentSize = static_cast<std::uint8_t>(std::min(bufferSize - (i * packetSize), packetSize));
|
||||
const auto response = this->sendCommandAndWaitForResponse(
|
||||
Commands::PreparePartialFlashPageWrite(startAddress + (packetSize * i), segmentSize)
|
||||
);
|
||||
|
||||
if (response.payload.size() != 1) {
|
||||
throw Exceptions::DeviceCommunicationFailure(
|
||||
"Unexpected response payload size for PreparePartialFlashPageWrite command"
|
||||
);
|
||||
}
|
||||
|
||||
this->usbInterface.writeBulk(
|
||||
WchLinkInterface::USB_DATA_ENDPOINT_OUT,
|
||||
std::vector<unsigned char>(
|
||||
buffer.begin() + (packetSize * i),
|
||||
buffer.begin() + (packetSize * i) + segmentSize
|
||||
)
|
||||
);
|
||||
|
||||
const auto rawResponse = this->usbInterface.readBulk(WchLinkInterface::USB_DATA_ENDPOINT_IN);
|
||||
|
||||
if (rawResponse.size() != 4) {
|
||||
throw Exceptions::DeviceCommunicationFailure("Unexpected response size for partial flash page write");
|
||||
}
|
||||
|
||||
/*
|
||||
* I have no idea what any of these bytes mean. There's no documentation available for this.
|
||||
*
|
||||
* All I know is that these values indicate a successful write.
|
||||
*/
|
||||
if (
|
||||
rawResponse[0] != 0x41
|
||||
|| rawResponse[1] != 0x01
|
||||
|| rawResponse[2] != 0x01
|
||||
|| rawResponse[3] != 0x02
|
||||
) {
|
||||
throw Exceptions::DeviceCommunicationFailure("Partial flash page write failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WchLinkInterface::setClockSpeed(WchLinkTargetClockSpeed speed) {
|
||||
const auto speedIdsBySpeed = BiMap<WchLinkTargetClockSpeed, std::uint8_t>({
|
||||
{WchLinkTargetClockSpeed::CLK_6000_KHZ, 0x01},
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp"
|
||||
#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVProgramInterface.hpp"
|
||||
#include "src/DebugToolDrivers/USB/UsbInterface.hpp"
|
||||
#include "src/DebugToolDrivers/USB/UsbDevice.hpp"
|
||||
|
||||
@@ -22,7 +23,9 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
|
||||
/**
|
||||
* The WchLinkInterface implements the WCH-Link protocol.
|
||||
*/
|
||||
class WchLinkInterface: public TargetInterfaces::RiscV::RiscVDebugInterface
|
||||
class WchLinkInterface
|
||||
: public TargetInterfaces::RiscV::RiscVDebugInterface
|
||||
, public TargetInterfaces::RiscV::RiscVProgramInterface
|
||||
{
|
||||
public:
|
||||
WchLinkInterface(Usb::UsbInterface& usbInterface, Usb::UsbDevice& usbDevice);
|
||||
@@ -44,6 +47,11 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
|
||||
Targets::RiscV::DebugModule::RegisterValue value
|
||||
) override;
|
||||
|
||||
void writeFlashMemory(
|
||||
Targets::TargetMemoryAddress startAddress,
|
||||
const Targets::TargetMemoryBuffer& buffer
|
||||
) override;
|
||||
|
||||
private:
|
||||
static constexpr std::uint8_t USB_COMMAND_ENDPOINT_IN = 0x81;
|
||||
static constexpr std::uint8_t USB_COMMAND_ENDPOINT_OUT = 0x01;
|
||||
|
||||
@@ -36,6 +36,24 @@ namespace DebugToolDrivers::Wch
|
||||
return this->wchLinkInterface.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* WCH-Link debug tools cannot write to flash memory via the RISC-V debug interface (RiscVDebugInterface).
|
||||
* Flash memory writes via abstract commands fail silently.
|
||||
*
|
||||
* We have to send a vendor-specific command to the debug tool, in order to program the target.
|
||||
*
|
||||
* For this reason, we have to provide an implementation of the RiscVProgramInterface, so that the RISC-V
|
||||
* target driver forwards any flash memory writes to this implementation (instead of relying on the debug
|
||||
* interface).
|
||||
*
|
||||
* The WchLinkInterface implements both the RiscVDebugInterface and the RiscVProgramInterface.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
DebugToolDrivers::TargetInterfaces::RiscV::RiscVProgramInterface* getRiscVProgramInterface() override {
|
||||
return this->wchLinkInterface.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
WchLinkVariant variant;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user