Skip to content

Commit

Permalink
chore: ch32v307 verified
Browse files Browse the repository at this point in the history
  • Loading branch information
andelf committed Oct 3, 2023
1 parent 2f18635 commit 31af071
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 75 deletions.
34 changes: 22 additions & 12 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ impl Command for Program {
/// 0x06 subset
// query -> check -> set
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum FlashProtect {
pub enum ConfigChip {
/// 06, _, 01
CheckReadProtect, // 1 for protected, 2 for unprotected
/// 06, _, 02
Expand All @@ -165,25 +165,34 @@ pub enum FlashProtect {
/// 06, _, 04
CheckReadProtectEx, // 1 for protected, 0 for unprotected,
/// bf, or e7
UnprotectEx(u8), // with 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
UnprotectEx(u8), // with 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
// prefix byte 0xe7 ? for ch32x035
ProtectEx(u8), // with 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
}
impl FlashProtect {
/// Config flags
/// 81 06 08 02 3f 00 00 ff ff ff ff
/// __ __ __ __ __ [DATA] [WRP ]
Config {
/// User data
data: u16,
/// WRP write protection
wrp: u32,
},
}
impl ConfigChip {
pub const FLAG_PROTECTED: u8 = 0x01;
}
impl Command for FlashProtect {
impl Command for ConfigChip {
type Response = u8;
const COMMAND_ID: u8 = 0x06;
fn payload(&self) -> Vec<u8> {
use FlashProtect::*;
match *self {
CheckReadProtect => vec![0x01],
Unprotect => vec![0x02],
Protect => vec![0x03],
CheckReadProtectEx => vec![0x04],
UnprotectEx(b) => vec![0x02, b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
ProtectEx(b) => vec![0x03, b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
ConfigChip::CheckReadProtect => vec![0x01],
ConfigChip::Unprotect => vec![0x02],
ConfigChip::Protect => vec![0x03],
ConfigChip::CheckReadProtectEx => vec![0x04],
ConfigChip::UnprotectEx(b) => vec![0x02, b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
ConfigChip::ProtectEx(b) => vec![0x03, b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
ConfigChip::Config { data: _, wrp: _ } => todo!("ConfigChip"),
}
}
}
Expand Down Expand Up @@ -423,6 +432,7 @@ impl Command for DisableDebug {
// 81 0D 01 0F ClearCodeFlashB
// 81 0D 02 08 xx ClearCodeFlash
// 81 11 01 0D unkown in query info, before GetChipRomRamSplit
// 81 0d 02 ee 00 stop flash ?

#[cfg(test)]
mod tests {
Expand Down
32 changes: 32 additions & 0 deletions src/commands/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,27 @@ impl fmt::Display for AttachChipResponse {
}
}

/// Erase code flash, only supported by WCH-LinkE.
#[derive(Debug)]
pub enum EraseCodeFlash {
ByPinRST,
ByPowerOff,
}
impl Command for EraseCodeFlash {
type Response = ();
const COMMAND_ID: u8 = 0x0d;
fn payload(&self) -> Vec<u8> {
match self {
// TODO: This is more complex, require RST pin to be connected.
EraseCodeFlash::ByPinRST => {
// vec![0x08, 0x06]
todo!("ByPinRST, This is more complex, require RST pin to be connected")
}
EraseCodeFlash::ByPowerOff => vec![0x0f, 0x06],
}
}
}

/// GetROMRAM, Only avaliable for CH32V2, CH32V3, CH56X
/// 0, 1, 2, 3
#[derive(Debug)]
Expand All @@ -108,6 +129,17 @@ impl Command for GetChipRomRamSplit {
}
}

/// 0, 1, 2, 3
#[derive(Debug)]
pub struct SetChipRomRamSplit(u8);
impl Command for SetChipRomRamSplit {
type Response = ();
const COMMAND_ID: u8 = 0x0d;
fn payload(&self) -> Vec<u8> {
vec![0x05, self.0]
}
}

// ?? close out
/// Detach Chip, (0x0d, 0xff)
#[derive(Debug)]
Expand Down
4 changes: 2 additions & 2 deletions src/dmi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use crate::{
use std::{thread, time::Duration};

// FPEC, OPTWRE to unlock,
const KEY1: u32 = 0x45670123;
const KEY2: u32 = 0xCDEF89AB;
pub const KEY1: u32 = 0x45670123;
pub const KEY2: u32 = 0xCDEF89AB;

/// RISC-V DMI
pub trait DebugModuleInterface {
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ impl WchLinkVariant {
!matches!(self, WchLinkVariant::Ch549)
}

/// Only W, E mode support this
pub fn support_pow5v(&self) -> bool {
/// Only W, E mode support this, power functions
pub fn support_power_funcs(&self) -> bool {
matches!(self, WchLinkVariant::WCh32v208 | WchLinkVariant::ECh32v305)
}

Expand Down
56 changes: 37 additions & 19 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ use std::{thread::sleep, time::Duration};

use anyhow::Result;
use wlink::{
commands::{self, RawCommand},
device::WchLink,
dmi::DebugModuleInterface,
format::read_firmware_from_file,
regs, RiscvChip,
commands, device::WchLink, dmi::DebugModuleInterface, format::read_firmware_from_file, regs,
RiscvChip,
};

use clap::{Parser, Subcommand};
Expand Down Expand Up @@ -38,6 +35,16 @@ struct Cli {
command: Option<Commands>,
}

#[derive(Debug, Clone, Copy, clap::ValueEnum)]
enum EraseMode {
/// Erase code flash by power off, the probe will power off the target chip
PowerOff,
/// Erase code flash by RST pin, the probe will active the nRST line. Requires a RST pin connection
PinRst,
/// Erase code flash by probe command
Default,
}

#[derive(Subcommand)]
enum Commands {
/// Dump memory region
Expand All @@ -53,7 +60,11 @@ enum Commands {
/// Dump registers
Regs {},
/// Erase flash
Erase {},
Erase {
/// Erase mode
#[arg(long, default_value = "default")]
method: EraseMode,
},
/// Program the code flash
Flash {
/// Address in u32
Expand Down Expand Up @@ -143,6 +154,7 @@ fn main() -> Result<()> {
None => {
wlink::device::check_usb_device()?;
println!("No command given, use --help for help.");
println!("hint: use `wlink status` to get started.");
}
Some(ModeSwitch { rv, dap }) => {
wlink::device::check_usb_device()?; // list all connected devices
Expand All @@ -161,14 +173,15 @@ fn main() -> Result<()> {
probe.attach_chip(cli.chip)?;
match command {
Dev {} => {
// probe.erase_flash_by_power_off()?;
// const FLASH_KEYR: u32 = 0x2000_0030;
let mut algo = wlink::dmi::Algorigthm::new(&mut probe);
//let mut algo = wlink::dmi::Algorigthm::new(&mut probe);
// algo.write_mem32(FLASH_KEYR, 0x45670123)?;

//algo.ensure_mcu_halt()?;
let address = 0x40001041;
let v = algo.read_mem32(address)?;
println!("0x{:08x}: 0x{:08x}", address, v);
//let address = 0x40001041;
//let v = algo.read_mem32(address)?;
//println!("0x{:08x}: 0x{:08x}", address, v);

// algo.dump_pmp()?;
}
Expand All @@ -195,11 +208,19 @@ fn main() -> Result<()> {
let dmstatus: regs::Dmstatus = probe.read_dmi_reg()?;
log::info!("{dmstatus:#?}");
}
Erase {} => {
log::info!("Erase Flash...");
probe.erase_flash()?;
log::debug!("Wait for some time to finish erase...");
sleep(Duration::from_millis(1000));
Erase { method } => {
log::info!("Erase Flash using {:?}", method);
match method {
EraseMode::Default => {
probe.erase_flash()?;
}
EraseMode::PinRst => {
unimplemented!("Erase by RST pin");
}
EraseMode::PowerOff => {
probe.erase_flash_by_power_off()?;
}
}
}
Flash {
address,
Expand Down Expand Up @@ -234,10 +255,6 @@ fn main() -> Result<()> {
probe.send_command(commands::Reset::ResetAndRun)?;
sleep(Duration::from_millis(500));
}
// reattach
//probe.attach_chip(cli.chip)?;
//log::info!("Resume executing...");
//probe.ensure_mcu_resume()?;
}
Unprotect {} => {
log::info!("Unprotect Flash");
Expand Down Expand Up @@ -267,6 +284,7 @@ fn main() -> Result<()> {
}
Status {} => {
probe.dump_info(true)?;

let dmstatus: regs::Dmstatus = probe.read_dmi_reg()?;
log::info!("{dmstatus:#x?}");
let dmcontrol: regs::Dmcontrol = probe.read_dmi_reg()?;
Expand Down
78 changes: 38 additions & 40 deletions src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ impl WchLink {
};
log::info!("Chip UID: {chip_id}");

let flash_protected = self.send_command(commands::FlashProtect::CheckReadProtect)?;
let protected = flash_protected == commands::FlashProtect::FLAG_PROTECTED;
let flash_protected = self.send_command(commands::ConfigChip::CheckReadProtect)?;
let protected = flash_protected == commands::ConfigChip::FLAG_PROTECTED;
log::info!("Flash protected: {}", protected);
if protected {
log::warn!("Flash is protected, debug access is not available");
Expand Down Expand Up @@ -141,8 +141,8 @@ impl WchLink {
// HACK: requires a fresh attach
self.reattach_chip()?;

let flash_protected_flag = self.send_command(commands::FlashProtect::CheckReadProtect)?;
let protected = flash_protected_flag == commands::FlashProtect::FLAG_PROTECTED;
let flash_protected_flag = self.send_command(commands::ConfigChip::CheckReadProtect)?;
let protected = flash_protected_flag == commands::ConfigChip::FLAG_PROTECTED;
if protect == protected {
log::info!(
"Flash already {}",
Expand All @@ -156,20 +156,20 @@ impl WchLink {

let use_v2 = self.probe.as_ref().unwrap().version() >= (2, 9);
let cmd = match (protect, use_v2) {
(true, true) => commands::FlashProtect::ProtectEx(0xbf),
(true, false) => commands::FlashProtect::Protect,
(false, true) => commands::FlashProtect::UnprotectEx(0xbf),
(false, false) => commands::FlashProtect::Unprotect,
(true, true) => commands::ConfigChip::ProtectEx(0xbf),
(true, false) => commands::ConfigChip::Protect,
(false, true) => commands::ConfigChip::UnprotectEx(0xbf),
(false, false) => commands::ConfigChip::Unprotect,
};
self.send_command(cmd)?;

self.send_command(commands::Reset::ResetAndRun)?; // quit reset
self.send_command(control::AttachChip)?;

let flash_protected = self.send_command(commands::FlashProtect::CheckReadProtect)?;
let flash_protected = self.send_command(commands::ConfigChip::CheckReadProtect)?;
log::info!(
"Flash protected: {}",
flash_protected == commands::FlashProtect::FLAG_PROTECTED
flash_protected == commands::ConfigChip::FLAG_PROTECTED
);

Ok(())
Expand Down Expand Up @@ -240,6 +240,18 @@ impl WchLink {
Ok(mem)
}

/// Clear All Code Flash - By Power off
pub fn erase_flash_by_power_off(&mut self) -> Result<()> {
if self.probe.as_ref().unwrap().variant.support_power_funcs() {
self.send_command(control::EraseCodeFlash::ByPowerOff)?;
Ok(())
} else {
Err(Error::Custom(format!(
"Probe doesn't support power off erase",
)))
}
}

/// Erases flash and re-attach
pub fn erase_flash(&mut self) -> Result<()> {
if self
Expand All @@ -249,8 +261,8 @@ impl WchLink {
.chip_family
.support_flash_protect()
{
let ret = self.send_command(commands::FlashProtect::CheckReadProtect)?;
if ret == commands::FlashProtect::FLAG_PROTECTED {
let ret = self.send_command(commands::ConfigChip::CheckReadProtect)?;
if ret == commands::ConfigChip::FLAG_PROTECTED {
log::warn!("Flash is protected, unprotecting...");
self.protect_flash(false)?;
} else if ret == 2 {
Expand All @@ -275,7 +287,7 @@ impl WchLink {
self.protect_flash(false)?;
}

let mut data = data.to_vec();
let data = data.to_vec();

// if data.len() % data_packet_size != 0 {
// data.resize((data.len() / data_packet_size + 1) * data_packet_size, 0xff);
Expand All @@ -287,49 +299,35 @@ impl WchLink {
data_packet_size
);

//if data.len() < write_pack_size as usize {
// data.resize(write_pack_size as usize, 0xff);
// }

// let mut retries = 0;
// while retries < 1 {
// wlink_ready_write
self.send_command(Program::Prepare)?;
// self.send_command(Program::Prepare)?; // no need for CH32V307
self.send_command(SetWriteMemoryRegion {
start_addr: address,
len: data.len() as _,
})?;

//std::thread::sleep(Duration::from_millis(10));
// if self.chip.as_ref().unwrap().chip_family == RiscvChip::CH32V103 {}
for _ in 0..1 {
self.send_command(Program::WriteFlashOP)?;
// wlink_ramcodewrite
self.device_handle
.write_data_endpoint(self.chip.as_ref().unwrap().chip_family.flash_op(), 128)?;
self.send_command(Program::WriteFlashOP)?;
// wlink_ramcodewrite
self.device_handle.write_data_endpoint(
self.chip.as_ref().unwrap().chip_family.flash_op(),
data_packet_size,
)?;

log::debug!("Flash OP written");

log::debug!("Flash OP written");

std::thread::sleep(Duration::from_millis(10));

if let Ok(n) = self.send_command(Program::Unknown07AfterFlashOPWritten) {
if n == 0x07 {
//return Err(Error::Custom(
// "Unknown07AfterFlashOPWritten failed".to_string(),
//));
break;
}
}
std::thread::sleep(Duration::from_millis(100));
let n = self.send_command(Program::Unknown07AfterFlashOPWritten)?;
if n != 0x07 {
return Err(Error::Custom(
"Unknown07AfterFlashOPWritten failed".to_string(),
));
}

// wlink_fastprogram
self.send_command(Program::WriteFlash)?;
for chunk in data.chunks(write_pack_size as usize) {
self.device_handle
.write_data_endpoint(&chunk, data_packet_size)?;
//std::thread::sleep(Duration::from_secs(2));
let rxbuf = self.device_handle.read_data_endpoint(4)?;
// 41 01 01 04
if rxbuf[3] != 0x04 {
Expand Down

0 comments on commit 31af071

Please sign in to comment.