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::progress::{
13 EraseFlashStyle, EraseRegionStyle, ProgressOperation, ProgressStatus, StubStage,
14};
15use crate::sf32lb52::ram_command::DownloadStub;
16use crate::{Result, SifliTool, SifliToolBase, SifliToolTrait};
17use serialport::SerialPort;
18use std::time::Duration;
19
20pub struct SF32LB52Tool {
21 pub base: SifliToolBase,
22 pub port: Box<dyn SerialPort>,
23}
24
25unsafe impl Send for SF32LB52Tool {}
28unsafe impl Sync for SF32LB52Tool {}
29
30impl SF32LB52Tool {
31 pub fn internal_erase_all(&mut self, address: u32) -> Result<()> {
33 use ram_command::{Command, RamCommand};
34
35 let progress = self.progress();
36 let spinner = progress.create_spinner(ProgressOperation::EraseFlash {
37 address,
38 style: EraseFlashStyle::Addressed,
39 });
40
41 let _ = self.command(Command::EraseAll { address });
43
44 let mut buffer = Vec::new();
45 let now = std::time::SystemTime::now();
46
47 loop {
49 let elapsed = now.elapsed().unwrap().as_millis();
50 if elapsed > 30000 {
51 tracing::error!("response string is {}", String::from_utf8_lossy(&buffer));
53 return Err(
54 std::io::Error::new(std::io::ErrorKind::TimedOut, "Erase timeout").into(),
55 );
56 }
57
58 let mut byte = [0];
59 let ret = self.port().read_exact(&mut byte);
60 if ret.is_err() {
61 continue;
62 }
63 buffer.push(byte[0]);
64
65 if buffer.windows(2).any(|window| window == b"OK") {
67 break;
68 }
69 }
70
71 spinner.finish(ProgressStatus::Success);
72
73 Ok(())
74 }
75
76 pub fn internal_erase_region(&mut self, address: u32, len: u32) -> Result<()> {
78 use ram_command::{Command, RamCommand};
79
80 let progress = self.progress();
81 let spinner = progress.create_spinner(ProgressOperation::EraseRegion {
82 address,
83 len,
84 style: EraseRegionStyle::LegacyFlashStartDecimalLength,
85 });
86
87 let _ = self.command(Command::Erase { address, len });
89
90 let mut buffer = Vec::new();
91 let now = std::time::SystemTime::now();
92
93 let timeout_ms = (len as u128 / (4 * 1024) + 1) * 800; tracing::info!(
95 "Erase region at 0x{:08X} with length 0x{:08X}, timeout: {} ms",
96 address,
97 len,
98 timeout_ms
99 );
100
101 loop {
103 let elapsed = now.elapsed().unwrap().as_millis();
104 if elapsed > timeout_ms {
105 tracing::error!("response string is {}", String::from_utf8_lossy(&buffer));
107 return Err(
108 std::io::Error::new(std::io::ErrorKind::TimedOut, "Erase timeout").into(),
109 );
110 }
111
112 let mut byte = [0];
113 let ret = self.port().read_exact(&mut byte);
114 if ret.is_err() {
115 continue;
116 }
117 buffer.push(byte[0]);
118
119 if buffer.windows(2).any(|window| window == b"OK") {
121 break;
122 }
123 }
124
125 spinner.finish(ProgressStatus::Success);
126
127 Ok(())
128 }
129
130 fn attempt_connect(&mut self) -> Result<()> {
131 use crate::common::sifli_debug::{SifliUartCommand, SifliUartResponse};
132
133 let infinite_attempts = self.base.connect_attempts <= 0;
134 let mut remaining_attempts = if infinite_attempts {
135 None
136 } else {
137 Some(self.base.connect_attempts)
138 };
139 loop {
140 if self.base.before.requires_reset() {
141 self.port.write_request_to_send(true)?;
143 std::thread::sleep(Duration::from_millis(100));
144 self.port.write_request_to_send(false)?;
145 std::thread::sleep(Duration::from_millis(100));
146 }
147 let value: Result<()> = match self.debug_command(SifliUartCommand::Enter) {
148 Ok(SifliUartResponse::Enter) => Ok(()),
149 _ => Err(std::io::Error::other("Failed to enter debug mode").into()),
150 };
151 if let Some(ref mut attempts) = remaining_attempts {
153 if *attempts == 0 {
154 break; }
156 *attempts -= 1;
157 }
158
159 let progress = self.progress();
160 let spinner = progress.create_spinner(ProgressOperation::Connect);
161
162 match value {
164 Ok(_) => {
165 spinner.finish(ProgressStatus::Success);
166 return Ok(());
167 }
168 Err(_) => {
169 spinner.finish(ProgressStatus::Retry);
170 std::thread::sleep(Duration::from_millis(500));
171 }
172 }
173 }
174 Err(std::io::Error::other("Failed to connect to the chip").into())
175 }
176
177 fn download_stub_impl(&mut self) -> Result<()> {
178 use crate::common::sifli_debug::SifliUartCommand;
179 use crate::ram_stub::load_stub_file;
180 use probe_rs::MemoryMappedRegister;
181 use probe_rs::architecture::arm::core::armv7m::{Aircr, Demcr};
182 use probe_rs::architecture::arm::core::registers::cortex_m::{PC, SP};
183
184 let progress = self.progress();
185 let spinner = progress.create_spinner(ProgressOperation::DownloadStub {
186 stage: StubStage::Start,
187 });
188
189 let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
192 let mut demcr = Demcr(demcr);
193 demcr.set_vc_corereset(true);
194 self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
195
196 let mut aircr = Aircr(0);
198 aircr.vectkey();
199 aircr.set_sysresetreq(true);
200 let _ = self.debug_write_word32(Aircr::get_mmio_address() as u32, aircr.into()); std::thread::sleep(std::time::Duration::from_millis(10));
202
203 self.debug_command(SifliUartCommand::Enter)?;
205
206 self.debug_halt()?;
208
209 let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
211 let mut demcr = Demcr(demcr);
212 demcr.set_vc_corereset(false);
213 self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
214
215 std::thread::sleep(std::time::Duration::from_millis(100));
216 let chip_memory_key = format!("sf32lb52_{}", self.base.memory_type);
218 let stub = match load_stub_file(self.base.external_stub_path.as_deref(), &chip_memory_key) {
219 Ok(s) => s,
220 Err(e) => {
221 spinner.finish(ProgressStatus::NotFound);
222 return Err(e.into());
223 }
224 };
225
226 let packet_size = if self.base.compat { 256 } else { 64 * 1024 };
227
228 let mut addr = 0x2005_A000;
229 let mut data = &stub.data[..];
230 while !data.is_empty() {
231 let chunk = &data[..std::cmp::min(data.len(), packet_size)];
232 self.debug_write_memory(addr, chunk)?;
233 addr += chunk.len() as u32;
234 data = &data[chunk.len()..];
235 }
236
237 let bkp0r_addr = 0x500cb000 + 0x30;
240 let bkp0r_value = 0xA640;
241 self.debug_write_word32(bkp0r_addr, bkp0r_value)?;
242
243 let gpio_dosr0_addr = 0x500a0008;
245 let mut gpio_dosr0_value = self.debug_read_word32(gpio_dosr0_addr)?;
246 gpio_dosr0_value |= 1 << 21;
248 self.debug_write_word32(gpio_dosr0_addr, gpio_dosr0_value)?;
249
250 let sp = u32::from_le_bytes(
253 stub.data[0..4]
254 .try_into()
255 .expect("slice with exactly 4 bytes"),
256 );
257 let pc = u32::from_le_bytes(
258 stub.data[4..8]
259 .try_into()
260 .expect("slice with exactly 4 bytes"),
261 );
262 self.debug_write_core_reg(PC.id.0, pc)?;
263 self.debug_write_core_reg(SP.id.0, sp)?;
264
265 self.debug_run()?;
267
268 spinner.finish(ProgressStatus::Success);
269
270 Ok(())
271 }
272}
273
274impl SifliTool for SF32LB52Tool {
275 fn create_tool(base: SifliToolBase) -> Box<dyn SifliTool> {
276 let mut port = serialport::new(&base.port_name, 1000000)
277 .timeout(Duration::from_secs(5))
278 .open()
279 .unwrap();
280 port.write_request_to_send(false).unwrap();
281 std::thread::sleep(Duration::from_millis(100));
282
283 let mut tool = Box::new(Self { base, port });
284 if tool.base.before.should_download_stub() {
285 tool.download_stub().expect("Failed to download stub");
286 }
287 tool
288 }
289}
290
291impl SifliToolTrait for SF32LB52Tool {
292 fn port(&mut self) -> &mut Box<dyn SerialPort> {
293 &mut self.port
294 }
295
296 fn base(&self) -> &SifliToolBase {
297 &self.base
298 }
299
300 fn set_speed(&mut self, baud: u32) -> Result<()> {
301 use crate::speed::SpeedTrait;
302 SpeedTrait::set_speed(self, baud)
303 }
304
305 fn soft_reset(&mut self) -> Result<()> {
306 use crate::reset::Reset;
307 Reset::soft_reset(self)
308 }
309}