Browse Source

wip: ch32v307 not works

pull/32/head
Andelf 1 year ago
parent
commit
3aeeae0e0c
  1. 14
      docs/CH32L103.md
  2. 4
      docs/CH32V307.md
  3. 45
      src/commands.rs
  4. 24
      src/commands/control.rs
  5. 18
      src/device.rs
  6. 1
      src/flash_op.rs
  7. 2
      src/lib.rs
  8. 14
      src/main.rs
  9. 134
      src/operations.rs
  10. 11
      src/transport.rs

14
docs/CH32L103.md

@ -0,0 +1,14 @@
# CH32L103
## Chips
```
* CH32L103C8U6-0x103007x0
* CH32L103C8T6-0x103107x0
* CH32L103F8P6-0x103A07x0
* CH32L103G8R6-0x103B07x0
* CH32L103K8U6-0x103207x0
* CH32L103F8U6-0x103D07x0
* CH32L103F7P6-0x103707x0
```

4
docs/CH32V307.md

@ -13,6 +13,10 @@ wlink -v dump 0x08000000 0x10`
08000000: b7 00 00 08 67 80 80 00 73 50 40 30 73 50 40 34 ×00•g××0sP@0sP@4
```
## Notes
- erased flash `39 e3 39 e3`
## Chips
```

45
src/commands.rs

@ -156,15 +156,18 @@ impl Command for Program {
// query -> check -> set
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum FlashProtect {
CheckReadProtect = 0x01, // 1 for protected, 2 for unprotected
CheckReadProtectEx = 0x04, // 1 for protected, 0 for unprotected,
Protect = 0x03,
Unprotect = 0x02,
// dummy 0xf0 mask
/// 06, _, 01
CheckReadProtect, // 1 for protected, 2 for unprotected
/// 06, _, 02
Unprotect,
/// 06, _, 03
Protect,
/// 06, _, 04
CheckReadProtectEx, // 1 for protected, 0 for unprotected,
/// bf, or e7
UnprotectEx(u8), // with 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
// prefix byte 0xe7 ? for ch32x035
ProtectEx = 0xf3, // with 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
// dummy 0xf0 mask
UnprotectEx = 0xf2, // with 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
ProtectEx(u8), // with 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
}
impl FlashProtect {
pub const FLAG_PROTECTED: u8 = 0x01;
@ -173,10 +176,14 @@ impl Command for FlashProtect {
type Response = u8;
const COMMAND_ID: u8 = 0x06;
fn payload(&self) -> Vec<u8> {
use FlashProtect::*;
match *self {
FlashProtect::ProtectEx => vec![0x03, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
FlashProtect::UnprotectEx => vec![0x02, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
_ => vec![*self as u8],
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],
}
}
}
@ -206,7 +213,7 @@ pub enum GetChipInfo {
V2 = 0x06,
}
impl Command for GetChipInfo {
type Response = ChipId;
type Response = ChipUID;
const COMMAND_ID: u8 = 0x11;
fn payload(&self) -> Vec<u8> {
vec![*self as u8]
@ -218,8 +225,8 @@ impl Command for GetChipInfo {
// UID in wchisp: cd-ab-b4-ae-45-bc-c6-16
// e339e339e339e339 => inital value of erased flash
/// Chip UID, also reported by wchisp
pub struct ChipId(pub [u8; 8]);
impl Response for ChipId {
pub struct ChipUID(pub [u8; 8]);
impl Response for ChipUID {
fn from_raw(resp: &[u8]) -> Result<Self> {
if resp.len() <= 12 {
return Err(Error::InvalidPayloadLength);
@ -242,7 +249,7 @@ impl Response for ChipId {
unreachable!("ChipId is not be parsed from payload; qed")
}
}
impl fmt::Display for ChipId {
impl fmt::Display for ChipUID {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(
&self
@ -254,7 +261,7 @@ impl fmt::Display for ChipId {
)
}
}
impl fmt::Debug for ChipId {
impl fmt::Debug for ChipUID {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&format!("ChipId({:02x?})", &self.0[..]))
}
@ -264,7 +271,7 @@ impl fmt::Debug for ChipId {
#[derive(Debug)]
pub enum Reset {
/// wlink_quitreset
AndRun, // the most common reset
ResetAndRun, // the most common reset
Normal,
Normal2,
}
@ -273,7 +280,7 @@ impl Command for Reset {
const COMMAND_ID: u8 = 0x0b;
fn payload(&self) -> Vec<u8> {
match self {
Reset::AndRun => vec![0x01],
Reset::ResetAndRun => vec![0x01],
Reset::Normal => vec![0x03],
Reset::Normal2 => vec![0x02],
}
@ -425,7 +432,7 @@ mod tests {
fn chip_id_parsing() {
let raw = hex::decode("ffff0020aeb4abcd16c6bc45e339e339e339e339").unwrap();
let uid = ChipId::from_raw(&raw).unwrap();
let uid = ChipUID::from_raw(&raw).unwrap();
println!("=> {uid:?}");
assert_eq!("cd-ab-b4-ae-45-bc-c6-16", uid.to_string());

24
src/commands/control.rs

@ -96,18 +96,6 @@ impl fmt::Display for AttachChipResponse {
}
}
// ?? close out
/// Detach Chip, (0x0d, 0xff)
#[derive(Debug)]
pub struct OptEnd;
impl Command for OptEnd {
type Response = ();
const COMMAND_ID: u8 = 0x0d;
fn payload(&self) -> Vec<u8> {
vec![0xff]
}
}
/// GetROMRAM, Only avaliable for CH32V2, CH32V3, CH56X
/// 0, 1, 2, 3
#[derive(Debug)]
@ -120,6 +108,18 @@ impl Command for GetChipRomRamSplit {
}
}
// ?? close out
/// Detach Chip, (0x0d, 0xff)
#[derive(Debug)]
pub struct OptEnd;
impl Command for OptEnd {
type Response = ();
const COMMAND_ID: u8 = 0x0d;
fn payload(&self) -> Vec<u8> {
vec![0xff]
}
}
/// Set Power, from pow3v3, pow5v fn
#[derive(Debug)]
pub enum SetPower {

18
src/device.rs

@ -4,7 +4,7 @@ use log::info;
use rusb::{DeviceHandle, UsbContext};
use crate::{
commands::{control::ProbeInfo, ChipId, RawCommand, Response},
commands::{control::ProbeInfo, ChipUID, RawCommand, Response},
transport::Transport,
Result, RiscvChip,
};
@ -24,19 +24,13 @@ const ENDPOINT_OUT_DAP: u8 = 0x02;
/// Attached chip information
#[derive(Debug)]
pub struct ChipInfo {
pub uid: Option<ChipId>,
/// UID
pub uid: Option<ChipUID>,
pub chip_family: RiscvChip,
pub chip_type: u32,
/// 0x303305x4 like chip_id, In SDK, `DBGMCU_GetCHIPID` is used to get this value
pub chip_id: u32,
/// parsed marchid: WCH-V4B, WCH-V4F...
pub march: Option<String>,
pub flash_size: u32,
pub page_size: u32,
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,
}
#[derive(Debug)]
@ -119,7 +113,7 @@ impl WchLink {
}
pub fn send_command<C: crate::commands::Command>(&mut self, cmd: C) -> Result<C::Response> {
log::trace!("send command: {:?}", cmd);
log::debug!("send command: {:?}", cmd);
let raw = cmd.to_raw();
self.device_handle.write_command_endpoint(&raw)?;
let resp = self.device_handle.read_command_endpoint()?;

1
src/flash_op.rs

@ -2,6 +2,7 @@
/// For both CH32V20X and CH32V30X
// 5, 6
// flash op packet size = 128
pub const CH32V307: [u8; 446] = [
0x01, 0x11, 0x02, 0xce, 0x93, 0x77, 0x15, 0x00, 0x99, 0xcf, 0xb7, 0x06, 0x67, 0x45, 0xb7, 0x27,
0x02, 0x40, 0x93, 0x86, 0x36, 0x12, 0x37, 0x97, 0xef, 0xcd, 0xd4, 0xc3, 0x13, 0x07, 0xb7, 0x9a,

2
src/lib.rs

@ -167,7 +167,7 @@ impl RiscvChip {
}
RiscvChip::CH32V30X | RiscvChip::CH8571 | RiscvChip::CH32V003 => {
// 81 0d 01 03
let _ = probe.send_command(RawCommand::<0x0d>(vec![0x03]))?;
// let _ = probe.send_command(RawCommand::<0x0d>(vec![0x03]))?;
}
RiscvChip::CH57X | RiscvChip::CH58X => {
log::warn!("The debug interface has been opened, there is a risk of code leakage.");

14
src/main.rs

@ -158,11 +158,10 @@ fn main() -> Result<()> {
Some(command) => {
let mut probe = WchLink::open_nth(device_index)?;
probe.set_speed(cli.speed);
probe.probe_info()?;
probe.attach_chip(cli.chip)?;
match command {
Dev {} => {
const FLASH_KEYR: u32 = 0x2000_0030;
// const FLASH_KEYR: u32 = 0x2000_0030;
let mut algo = wlink::dmi::Algorigthm::new(&mut probe);
// algo.write_mem32(FLASH_KEYR, 0x45670123)?;
@ -208,9 +207,12 @@ fn main() -> Result<()> {
no_run,
path,
} => {
probe.dump_info(false)?;
let firmware = read_firmware_from_file(path)?;
let start_address =
address.unwrap_or_else(|| probe.chip.as_ref().unwrap().memory_start_addr);
let start_address = address.unwrap_or_else(|| {
probe.chip.as_ref().unwrap().chip_family.code_flash_start()
});
log::info!(
"Flashing {} bytes to 0x{:08x}",
firmware.len(),
@ -229,7 +231,7 @@ fn main() -> Result<()> {
if !no_run {
log::info!("Now reset...");
probe.send_command(commands::Reset::AndRun)?;
probe.send_command(commands::Reset::ResetAndRun)?;
sleep(Duration::from_millis(500));
}
// reattach
@ -264,7 +266,7 @@ fn main() -> Result<()> {
probe.write_memory_word(address, value)?;
}
Status {} => {
probe.dump_info()?;
probe.dump_info(true)?;
let dmstatus: regs::Dmstatus = probe.read_dmi_reg()?;
log::info!("{dmstatus:#x?}");
let dmcontrol: regs::Dmcontrol = probe.read_dmi_reg()?;

134
src/operations.rs

@ -6,7 +6,7 @@ use crate::{
commands::{
self,
control::{self, ProbeInfo},
DmiOp, Program, RawCommand, SetReadMemoryRegion, SetWriteMemoryRegion,
DmiOp, Program, SetReadMemoryRegion, SetWriteMemoryRegion,
},
device::{ChipInfo, WchLink},
dmi::DebugModuleInterface,
@ -29,7 +29,7 @@ impl WchLink {
log::warn!("Chip already attached");
}
let probe_info = self.send_command(commands::control::GetProbeInfo)?;
let probe_info = self.probe_info()?;
if let Some(chip) = expected_chip {
if !probe_info.variant.support_chip(chip) {
@ -81,20 +81,14 @@ impl WchLink {
//log::info!("Check QE: {:?}", ret);
// riscvchip = 7 => 2
let flash_addr = chip_info.chip_family.code_flash_start();
let page_size = chip_info.chip_family.data_packet_size();
//let flash_addr = chip_info.chip_family.code_flash_start();
//let page_size = chip_info.chip_family.data_packet_size();
let info = ChipInfo {
uid: None, // TODO
chip_family: chip_info.chip_family,
chip_type: chip_info.chip_type,
chip_id: chip_info.chip_type,
march: None,
flash_size: 0, // TODO: read flash size
memory_start_addr: flash_addr,
page_size: page_size as _,
// sram_code_mode: 0, // TODO
//rom_kb: 0, // TODO:
//ram_kb: 0, // TODO:
};
self.chip = Some(info);
@ -104,16 +98,17 @@ impl WchLink {
}
// NOTE: this halts the MCU, so it's not suitable except for dumping info
pub fn dump_info(&mut self) -> Result<()> {
pub fn dump_info(&mut self, detailed: bool) -> Result<()> {
let probe_info = self.probe.as_ref().unwrap();
if self.chip.as_ref().unwrap().chip_family.support_query_info() {
let chip_family = self.chip.as_ref().unwrap().chip_family;
if chip_family.support_query_info() {
let chip_id = if probe_info.version() >= (2, 9) {
self.send_command(commands::GetChipInfo::V2)?
} else {
self.send_command(commands::GetChipInfo::V1)?
};
log::info!("Chip UID: {chip_id}");
// self.uid = Some(chip_id);
let flash_protected = self.send_command(commands::FlashProtect::CheckReadProtect)?;
let protected = flash_protected == commands::FlashProtect::FLAG_PROTECTED;
@ -122,28 +117,23 @@ impl WchLink {
log::warn!("Flash is protected, debug access is not available");
}
}
if self
.chip
.as_ref()
.unwrap()
.chip_family
.support_ram_rom_mode()
{
if chip_family.support_ram_rom_mode() {
let sram_code_mode = self.send_command(commands::control::GetChipRomRamSplit)?;
log::debug!("SRAM CODE split mode: {}", sram_code_mode);
}
let misa = self.read_reg(regs::MISA)?;
log::trace!("Read csr misa: {misa:08x}");
let misa = parse_misa(misa);
log::info!("RISC-V ISA: {misa:?}");
// detect chip's RISC-V core version, QingKe cores
let marchid = self.read_reg(regs::MARCHID)?;
log::trace!("Read csr marchid: {marchid:08x}");
let core_type = parse_marchid(marchid);
log::info!("RISC-V arch: {core_type:?}");
if detailed {
let misa = self.read_reg(regs::MISA)?;
log::trace!("Read csr misa: {misa:08x}");
let misa = parse_misa(misa);
log::info!("RISC-V ISA: {misa:?}");
// detect chip's RISC-V core version, QingKe cores
let marchid = self.read_reg(regs::MARCHID)?;
log::trace!("Read csr marchid: {marchid:08x}");
let core_type = parse_marchid(marchid);
log::info!("RISC-V arch: {core_type:?}");
}
Ok(())
}
@ -164,21 +154,17 @@ impl WchLink {
);
}
let use_v2 = false; //probe_info.version() >= (2, 9);
let use_v2 = self.probe.as_ref().unwrap().version() >= (2, 9);
let cmd = match (protect, use_v2) {
(true, true) => commands::FlashProtect::ProtectEx,
(true, true) => commands::FlashProtect::ProtectEx(0xbf),
(true, false) => commands::FlashProtect::Protect,
(false, true) => commands::FlashProtect::UnprotectEx,
(false, true) => commands::FlashProtect::UnprotectEx(0xbf),
(false, false) => commands::FlashProtect::Unprotect,
};
self.send_command(cmd)?;
self.send_command(commands::Reset::AndRun)?; // quit reset
self.send_command(commands::control::OptEnd)?;
self.send_command(commands::control::GetProbeInfo)?;
self.send_command(commands::control::AttachChip)?;
self.send_command(commands::Reset::ResetAndRun)?; // quit reset
self.send_command(control::AttachChip)?;
let flash_protected = self.send_command(commands::FlashProtect::CheckReadProtect)?;
log::info!(
@ -199,8 +185,9 @@ impl WchLink {
}
fn reattach_chip(&mut self) -> Result<()> {
let current_chip_family = self.chip.as_ref().map(|i| i.chip_family);
self.detach_chip()?;
self.attach_chip(self.chip.as_ref().map(|i| i.chip_family))?;
self.attach_chip(current_chip_family)?;
Ok(())
}
@ -267,77 +254,82 @@ impl WchLink {
log::warn!("Flash is protected, unprotecting...");
self.protect_flash(false)?;
} else if ret == 2 {
self.protect_flash(false)?;
} else {
log::warn!("Unknown flash protect status: {}", ret);
}
}
self.send_command(Program::EraseFlash)?;
self.send_command(control::AttachChip)?;
Ok(())
}
// wlink_write
pub fn write_flash(&mut self, data: &[u8], address: u32) -> Result<()> {
let write_pack_size = self.chip.as_ref().unwrap().chip_family.write_pack_size();
let data_packet_size = self.chip.as_ref().unwrap().chip_family.data_packet_size();
let chip_family = self.chip.as_ref().unwrap().chip_family;
let write_pack_size = chip_family.write_pack_size();
let data_packet_size = chip_family.data_packet_size();
let mut data = data.to_vec();
if data.len() % data_packet_size != 0 {
data.resize((data.len() / data_packet_size + 1) * data_packet_size, 0xff);
log::debug!("Data resized to {}", data.len());
if chip_family.support_flash_protect() {
self.protect_flash(false)?;
}
let mut data = data.to_vec();
// if data.len() % data_packet_size != 0 {
// data.resize((data.len() / data_packet_size + 1) * data_packet_size, 0xff);
// log::debug!("Data resized to {}", data.len());
// }
log::debug!(
"Using write pack size {} data pack size {}",
write_pack_size,
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 < 3 {
// wlink_ready_write
self.send_command(Program::Prepare)?;
self.send_command(SetWriteMemoryRegion {
start_addr: address,
len: data.len() as _,
})?;
// let mut retries = 0;
// while retries < 1 {
// wlink_ready_write
self.send_command(Program::Prepare)?;
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(),
data_packet_size,
)?;
self.device_handle
.write_data_endpoint(self.chip.as_ref().unwrap().chip_family.flash_op(), 128)?;
log::debug!("Flash OP written");
std::thread::sleep(Duration::from_millis(10));
if self.chip.as_ref().unwrap().chip_family == RiscvChip::CH32V103 {}
if let Ok(n) = self.send_command(Program::Unknown07AfterFlashOPWritten) {
if n == 0x07 {
//return Err(Error::Custom(
// "Unknown07AfterFlashOPWritten failed".to_string(),
//));
break;
}
}
log::warn!("Unknown07AfterFlashOPWritten failed, retrying...");
std::thread::sleep(Duration::from_millis(100));
self.reattach_chip()?;
retries += 1;
}
if retries >= 3 {
return Err(Error::Custom(
"Unknown07AfterFlashOPWritten failed".to_string(),
));
}
// wlink_fastprogram
self.send_command(Program::WriteFlashAndVerify)?;
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));
//std::thread::sleep(Duration::from_secs(2));
let rxbuf = self.device_handle.read_data_endpoint(4)?;
// 41 01 01 04
if rxbuf[3] != 0x04 {

11
src/transport.rs

@ -9,8 +9,8 @@ use crate::{Error, Result};
const ENDPOINT_OUT: u8 = 0x01;
const ENDPOINT_IN: u8 = 0x81;
const RAW_ENDPOINT_OUT: u8 = 0x02;
const RAW_ENDPOINT_IN: u8 = 0x82;
const DATA_ENDPOINT_OUT: u8 = 0x02;
const DATA_ENDPOINT_IN: u8 = 0x82;
// 1a86:8010 1a86 WCH-Link Serial: 0001A0000000
const USB_TIMEOUT_MS: u64 = 5000;
@ -55,7 +55,7 @@ impl Transport for DeviceHandle<rusb::Context> {
while bytes_read < n {
let mut chunk = vec![0u8; 64];
let chunk_read = self.read_bulk(
RAW_ENDPOINT_IN,
DATA_ENDPOINT_IN,
&mut chunk,
Duration::from_millis(USB_TIMEOUT_MS),
)?;
@ -83,13 +83,14 @@ impl Transport for DeviceHandle<rusb::Context> {
if chunk.len() < packet_len {
chunk.resize(packet_len, 0xff);
}
log::trace!("write data ep {} bytes", chunk.len());
self.write_bulk(
RAW_ENDPOINT_OUT,
DATA_ENDPOINT_OUT,
&chunk,
Duration::from_millis(USB_TIMEOUT_MS),
)?;
}
log::trace!("write data ep {} bytes", buf.len());
log::trace!("write data ep total {} bytes", buf.len());
Ok(())
}
}

Loading…
Cancel
Save