- Implemented program memory erasure routine in WchRiscV target driver

- Moved away from relying on WCH-Link debug tool command for erasing program memory, due to a bug that I couldn't fix
- Small tweaks to programming method selection in WCH-Link driver
- Refactored flash peripheral registers in WchRiscV target driver
This commit is contained in:
Nav
2025-01-29 23:48:32 +00:00
parent 55b8bf17fe
commit 7466850478
10 changed files with 166 additions and 33 deletions

View File

@@ -31,6 +31,13 @@ namespace Targets
assert(registerDescriptor.size <= 8);
}
DynamicRegisterValue& DynamicRegisterValue::operator = (const DynamicRegisterValue& other) {
assert(other.registerDescriptor == this->registerDescriptor);
this->value = other.value;
return *this;
}
void DynamicRegisterValue::setBitField(
const TargetBitFieldDescriptor& bitFieldDescriptor,
std::uint64_t inputValue

View File

@@ -19,6 +19,8 @@ namespace Targets
DynamicRegisterValue(const TargetRegisterDescriptor& registerDescriptor, TargetMemoryBufferSpan value);
DynamicRegisterValue(const TargetRegisterDescriptor& registerDescriptor, std::uint64_t value);
DynamicRegisterValue& operator = (const DynamicRegisterValue& other);
void setBitField(const TargetBitFieldDescriptor& bitFieldDescriptor, std::uint64_t inputValue);
void setBitField(const std::string& bitFieldKey, std::uint64_t inputValue);

View File

@@ -0,0 +1,14 @@
#pragma once
#include "src/Targets/TargetBitFieldDescriptor.hpp"
#include "src/Targets/RiscV/Wch/TargetDescriptionFile.hpp"
namespace Targets::RiscV::Wch::Peripherals::Flash
{
struct FlashControlRegisterFields
{
const TargetBitFieldDescriptor& locked;
const TargetBitFieldDescriptor& startErase;
const TargetBitFieldDescriptor& mainSegmentErase;
};
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include "src/Targets/TargetBitFieldDescriptor.hpp"
#include "src/Targets/RiscV/Wch/TargetDescriptionFile.hpp"
namespace Targets::RiscV::Wch::Peripherals::Flash
{
struct FlashStatusRegisterFields
{
const TargetBitFieldDescriptor& busy;
const TargetBitFieldDescriptor& bootLock;
const TargetBitFieldDescriptor& bootMode;
};
}

View File

@@ -2,6 +2,8 @@
#include <utility>
#include <cassert>
#include <chrono>
#include <thread>
#include "src/Targets/DynamicRegisterValue.hpp"
@@ -12,6 +14,7 @@
#include "src/Services/StringService.hpp"
#include "src/Logger/Logger.hpp"
#include "src/TargetController/Exceptions/TargetOperationFailure.hpp"
namespace Targets::RiscV::Wch
{
@@ -36,8 +39,21 @@ namespace Targets::RiscV::Wch
, flashKeyRegisterDescriptor(this->flashPeripheralDescriptor.getRegisterDescriptor("flash", "keyr"))
, flashBootKeyRegisterDescriptor(this->flashPeripheralDescriptor.getRegisterDescriptor("flash", "boot_modekeyr"))
, flashStatusRegisterDescriptor(this->flashPeripheralDescriptor.getRegisterDescriptor("flash", "statr"))
, flashStatusBootLockFieldDescriptor(this->flashStatusRegisterDescriptor.getBitFieldDescriptor("boot_lock"))
, flashStatusBootModeFieldDescriptor(this->flashStatusRegisterDescriptor.getBitFieldDescriptor("boot_mode"))
, flashControlRegisterDescriptor(this->flashPeripheralDescriptor.getRegisterDescriptor("flash", "ctrl"))
, flashControlRegisterFields(
Peripherals::Flash::FlashControlRegisterFields{
.locked = this->flashControlRegisterDescriptor.getBitFieldDescriptor("lock"),
.startErase = this->flashControlRegisterDescriptor.getBitFieldDescriptor("strt"),
.mainSegmentErase = this->flashControlRegisterDescriptor.getBitFieldDescriptor("mer"),
}
)
, flashStatusRegisterFields(
Peripherals::Flash::FlashStatusRegisterFields{
.busy = this->flashStatusRegisterDescriptor.getBitFieldDescriptor("bsy"),
.bootLock = this->flashStatusRegisterDescriptor.getBitFieldDescriptor("boot_lock"),
.bootMode = this->flashStatusRegisterDescriptor.getBitFieldDescriptor("boot_mode"),
}
)
, rccPeripheralDescriptor(this->targetDescriptionFile.getTargetPeripheralDescriptor("rcc"))
, portPeripheralClockEnableRegisterDescriptor(
this->rccPeripheralDescriptor.getRegisterDescriptor("rcc", "apb2pcenr")
@@ -321,11 +337,17 @@ namespace Targets::RiscV::Wch
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
const TargetMemorySegmentDescriptor& memorySegmentDescriptor
) {
if (memorySegmentDescriptor == this->mappedSegmentDescriptor) {
return RiscV::eraseMemory(addressSpaceDescriptor, this->selectedProgramSegmentDescriptor);
if (
memorySegmentDescriptor == this->mainProgramSegmentDescriptor
|| (
memorySegmentDescriptor == this->mappedSegmentDescriptor
&& this->selectedProgramSegmentDescriptor == this->mainProgramSegmentDescriptor
)
) {
return this->eraseMainFlashSegment();
}
RiscV::eraseMemory(addressSpaceDescriptor, memorySegmentDescriptor);
Logger::debug("Ignoring erase operation on `" + memorySegmentDescriptor.key + "` segment - not supported");
}
TargetMemoryAddress WchRiscV::getProgramCounter() {
@@ -659,11 +681,11 @@ namespace Targets::RiscV::Wch
auto statusRegister = this->readRegisterDynamicValue(this->flashStatusRegisterDescriptor);
if (statusRegister.bitFieldAs<bool>(this->flashStatusBootLockFieldDescriptor)) {
if (statusRegister.bitFieldAs<bool>(this->flashStatusRegisterFields.bootLock)) {
throw Exceptions::Exception{"Failed to unlock boot mode field"};
}
statusRegister.setBitField(this->flashStatusBootModeFieldDescriptor, true);
statusRegister.setBitField(this->flashStatusRegisterFields.bootMode, true);
this->writeRegister(statusRegister);
this->reset();
@@ -675,16 +697,59 @@ namespace Targets::RiscV::Wch
auto statusRegister = this->readRegisterDynamicValue(this->flashStatusRegisterDescriptor);
if (statusRegister.bitFieldAs<bool>(this->flashStatusBootLockFieldDescriptor)) {
if (statusRegister.bitFieldAs<bool>(this->flashStatusRegisterFields.bootLock)) {
throw Exceptions::Exception{"Failed to unlock boot mode field"};
}
statusRegister.setBitField(this->flashStatusBootModeFieldDescriptor, false);
statusRegister.setBitField(this->flashStatusRegisterFields.bootMode, false);
this->writeRegister(statusRegister);
this->reset();
}
void WchRiscV::eraseMainFlashSegment() {
static constexpr auto ERASE_RESPONSE_DELAY = std::chrono::microseconds{10};
static constexpr auto ERASE_TIMEOUT = std::chrono::milliseconds{100};
this->unlockFlash();
auto statusRegister = this->readRegisterDynamicValue(this->flashStatusRegisterDescriptor);
if (statusRegister.bitFieldAs<bool>(this->flashStatusRegisterFields.busy)) {
throw Exceptions::TargetOperationFailure{"Flash peripheral is unavailable"};
}
auto controlRegister = this->readRegisterDynamicValue(this->flashControlRegisterDescriptor);
if (controlRegister.bitFieldAs<bool>(this->flashControlRegisterFields.locked)) {
throw Exceptions::TargetOperationFailure{"Failed to unlock flash"};
}
// It seems we have to write these bit fields individually. Otherwise, the target misbehaves
controlRegister.setBitField(this->flashControlRegisterFields.mainSegmentErase, true);
this->writeRegister(controlRegister);
controlRegister.setBitField(this->flashControlRegisterFields.startErase, true);
this->writeRegister(controlRegister);
statusRegister = this->readRegisterDynamicValue(this->flashStatusRegisterDescriptor);
for (
auto attempts = 0;
statusRegister.bitFieldAs<bool>(this->flashStatusRegisterFields.busy)
&& (ERASE_RESPONSE_DELAY * attempts) <= ERASE_TIMEOUT;
++attempts
) {
std::this_thread::sleep_for(ERASE_RESPONSE_DELAY);
statusRegister = this->readRegisterDynamicValue(this->flashStatusRegisterDescriptor);
}
controlRegister = this->readRegisterDynamicValue(this->flashControlRegisterDescriptor);
controlRegister.setBitField(this->flashControlRegisterFields.mainSegmentErase, false);
controlRegister.setBitField(this->flashControlRegisterFields.startErase, false);
this->writeRegister(controlRegister);
if (statusRegister.bitFieldAs<bool>(this->flashStatusRegisterFields.busy)) {
throw Exceptions::TargetOperationFailure{"Erase operation timed out"};
}
}
std::map<TargetPadId, GpioPadDescriptor> WchRiscV::generateGpioPadDescriptorMapping(
const TargetRegisterDescriptor& portPeripheralClockEnableRegisterDescriptor,
const std::vector<TargetPeripheralDescriptor>& portPeripheralDescriptors,

View File

@@ -12,11 +12,16 @@
#include "WchRiscVTargetConfig.hpp"
#include "TargetDescriptionFile.hpp"
#include "GpioPadDescriptor.hpp"
#include "Peripherals/Flash/FlashControlRegisterFields.hpp"
#include "Peripherals/Flash/FlashStatusRegisterFields.hpp"
namespace Targets::RiscV::Wch
{
class WchRiscV: public ::Targets::RiscV::RiscV
class WchRiscV
: public ::Targets::RiscV::RiscV
, public DeltaProgrammingInterface
{
public:
WchRiscV(const TargetConfig& targetConfig, TargetDescriptionFile&& targetDescriptionFile);
@@ -88,9 +93,10 @@ namespace Targets::RiscV::Wch
const TargetRegisterDescriptor& flashKeyRegisterDescriptor;
const TargetRegisterDescriptor& flashBootKeyRegisterDescriptor;
const TargetRegisterDescriptor& flashStatusRegisterDescriptor;
const TargetRegisterDescriptor& flashControlRegisterDescriptor;
const TargetBitFieldDescriptor& flashStatusBootLockFieldDescriptor;
const TargetBitFieldDescriptor& flashStatusBootModeFieldDescriptor;
const Peripherals::Flash::FlashControlRegisterFields flashControlRegisterFields;
const Peripherals::Flash::FlashStatusRegisterFields flashStatusRegisterFields;
const TargetPeripheralDescriptor rccPeripheralDescriptor;
const TargetRegisterDescriptor& portPeripheralClockEnableRegisterDescriptor;
@@ -109,6 +115,7 @@ namespace Targets::RiscV::Wch
void unlockBootModeBitField();
void enableBootMode();
void enableUserMode();
void eraseMainFlashSegment();
static std::map<TargetPadId, GpioPadDescriptor> generateGpioPadDescriptorMapping(
const TargetRegisterDescriptor& portPeripheralClockEnableRegisterDescriptor,

View File

@@ -1932,7 +1932,7 @@
<bit-field key="wrprterr" name="WRPRTERR" description="Write Protected Error Flag" mask="0x00000010" access="RW"/>
<bit-field key="bsy" name="BSY" description="Busy Status" mask="0x00000001" access="R"/>
</register>
<register key="ctlr" name="CTLR" description="Control" offset="0x10" size="4" initial-value="0x00008080" access="RW">
<register key="ctrl" name="CTRL" description="Control" offset="0x10" size="4" initial-value="0x00008080" access="RW">
<bit-field key="bufrst" name="BUFRST" description="Reset BUF Cache" mask="0x00080000" access="RW"/>
<bit-field key="bufload" name="BUFLOAD" description="BUF Cache Enable" mask="0x00040000" access="RW"/>
<bit-field key="fter" name="FTER" description="Select Fast Page Erase Operation" mask="0x00020000" access="RW"/>

View File

@@ -3227,7 +3227,7 @@
<bit-field key="errie" name="ERRIE" description="Error Interrupt Enable" mask="0x00000400" access="RW"/>
<bit-field key="obwre" name="OBWRE" description="Flash Address Locked Flag" mask="0x00000200" access="RW"/>
<bit-field key="lock" name="LOCK" description="FPEC and CTRL Write-lock Enable" mask="0x00000080" access="RW"/>
<bit-field key="strt" name="STRT" description="Start Operation" mask="0x00000040" access="RW"/>
<bit-field key="strt" name="STRT" description="Start Erase Operation" mask="0x00000040" access="RW"/>
<bit-field key="ober" name="OBER" description="Select Word Erase Operation" mask="0x00000020" access="RW"/>
<bit-field key="obpg" name="OBPG" description="Select Word Programming Operation" mask="0x00000010" access="RW"/>
<bit-field key="mer" name="MER" description="Select User Area Erase Operation" mask="0x00000004" access="RW"/>