- 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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
Reference in New Issue
Block a user