Browse Source

refactor: impl mode switch; See-also: #3

pull/28/head
Andelf 1 year ago
parent
commit
8c7486045c
  1. 4
      README.md
  2. 2
      docs/CH32V307.md
  3. 8
      docs/references.md
  4. 14
      protocol.md
  5. 4
      src/commands.rs
  6. 4
      src/commands/control.rs
  7. 104
      src/device.rs
  8. 4
      src/error.rs
  9. 8
      src/flash_op.rs
  10. 46
      src/lib.rs
  11. 64
      src/main.rs
  12. 14
      src/operations.rs

4
README.md

@ -51,7 +51,7 @@
> # Flash firmware.bin to Code FLASH at address 0x08000000
> cargo run -- flash --address 0x08000000 ./firmware.bin
12:10:26 [INFO] WCH-Link v2.8 (WCH-Link-CH549)
12:10:26 [INFO] Attached chip: CH32V30x(0x30700518)
12:10:26 [INFO] Attached chip: CH32V30X(0x30700518)
12:10:26 [INFO] Flashing 8068 bytes to 0x08000000
12:10:27 [INFO] Flash done
12:10:28 [INFO] Now reset...
@ -62,7 +62,7 @@
18:31:18 [DEBUG] (1) wlink::device: Acquired libusb context.
18:31:18 [DEBUG] (1) wlink::device: Claimed interface 0 of USB device.
18:31:18 [INFO] WCH-Link v2.8 (WCH-LinkE-CH32V305)
18:31:18 [DEBUG] (1) wlink::operations: attached chip: ChipInfo { chip_family: CH32V20x, chip_type: "0x20360510" }
18:31:18 [DEBUG] (1) wlink::operations: attached chip: ChipInfo { chip_family: CH32V20X, chip_type: "0x20360510" }
18:31:18 [DEBUG] (1) wlink::operations: Chip UID: cd-ab-b4-ae-45-bc-c6-16
18:31:18 [DEBUG] (1) wlink::operations: flash protected: false
18:31:18 [DEBUG] (1) wlink::operations: SRAM CODE mode: 3

2
docs/CH32V307.md

@ -3,7 +3,7 @@
```console
wlink -v dump 0x08000000 0x10`
14:40:22 [INFO] WCH-Link v2.8 (WCH-LinkE-CH32V305)
14:40:22 [INFO] attached chip: CH32V30x(0x30700518)
14:40:22 [INFO] attached chip: CH32V30X(0x30700518)
14:40:22 [DEBUG] (1) wlink::operations: Chip UID: 30-78-3e-26-3b-38-a9-d6
14:40:22 [DEBUG] (1) wlink::operations: flash protected: false
14:40:22 [DEBUG] (1) wlink::operations: SRAM CODE mode: 3

8
docs/references.md

@ -36,8 +36,8 @@
| CH32F20x | ✓ | ✓ | ✓ | ✓ |
| CH32V003 | | ✓ | ✓ | |
| CH32V10x | ✓ | ✓ | ✓ | |
| CH32V20x | ✓ | ✓ | ✓ | |
| CH32V30x | ✓ | ✓ | ✓ | |
| CH32V20X | ✓ | ✓ | ✓ | |
| CH32V30X | ✓ | ✓ | ✓ | |
| CH569 | ✓ | ✓ | | |
| CH573 | ✓ | ✓ | | |
| CH579 | ✓ | ✓ | ✓ | ✓ |
@ -68,8 +68,8 @@
| CH32F20x | PA13 | PA14 |
| CH32V003 | PD1 | |
| CH32V10x | PA13 | PA14 |
| CH32V20x | PA13 | PA14 |
| CH32V30x | PA13 | PA14 |
| CH32V20X | PA13 | PA14 |
| CH32V30X | PA13 | PA14 |
| CH32X035 | PC18 | PC19 |
| CH569 | PA11 | PA10 |
| CH573 | PB14 | PB15 |

14
protocol.md

