From 31af071336cbbfdf507547f268f5abcb6c4d78a5 Mon Sep 17 00:00:00 2001 From: Andelf Date: Wed, 4 Oct 2023 00:52:42 +0800 Subject: [PATCH] chore: ch32v307 verified --- src/commands.rs | 34 +++++++++++------- src/commands/control.rs | 32 +++++++++++++++++ src/dmi.rs | 4 +-- src/lib.rs | 4 +-- src/main.rs | 56 +++++++++++++++++++---------- src/operations.rs | 78 ++++++++++++++++++++--------------------- 6 files changed, 133 insertions(+), 75 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index dbe3373..3ccc830 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -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 @@ -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 { - 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"), } } } @@ -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 { diff --git a/src/commands/control.rs b/src/commands/control.rs index e976e1c..b99f2ff 100644 --- a/src/commands/control.rs +++ b/src/commands/control.rs @@ -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 { + 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)] @@ -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 { + vec![0x05, self.0] + } +} + // ?? close out /// Detach Chip, (0x0d, 0xff) #[derive(Debug)] diff --git a/src/dmi.rs b/src/dmi.rs index 110a5f1..70e8e92 100644 --- a/src/dmi.rs +++ b/src/dmi.rs @@ -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 { diff --git a/src/lib.rs b/src/lib.rs index 179a1b8..9aee154 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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) } diff --git a/src/main.rs b/src/main.rs index e35c2b5..2acb328 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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}; @@ -38,6 +35,16 @@ struct Cli { command: Option, } +#[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 @@ -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 @@ -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 @@ -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()?; } @@ -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, @@ -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"); @@ -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()?; diff --git a/src/operations.rs b/src/operations.rs index 4aa263c..2d1b903 100644 --- a/src/operations.rs +++ b/src/operations.rs @@ -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"); @@ -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 {}", @@ -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(()) @@ -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 @@ -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 { @@ -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); @@ -287,41 +299,28 @@ 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 @@ -329,7 +328,6 @@ impl WchLink { 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 {