sftool_lib/sf32lb52/
mod.rs1pub mod erase_flash;
4pub mod ram_command;
5pub mod read_flash;
6pub mod reset;
7pub mod sifli_debug;
8pub mod speed;
9pub mod write_flash;
10
11use crate::common::sifli_debug::SifliDebug;
12use crate::sf32lb52::ram_command::DownloadStub;
13use crate::{SifliTool, SifliToolBase, SifliToolTrait};
14use serialport::SerialPort;
15use std::time::Duration;
16
17pub struct SF32LB52Tool {
18 pub base: SifliToolBase,
19 pub port: Box<dyn SerialPort>,
20}
21
22unsafe impl Send for SF32LB52Tool {}
25unsafe impl Sync for SF32LB52Tool {}
26
27impl SF32LB52Tool {
28 pub fn internal_erase_all(&mut self, address: u32) -> Result<(), std::io::Error> {
30 use ram_command::{Command, RamCommand};
31
32 let progress = self.progress();
33 let spinner =
34 progress.create_spinner(format!("Erasing entire flash at 0x{:08X}...", address));
35
36 let _ = self.command(Command::EraseAll { address });
38
39 let mut buffer = Vec::new();
40 let now = std::time::SystemTime::now();
41
42 loop {
44 let elapsed = now.elapsed().unwrap().as_millis();
45 if elapsed > 30000 {
46 tracing::error!("response string is {}", String::from_utf8_lossy(&buffer));
48 return Err(std::io::Error::new(
49 std::io::ErrorKind::TimedOut,
50 "Erase timeout",
51 ));
52 }
53
54 let mut byte = [0];
55 let ret = self.port().read_exact(&mut byte);
56 if ret.is_err() {
57 continue;
58 }
59 buffer.push(byte[0]);
60
61 if buffer.windows(2).any(|window| window == b"OK") {
63 break;
64 }
65 }
66
67 spinner.finish_with_message(format!("Erase flash successfully: 0x{:08X}", address));
68
69 Ok(())
70 }
71
72 pub fn internal_erase_region(&mut self, address: u32, len: u32) -> Result<(), std::io::Error> {
74 use ram_command::{Command, RamCommand};
75
76 let progress = self.progress();
77 let spinner =
78 progress.create_spinner(format!("Erasing entire flash at 0x{:08X}...", address));
79
80 let _ = self.command(Command::Erase { address, len });
82
83 let mut buffer = Vec::new();
84 let now = std::time::SystemTime::now();
85
86 let timeout_ms = (len as u128 / (4 * 1024) + 1) * 800; tracing::info!(
88 "Erase region at 0x{:08X} with length 0x{:08X}, timeout: {} ms",
89 address,
90 len,
91 timeout_ms
92 );
93
94 loop {
96 let elapsed = now.elapsed().unwrap().as_millis();
97 if elapsed > timeout_ms {
98 tracing::error!("response string is {}", String::from_utf8_lossy(&buffer));
100 return Err(std::io::Error::new(
101 std::io::ErrorKind::TimedOut,
102 "Erase timeout",
103 ));
104 }
105
106 let mut byte = [0];
107 let ret = self.port().read_exact(&mut byte);
108 if ret.is_err() {
109 continue;
110 }
111 buffer.push(byte[0]);
112
113 if buffer.windows(2).any(|window| window == b"OK") {
115 break;
116 }
117 }
118
119 spinner.finish_with_message(format!(
120 "Erase region successfully: 0x{:08X} (length: {} bytes)",
121 address, len
122 ));
123
124 Ok(())
125 }
126
127 fn attempt_connect(&mut self) -> Result<(), std::io::Error> {
128 use crate::Operation;
129 use crate::common::sifli_debug::{SifliUartCommand, SifliUartResponse};
130
131 let infinite_attempts = self.base.connect_attempts <= 0;
132 let mut remaining_attempts = if infinite_attempts {
133 None
134 } else {
135 Some(self.base.connect_attempts)
136 };
137 loop {
138 if self.base.before == Operation::DefaultReset {
139 self.port.write_request_to_send(true)?;
141 std::thread::sleep(Duration::from_millis(100));
142 self.port.write_request_to_send(false)?;
143 std::thread::sleep(Duration::from_millis(100));
144 }
145 let value = match self.debug_command(SifliUartCommand::Enter) {
146 Ok(SifliUartResponse::Enter) => Ok(()),
147 _ => Err(std::io::Error::new(
148 std::io::ErrorKind::Other,
149 "Failed to enter debug mode",
150 )),
151 };
152 if let Some(ref mut attempts) = remaining_attempts {
154 if *attempts == 0 {
155 break; }
157 *attempts -= 1;
158 }
159
160 let progress = self.progress();
161 let spinner = progress.create_spinner("Connecting to chip...");
162
163 match value {
165 Ok(_) => {
166 spinner.finish_with_message("Connected success!");
167 return Ok(());
168 }
169 Err(_) => {
170 spinner.finish_with_message("Failed to connect to the chip, retrying...");
171 std::thread::sleep(Duration::from_millis(500));
172 }
173 }
174 }
175 Err(std::io::Error::new(
176 std::io::ErrorKind::Other,
177 "Failed to connect to the chip",
178 ))
179 }
180
181 fn download_stub_impl(&mut self) -> Result<(), std::io::Error> {
182 use crate::common::sifli_debug::SifliUartCommand;
183 use crate::ram_stub::{self, CHIP_FILE_NAME};
184 use probe_rs::MemoryMappedRegister;
185 use probe_rs::architecture::arm::core::armv7m::{Aircr, Demcr};
186 use probe_rs::architecture::arm::core::registers::cortex_m::{PC, SP};
187
188 let progress = self.progress();
189 let spinner = progress.create_spinner("Download stub...");
190
191 let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
194 let mut demcr = Demcr(demcr);
195 demcr.set_vc_corereset(true);
196 self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
197
198 let mut aircr = Aircr(0);
200 aircr.vectkey();
201 aircr.set_sysresetreq(true);
202 let _ = self.debug_write_word32(Aircr::get_mmio_address() as u32, aircr.into()); std::thread::sleep(std::time::Duration::from_millis(10));
204
205 self.debug_command(SifliUartCommand::Enter)?;
207
208 self.debug_halt()?;
210
211 let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
213 let mut demcr = Demcr(demcr);
214 demcr.set_vc_corereset(false);
215 self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
216
217 std::thread::sleep(std::time::Duration::from_millis(100));
218 let stub = ram_stub::RamStubFile::get(
220 CHIP_FILE_NAME
221 .get(format!("sf32lb52_{}", self.base.memory_type).as_str())
222 .expect("REASON"),
223 );
224 let Some(stub) = stub else {
225 spinner.finish_with_message("No stub file found for the given chip and memory type");
226 return Err(std::io::Error::new(
227 std::io::ErrorKind::NotFound,
228 "No stub file found for the given chip and memory type",
229 ));
230 };
231
232 let packet_size = if self.base.compat { 256 } else { 64 * 1024 };
233
234 let mut addr = 0x2005_A000;
235 let mut data = &stub.data[..];
236 while !data.is_empty() {
237 let chunk = &data[..std::cmp::min(data.len(), packet_size)];
238 self.debug_write_memory(addr, chunk)?;
239 addr += chunk.len() as u32;
240 data = &data[chunk.len()..];
241 }
242
243 let bkp0r_addr = 0x500cb000 + 0x30;
246 let bkp0r_value = 0xA640;
247 self.debug_write_word32(bkp0r_addr, bkp0r_value)?;
248
249 let gpio_dosr0_addr = 0x500a0008;
251 let mut gpio_dosr0_value = self.debug_read_word32(gpio_dosr0_addr)?;
252 gpio_dosr0_value |= 1 << 21;
254 self.debug_write_word32(gpio_dosr0_addr, gpio_dosr0_value)?;
255
256 let sp = u32::from_le_bytes(
259 stub.data[0..4]
260 .try_into()
261 .expect("slice with exactly 4 bytes"),
262 );
263 let pc = u32::from_le_bytes(
264 stub.data[4..8]
265 .try_into()
266 .expect("slice with exactly 4 bytes"),
267 );
268 self.debug_write_core_reg(PC.id.0, pc)?;
269 self.debug_write_core_reg(SP.id.0, sp)?;
270
271 self.debug_run()?;
273
274 spinner.finish_with_message("Download stub success!");
275
276 Ok(())
277 }
278}
279
280impl SifliTool for SF32LB52Tool {
281 fn create_tool(base: SifliToolBase) -> Box<dyn SifliTool> {
282 let mut port = serialport::new(&base.port_name, 1000000)
283 .timeout(Duration::from_secs(5))
284 .open()
285 .unwrap();
286 port.write_request_to_send(false).unwrap();
287 std::thread::sleep(Duration::from_millis(100));
288
289 let mut tool = Box::new(Self { base, port });
290 tool.download_stub().expect("Failed to download stub");
291 tool
292 }
293}
294
295impl SifliToolTrait for SF32LB52Tool {
296 fn port(&mut self) -> &mut Box<dyn SerialPort> {
297 &mut self.port
298 }
299
300 fn base(&self) -> &SifliToolBase {
301 &self.base
302 }
303
304 fn set_speed(&mut self, baud: u32) -> Result<(), std::io::Error> {
305 use crate::speed::SpeedTrait;
306 SpeedTrait::set_speed(self, baud)
307 }
308
309 fn soft_reset(&mut self) -> Result<(), std::io::Error> {
310 use crate::reset::Reset;
311 Reset::soft_reset(self)
312 }
313}