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