@ -131,15 +131,15 @@ pub enum RiscvChip {
/// CH32V103 RISC-V3A series
CH32V103 = 0x01,
/// CH571/CH573 RISC-V3A BLE 4.2 series
CH57x = 0x02,
CH57X = 0x02,
/// CH565/CH569 RISC-V3A series
CH56x = 0x03,
/// CH32V20x RISC-V4B/V4C series
CH32V20x = 0x05,
/// CH32V30x RISC-V4C/V4F series
CH32V30x = 0x06,
CH56X = 0x03,
/// CH32V20X RISC-V4B/V4C series
CH32V20X = 0x05,
/// CH32V30X RISC-V4C/V4F series
CH32V30X = 0x06,
/// CH581/CH582/CH583 RISC-V4A BLE 5.3 series
CH58x = 0x07,
CH58X = 0x07,
/// CH32V003 RISC-V2A series
CH32V003 = 0x09,
}

4
src/commands.rs

@ -1,10 +1,10 @@
//! WCH-Link commands and response types
//! WCH-Link commands and response types.
use std::fmt;
use crate::error::{Error, Result};
// 0x0d
// 0x0d subset
pub mod control;
/// Command to call the WCH-Link

4
src/commands/control.rs

@ -96,7 +96,7 @@ impl Command for DetachChip {
}
}
/// Only avaliable for CH32V2, CH32V3, CH56x
/// Only avaliable for CH32V2, CH32V3, CH56X
/// 0, 1, 2, 3
pub struct GetChipRomRamSplit;
impl Command for GetChipRomRamSplit {
@ -107,7 +107,7 @@ impl Command for GetChipRomRamSplit {
}
}
/// Special command for CH32V20x, CH32V30x, CH32V003, CH32V103
/// Special command for CH32V20X, CH32V30X, CH32V003, CH32V103
/// After attach chip
pub struct Unknown3;
impl Command for Unknown3 {

104
src/device.rs

@ -1,9 +1,10 @@
//! WchLink device type
use log::info;
use rusb::{DeviceHandle, UsbContext};
use crate::{
commands::{ChipId, Response},
commands::{ChipId, RawCommand, Response},
transport::Transport,
Result, RiscvChip,
};
@ -14,6 +15,12 @@ const PRODUCT_ID: u16 = 0x8010;
const ENDPOINT_OUT: u8 = 0x01;
const ENDPOINT_IN: u8 = 0x81;
const VENDOR_ID_DAP: u16 = 0x1a86;
const PRODUCT_ID_DAP: u16 = 0x8012;
const ENDPOINT_OUT_DAP: u8 = 0x02;
// const ENDPOINT_IN_DAP: u8 = 0x83;
/// Attached chip information
#[derive(Debug)]
pub struct ChipInfo {
@ -29,8 +36,8 @@ pub struct ChipInfo {
pub memory_start_addr: u32,
// Fields for ROM/RAM split
pub sram_code_mode: u8,
pub(crate) rom_kb: u32,
pub(crate) ram_kb: u32,
//pub(crate) rom_kb: u32,
//pub(crate) ram_kb: u32,
}
#[derive(Debug)]
@ -54,18 +61,15 @@ impl WchLink {
.unwrap_or(false)
})
.nth(nth)
.map_or(
Err(crate::error::Error::Custom("No such device".to_string())),
Ok,
)?;
.map_or(Err(crate::error::Error::ProbeNotFound), Ok)?;
let mut device_handle = device.open()?;
let config = device.active_config_descriptor()?;
let descriptor = device.device_descriptor()?;
// let descriptor = device.device_descriptor()?;
log::trace!("Device descriptor: {:?}", &descriptor);
log::trace!("Device: {:?}", &device);
device_handle.claim_interface(0)?;
@ -114,3 +118,85 @@ impl Drop for WchLink {
let _ = self.device_handle.release_interface(0);
}
}
/// Switch from DAP mode to RV mode
// ref: https://github.com/cjacker/wchlinke-mode-switch/blob/main/main.c
pub fn try_switch_from_rv_to_dap(nth: usize) -> Result<()> {
let dev = open_usb_device(VENDOR_ID, PRODUCT_ID, nth)?;
info!("Switch mode WCH-LinkRV {:?}", dev.device());
let mut dev = WchLink {
device_handle: dev,
chip: None,
};
let info = dev.probe_info()?;
info!("probe info: {:?}", info);
let _ = dev.send_command(RawCommand::<0xff>(vec![0x41]));
Ok(())
}
/// Switch from RV mode to DAP mode
pub fn try_switch_from_dap_to_rv(nth: usize) -> Result<()> {
let dev = open_usb_device(VENDOR_ID_DAP, PRODUCT_ID_DAP, nth)?;
info!("Switch mode for WCH-LinkDAP {:?}", dev.device());
let buf = [0x81, 0xff, 0x01, 0x52];
log::trace!("send {} {}", hex::encode(&buf[..3]), hex::encode(&buf[3..]));
let _ = dev.write_bulk(
ENDPOINT_OUT_DAP,
&buf,
std::time::Duration::from_millis(5000),
);
Ok(())
}
/// Check connected USB device
pub fn check_usb_device() -> Result<()> {
let context = rusb::Context::new()?;
log::trace!("Acquired libusb context.");
for device in context.devices()?.iter() {
let desc = device.device_descriptor()?;
if desc.vendor_id() == VENDOR_ID && desc.product_id() == PRODUCT_ID {
log::info!("Found WCH-LinkRV, {:?}", device);
} else if desc.vendor_id() == VENDOR_ID_DAP && desc.product_id() == PRODUCT_ID_DAP {
log::info!("Found WCH-LinkDAP, {:?}", device);
}
}
Ok(())
}
fn open_usb_device(
vendor_id: u16,
produce_id: u16,
nth: usize,
) -> Result<DeviceHandle<rusb::Context>> {
let context = rusb::Context::new()?;
log::trace!("Acquired libusb context.");
let device = context
.devices()?
.iter()
.filter(|device| {
device
.device_descriptor()
.map(|desc| desc.vendor_id() == vendor_id && desc.product_id() == produce_id)
.unwrap_or(false)
})
.nth(nth)
.map_or(Err(crate::error::Error::ProbeNotFound), Ok)?;
let mut device_handle = device.open()?;
device_handle.claim_interface(0)?;
log::trace!("Claimed interface 0 of USB device.");
// TODO: endpoint check
// let config = device.active_config_descriptor()?;
Ok(device_handle)
}

