Added PostAttach command in WCH-Link interface.
Also some bits of tidying
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "src/DebugToolDrivers/WCH/Protocols/WchLink/Commands/Command.hpp"
|
||||||
|
|
||||||
|
namespace DebugToolDrivers::Wch::Protocols::WchLink::Commands::Control
|
||||||
|
{
|
||||||
|
class PostAttach: public Command<std::array<unsigned char, 1>>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PostAttach()
|
||||||
|
: Command(0x0d)
|
||||||
|
{
|
||||||
|
this->payload = {
|
||||||
|
0x03
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Commands/Control/GetDeviceInfo.hpp"
|
#include "Commands/Control/GetDeviceInfo.hpp"
|
||||||
#include "Commands/Control/AttachTarget.hpp"
|
#include "Commands/Control/AttachTarget.hpp"
|
||||||
#include "Commands/Control/DetachTarget.hpp"
|
#include "Commands/Control/DetachTarget.hpp"
|
||||||
|
#include "Commands/Control/PostAttach.hpp"
|
||||||
#include "Commands/SetClockSpeed.hpp"
|
#include "Commands/SetClockSpeed.hpp"
|
||||||
#include "Commands/DebugModuleInterfaceOperation.hpp"
|
#include "Commands/DebugModuleInterfaceOperation.hpp"
|
||||||
#include "Commands/PreparePartialFlashPageWrite.hpp"
|
#include "Commands/PreparePartialFlashPageWrite.hpp"
|
||||||
@@ -61,16 +62,47 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
|
|||||||
void WchLinkInterface::activate() {
|
void WchLinkInterface::activate() {
|
||||||
this->setClockSpeed(WchLinkTargetClockSpeed::CLK_6000_KHZ);
|
this->setClockSpeed(WchLinkTargetClockSpeed::CLK_6000_KHZ);
|
||||||
|
|
||||||
const auto response = this->sendCommandAndWaitForResponse(Commands::Control::AttachTarget{});
|
auto response = this->sendCommandAndWaitForResponse(Commands::Control::AttachTarget{});
|
||||||
if (response.payload.size() != 5) {
|
if (response.payload.size() != 5) {
|
||||||
throw Exceptions::DeviceCommunicationFailure{"Unexpected response payload size for AttachTarget command"};
|
throw Exceptions::DeviceCommunicationFailure{"Unexpected response payload size for AttachTarget command"};
|
||||||
}
|
}
|
||||||
|
|
||||||
this->cachedTargetId = static_cast<WchTargetId>(
|
this->cachedTargetId = response.payload[0];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For some WCH targets, we must send another command to the debug tool, immediately after attaching.
|
||||||
|
*
|
||||||
|
* I don't know what this post-attach command does. But what I *do* know is that the target and/or the debug
|
||||||
|
* tool will misbehave if we don't send it immediately after the attach.
|
||||||
|
*
|
||||||
|
* More specifically, the debug tool will read an invalid target variant ID upon the mutation of the target's
|
||||||
|
* program buffer. So when we write to progbuf2, progbuf3, progbuf4 or progbuf5, all subsequent reads of the
|
||||||
|
* target variant ID will yield invalid values, until the target and debug tool have been power cycled.
|
||||||
|
* Interestingly, when we restore those progbuf registers to their original values, the reading of the target
|
||||||
|
* variant ID works again. So I suspect the debug tool is using the target's program buffer to read the
|
||||||
|
* variant ID, but it's assuming the program buffer hasn't changed. Maybe.
|
||||||
|
*
|
||||||
|
* So how does this post-attach command fix this issue? I don't know. I just know that it does.
|
||||||
|
*
|
||||||
|
* In addition to sending the post-attach command, we have to send another attach command, because the target
|
||||||
|
* variant ID returned in the response of the first attach command may be invalid. Sending another attach
|
||||||
|
* command will ensure that we have a valid target variant ID.
|
||||||
|
*/
|
||||||
|
if (this->cachedTargetId == 0x09) {
|
||||||
|
this->sendCommandAndWaitForResponse(Commands::Control::PostAttach{});
|
||||||
|
response = this->sendCommandAndWaitForResponse(Commands::Control::AttachTarget{});
|
||||||
|
|
||||||
|
if (response.payload.size() != 5) {
|
||||||
|
throw Exceptions::DeviceCommunicationFailure{
|
||||||
|
"Unexpected response payload size for subsequent AttachTarget command"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->cachedVariantId = static_cast<WchTargetVariantId>(
|
||||||
(response.payload[1] << 24) | (response.payload[2] << 16) | (response.payload[3] << 8)
|
(response.payload[1] << 24) | (response.payload[2] << 16) | (response.payload[3] << 8)
|
||||||
| (response.payload[4])
|
| (response.payload[4])
|
||||||
);
|
);
|
||||||
this->cachedTargetGroupId = response.payload[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WchLinkInterface::deactivate() {
|
void WchLinkInterface::deactivate() {
|
||||||
@@ -81,7 +113,7 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string WchLinkInterface::getDeviceId() {
|
std::string WchLinkInterface::getDeviceId() {
|
||||||
return "0x" + Services::StringService::toHex(this->cachedTargetId.value());
|
return "0x" + Services::StringService::toHex(this->cachedVariantId.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugModule::RegisterValue WchLinkInterface::readDebugModuleRegister(DebugModule::RegisterAddress address) {
|
DebugModule::RegisterValue WchLinkInterface::readDebugModuleRegister(DebugModule::RegisterAddress address) {
|
||||||
@@ -261,7 +293,7 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
|
|||||||
};
|
};
|
||||||
|
|
||||||
const auto response = this->sendCommandAndWaitForResponse(
|
const auto response = this->sendCommandAndWaitForResponse(
|
||||||
Commands::SetClockSpeed{this->cachedTargetGroupId.value_or(0x01), speedIdsBySpeed.at(speed)}
|
Commands::SetClockSpeed{this->cachedTargetId.value_or(0x01), speedIdsBySpeed.at(speed)}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.payload.size() != 1) {
|
if (response.payload.size() != 1) {
|
||||||
|
|||||||
@@ -75,17 +75,12 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
|
|||||||
/**
|
/**
|
||||||
* The 'target activation' command returns a payload of 5 bytes.
|
* The 'target activation' command returns a payload of 5 bytes.
|
||||||
*
|
*
|
||||||
* The last 4 bytes hold the WCH RISC-V target ID. Given that the 'target activation' command appears to be
|
* The last 4 bytes hold the WCH target variant ID. Given that the 'target activation' command appears to be
|
||||||
* the only way to obtain the target ID, we cache it via WchLinkInterface::cachedTargetId and return the
|
* the only way to obtain this ID, we cache it via WchLinkInterface::cachedVariantId and return the cached
|
||||||
* cached value in WchLinkInterface::getTargetId().
|
* value in WchLinkInterface::getTargetId().
|
||||||
*
|
|
||||||
* As for the first byte in the payload, I'm not really sure what it is. It appears to be some kind of
|
|
||||||
* identifier for groups of WCH RISC-V targets. It's unclear. All I know is that it has some significance, as
|
|
||||||
* it's expected in the payload of some other commands, such as the command to set clock speed. For this
|
|
||||||
* reason, we have to keep hold of it via WchLinkInterface::cachedTargetGroupId.
|
|
||||||
*/
|
*/
|
||||||
|
std::optional<WchTargetVariantId> cachedVariantId;
|
||||||
std::optional<WchTargetId> cachedTargetId;
|
std::optional<WchTargetId> cachedTargetId;
|
||||||
std::optional<std::uint8_t> cachedTargetGroupId;
|
|
||||||
|
|
||||||
void setClockSpeed(WchLinkTargetClockSpeed speed);
|
void setClockSpeed(WchLinkTargetClockSpeed speed);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
namespace DebugToolDrivers::Wch
|
namespace DebugToolDrivers::Wch
|
||||||
{
|
{
|
||||||
using WchTargetId = std::uint32_t;
|
using WchTargetId = std::uint8_t;
|
||||||
|
using WchTargetVariantId = std::uint32_t;
|
||||||
|
|
||||||
enum class WchLinkVariant: std::uint8_t
|
enum class WchLinkVariant: std::uint8_t
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user