4
src/error.rs

@ -5,10 +5,12 @@ pub type Result<T> = std::result::Result<T, Error>;
#[derive(Error, Debug)]
pub enum Error {
#[error("error: {0}")]
#[error("{0}")]
Custom(String),
#[error("USB error: {0}")]
Rusb(#[from] rusb::Error),
#[error("WCH-Link not found or not in RV mode, please check your connection or use mode-switch tool to switch to RV mode")]
ProbeNotFound,
#[error("Unknown WCH-Link variant: {0}")]
UnknownLinkVariant(u8),
#[error("Unknown RISC-V Chip: 0x{0:02x}")]

8
src/flash_op.rs

@ -3,9 +3,9 @@
//! These bytes are from WCH's OpenOCD fork, which shoule be licensed under the GNU General Public License v2.0.
//! But the code is not available in the public repository, you need to ask WCH official for a copy.
//!
//! NOTE: No flash op code for CH58x found.
//! NOTE: No flash op code for CH58X found.
/// For both CH32V20x and CH32V30x
/// For both CH32V20X and CH32V30X
pub const CH32V307: [u8; 512] = [
0x93, 0x77, 0x15, 0x00, 0x41, 0x11, 0x99, 0xcf, 0xb7, 0x06, 0x67, 0x45, 0xb7, 0x27, 0x02, 0x40,
0x93, 0x86, 0x36, 0x12, 0x37, 0x97, 0xef, 0xcd, 0xd4, 0xc3, 0x13, 0x07, 0xb7, 0x9a, 0xd8, 0xc3,
@ -77,7 +77,7 @@ pub const CH32V103: [u8; 512] = [
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
];
/// For CH56x
/// For CH56X
pub const CH569: [u8; 1204] = [
0x79, 0x71, 0x22, 0xd4, 0x26, 0xd2, 0x5a, 0xc8, 0x06, 0xd6, 0x4a, 0xd0, 0x4e, 0xce, 0x52, 0xcc,
0x56, 0xca, 0x5e, 0xc6, 0x93, 0x77, 0x15, 0x00, 0x2a, 0x84, 0x2e, 0x8b, 0xb2, 0x84, 0x9d, 0xe7,
@ -157,7 +157,7 @@ pub const CH569: [u8; 1204] = [
0x01, 0x45, 0xc1, 0xb7,
];
/// For both CH57x andxs CH58x
/// For both CH57X andxs CH58X
pub const CH573: [u8; 1280] = [
0x79, 0x71, 0x22, 0xD4, 0x26, 0xD2, 0x5A, 0xC8, 0x06, 0xD6, 0x4A, 0xD0, 0x4E, 0xCE, 0x52, 0xCC,
0x56, 0xCA, 0x5E, 0xC6, 0x93, 0x77, 0x15, 0x00, 0x2A, 0x84, 0x2E, 0x8B, 0xB2, 0x84, 0x9D, 0xEF,

46
src/lib.rs

@ -56,27 +56,27 @@ pub enum RiscvChip {
/// CH32V103 RISC-V3A series
CH32V103 = 0x01,
/// CH571/CH573 RISC-V3A BLE 4.2 series
CH57x = 0x02,
CH57X = 0x02,
/// CH565/CH569 RISC-V3A series
CH56x = 0x03,
/// CH32V20x RISC-V4B/V4C series
CH32V20x = 0x05,
/// CH32V30x RISC-V4C/V4F series
CH32V30x = 0x06,
/// CH581/CH582/CH583 RISC-V4A BLE 5.3 series, always failback as CH57x
CH58x = 0x07,
CH56X = 0x03,
/// CH32V20X RISC-V4B/V4C series
CH32V20X = 0x05,
/// CH32V30X RISC-V4C/V4F series
CH32V30X = 0x06,
/// CH581/CH582/CH583 RISC-V4A BLE 5.3 series, always failback as CH57X
CH58X = 0x07,
/// CH32V003 RISC-V2A series
CH32V003 = 0x09,
}
impl RiscvChip {
fn can_disable_debug(&self) -> bool {
matches!(self, RiscvChip::CH57x | RiscvChip::CH56x | RiscvChip::CH58x)
matches!(self, RiscvChip::CH57X | RiscvChip::CH56X | RiscvChip::CH58X)
}
fn reset_command(&self) -> crate::commands::Reset {
match self {
RiscvChip::CH57x | RiscvChip::CH58x => crate::commands::Reset::Normal2,
RiscvChip::CH57X | RiscvChip::CH58X => crate::commands::Reset::Normal2,
_ => crate::commands::Reset::Normal,
}
}
@ -85,21 +85,21 @@ impl RiscvChip {
match self {
RiscvChip::CH32V103 => &flash_op::CH32V103,
RiscvChip::CH32V003 => &flash_op::CH32V003,
RiscvChip::CH57x => &flash_op::CH573,
RiscvChip::CH56x => &flash_op::CH569,
RiscvChip::CH32V20x => &flash_op::CH32V307,
RiscvChip::CH32V30x => &flash_op::CH32V307,
RiscvChip::CH58x => &flash_op::CH573,
RiscvChip::CH57X => &flash_op::CH573,
RiscvChip::CH56X => &flash_op::CH569,
RiscvChip::CH32V20X => &flash_op::CH32V307,
RiscvChip::CH32V30X => &flash_op::CH32V307,
RiscvChip::CH58X => &flash_op::CH573,
}
}
fn try_from_u8(value: u8) -> Result<Self> {
match value {
0x01 => Ok(RiscvChip::CH32V103),
0x02 => Ok(RiscvChip::CH57x),
0x03 => Ok(RiscvChip::CH56x),
0x05 => Ok(RiscvChip::CH32V20x),
0x06 => Ok(RiscvChip::CH32V30x),
0x07 => Ok(RiscvChip::CH58x),
0x02 => Ok(RiscvChip::CH57X),
0x03 => Ok(RiscvChip::CH56X),
0x05 => Ok(RiscvChip::CH32V20X),
0x06 => Ok(RiscvChip::CH32V30X),
0x07 => Ok(RiscvChip::CH58X),
0x09 => Ok(RiscvChip::CH32V003),
_ => Err(Error::UnknownChip(value)),
}
@ -115,9 +115,9 @@ impl RiscvChip {
pub fn code_flash_start(&self) -> u32 {
match self {
RiscvChip::CH56x => 0x0000_0000,
RiscvChip::CH57x => 0x0000_0000,
RiscvChip::CH58x => 0x0000_0000,
RiscvChip::CH56X => 0x0000_0000,
RiscvChip::CH57X => 0x0000_0000,
RiscvChip::CH58X => 0x0000_0000,
_ => 0x0800_0000,
}
}

64
src/main.rs

@ -74,14 +74,21 @@ enum Commands {
Reset {},
/// Debug, check status
Status {},
/// Swifth mode from RV to DAP or vice versa
ModeSwitch {
#[arg(long)]
rv: bool,
#[arg(long)]
dap: bool,
},
}
fn main() -> Result<()> {
use Commands::*;
let cli = Cli::parse();
// init simplelogger
// init simplelogger
if cli.verbose >= 2 {
let _ = simplelog::TermLogger::init(
simplelog::LevelFilter::Trace,
@ -107,16 +114,25 @@ fn main() -> Result<()> {
let device_index = cli.device.unwrap_or(0);
let mut probe = WchLink::open_nth(device_index)?;
probe.probe_info()?;
match cli.command {
None => {
wlink::device::check_usb_device()?;
println!("No command given, use --help for help.");
//probe.attach_chip()?;
//probe.reset_mcu_and_halt()?;
}
Some(ModeSwitch { rv, dap }) => {
wlink::device::check_usb_device()?; // list all connected devices
log::warn!("This is an experimental feature, better use the WCH-LinkUtility!");
if !(rv ^ dap) {
println!("Please choose one mode to switch, either --rv or --dap");
} else if dap {
wlink::device::try_switch_from_rv_to_dap(device_index)?;
} else {
wlink::device::try_switch_from_dap_to_rv(device_index)?;
}
}
Some(command) => {
let mut probe = WchLink::open_nth(device_index)?;
probe.probe_info()?;
probe.attach_chip()?;
match command {
Dump { address, length } => {
@ -180,43 +196,13 @@ fn main() -> Result<()> {
let dmstatus: regs::Dmstatus = probe.dmi_read()?;
println!("=> {dmstatus:?}");
}
_ => unreachable!("unimplemented command"),
}
}
}
if cli.detach {
probe.detach_chip()?;
}
/*
let dmcontrol: Dmcontrol = probe.dmi_read()?;
println!("=> {:?}", dmcontrol);
//println!("resume");
// probe.resume_mcu()?;
let dmstatus: Dmstatus = probe.dmi_read()?;
println!("=> {:?}", dmstatus);
let dmcontrol: Dmcontrol = probe.dmi_read()?;
println!("=> {:?}", dmcontrol);
*/
// probe.resume_mcu()?;
//probe.reset_mcu_and_run()?;
// probe.read_flash_size_kb()?;
// println!("{}", nu_pretty_hex::pretty_hex(&mem));
//link.reset_mcu_and_run()?;
//log::info!("reset dm");
//probe.reset_debug_module()?;
//link.send_command(commands::Reset::Quit)?;
// link.send_command(commands::control::DetachChip)?;
}
}
Ok(())
}

14
src/operations.rs

@ -3,7 +3,7 @@
use std::{thread::sleep, time::Duration};
use crate::{
commands::{self, DmiOp, Program, ReadMemory, SetRamAddress},
commands::{self, control::ProbeInfo, DmiOp, Program, ReadMemory, SetRamAddress},
device::{ChipInfo, WchLink},
error::AbstractcsCmdErr,
regs::{self, Abstractcs, DMReg, Dmcontrol, Dmstatus},
@ -12,10 +12,10 @@ use crate::{
};
impl WchLink {
pub fn probe_info(&mut self) -> Result<()> {
pub fn probe_info(&mut self) -> Result<ProbeInfo> {
let info = self.send_command(commands::control::GetProbeInfo)?;
log::info!("{}", info);
Ok(())
Ok(info)
}
/// Attach chip and get chip info
pub fn attach_chip(&mut self) -> Result<()> {
@ -28,8 +28,8 @@ impl WchLink {
self.send_command(commands::control::GetProbeInfo)?;
self.send_command(commands::control::DetachChip)?;
let dummy = self.send_command(commands::RawCommand::<0x0c>(vec![0x07, 0x01]))?;
log::debug!("Dummy command: {:?}", dummy);
// unknown command
self.send_command(commands::RawCommand::<0x0c>(vec![0x07, 0x01]))?;
if let Ok(resp) = self.send_command(commands::control::AttachChip) {
log::info!("Attached chip: {}", resp);
@ -71,8 +71,8 @@ impl WchLink {
memory_start_addr: flash_addr,
sram_code_mode,
page_size,
rom_kb: 0, // TODO:
ram_kb: 0, // TODO:
//rom_kb: 0, // TODO:
//ram_kb: 0, // TODO:
};
self.chip = Some(info);

Loading…
Cancel
Save