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::serial_io::{for_tool, sleep_with_cancel};
12use crate::common::sifli_debug::SifliDebug;
13use crate::progress::{
14 EraseFlashStyle, EraseRegionStyle, ProgressOperation, ProgressStatus, StubStage,
15};
16use crate::sf32lb52::ram_command::DownloadStub;
17use crate::{Result, SifliTool, SifliToolBase, SifliToolTrait};
18use serialport::SerialPort;
19use std::time::Duration;
20
21pub struct SF32LB52Tool {
22 pub base: SifliToolBase,
23 pub port: Box<dyn SerialPort>,
24}
25
26unsafe impl Send for SF32LB52Tool {}
29unsafe impl Sync for SF32LB52Tool {}
30
31impl SF32LB52Tool {
32 pub fn internal_erase_all(&mut self, address: u32) -> Result<()> {
34 use ram_command::{Command, RamCommand};
35
36 let progress = self.progress();
37 let spinner = progress.create_spinner(ProgressOperation::EraseFlash {
38 address,
39 style: EraseFlashStyle::Addressed,
40 });
41
42 let _ = self.command(Command::EraseAll { address });
44
45 let mut io = for_tool(self);
46 io.wait_for_pattern(
47 b"OK",
48 Duration::from_millis(30_000),
49 &format!("erasing flash at 0x{:08X}", address),
50 )?;
51
52 spinner.finish(ProgressStatus::Success);
53
54 Ok(())
55 }
56
57 pub fn internal_erase_region(&mut self, address: u32, len: u32) -> Result<()> {
59 use ram_command::{Command, RamCommand};
60
61 let progress = self.progress();
62 let spinner = progress.create_spinner(ProgressOperation::EraseRegion {
63 address,
64 len,
65 style: EraseRegionStyle::LegacyFlashStartDecimalLength,
66 });
67
68 let _ = self.command(Command::Erase { address, len });
70
71 let timeout_ms = (len as u128 / (4 * 1024) + 1) * 800; tracing::info!(
73 "Erase region at 0x{:08X} with length 0x{:08X}, timeout: {} ms",
74 address,
75 len,
76 timeout_ms
77 );
78
79 let mut io = for_tool(self);
80 io.wait_for_pattern(
81 b"OK",
82 Duration::from_millis(timeout_ms as u64),
83 &format!("erasing region at 0x{:08X}", address),
84 )?;
85
86 spinner.finish(ProgressStatus::Success);
87
88 Ok(())
89 }
90
91 fn attempt_connect(&mut self) -> Result<()> {
92 use crate::common::sifli_debug::{SifliUartCommand, SifliUartResponse};
93
94 let infinite_attempts = self.base.connect_attempts <= 0;
95 let mut remaining_attempts = if infinite_attempts {
96 None
97 } else {
98 Some(self.base.connect_attempts)
99 };
100 loop {
101 if self.base.before.requires_reset() {
102 let mut io = for_tool(self);
104 io.write_request_to_send(true)?;
105 io.sleep(Duration::from_millis(100))?;
106 io.write_request_to_send(false)?;
107 io.sleep(Duration::from_millis(100))?;
108 }
109 let value: Result<()> = match self.debug_command(SifliUartCommand::Enter) {
110 Ok(SifliUartResponse::Enter) => Ok(()),
111 _ => Err(std::io::Error::other("Failed to enter debug mode").into()),
112 };
113 if let Some(ref mut attempts) = remaining_attempts {
115 if *attempts == 0 {
116 break; }
118 *attempts -= 1;
119 }
120
121 let progress = self.progress();
122 let spinner = progress.create_spinner(ProgressOperation::Connect);
123
124 match value {
126 Ok(_) => {
127 spinner.finish(ProgressStatus::Success);
128 return Ok(());
129 }
130 Err(_) => {
131 spinner.finish(ProgressStatus::Retry);
132 sleep_with_cancel(&self.base.cancel_token, Duration::from_millis(500))?;
133 }
134 }
135 }
136 Err(std::io::Error::other("Failed to connect to the chip").into())
137 }
138
139 fn download_stub_impl(&mut self) -> Result<()> {
140 use crate::common::sifli_debug::SifliUartCommand;
141 use crate::ram_stub::load_stub_file;
142 use probe_rs::MemoryMappedRegister;
143 use probe_rs::architecture::arm::core::armv7m::{Aircr, Demcr};
144 use probe_rs::architecture::arm::core::registers::cortex_m::{PC, SP};
145
146 let progress = self.progress();
147 let spinner = progress.create_spinner(ProgressOperation::DownloadStub {
148 stage: StubStage::Start,
149 });
150
151 let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
154 let mut demcr = Demcr(demcr);
155 demcr.set_vc_corereset(true);
156 self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
157
158 let mut aircr = Aircr(0);
160 aircr.vectkey();
161 aircr.set_sysresetreq(true);
162 let _ = self.debug_write_word32(Aircr::get_mmio_address() as u32, aircr.into()); sleep_with_cancel(
164 &self.base.cancel_token,
165 std::time::Duration::from_millis(10),
166 )?;
167
168 self.debug_command(SifliUartCommand::Enter)?;
170
171 self.debug_halt()?;
173
174 let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
176 let mut demcr = Demcr(demcr);
177 demcr.set_vc_corereset(false);
178 self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
179
180 sleep_with_cancel(
181 &self.base.cancel_token,
182 std::time::Duration::from_millis(100),
183 )?;
184 let chip_memory_key = format!("sf32lb52_{}", self.base.memory_type);
186 let stub = match load_stub_file(self.base.external_stub_path.as_deref(), &chip_memory_key) {
187 Ok(s) => s,
188 Err(e) => {
189 spinner.finish(ProgressStatus::NotFound);
190 return Err(e.into());
191 }
192 };
193
194 let packet_size = if self.base.compat { 256 } else { 64 * 1024 };
195
196 let mut addr = 0x2005_A000;
197 let mut data = &stub.data[..];
198 while !data.is_empty() {
199 let chunk = &data[..std::cmp::min(data.len(), packet_size)];
200 self.debug_write_memory(addr, chunk)?;
201 addr += chunk.len() as u32;
202 data = &data[chunk.len()..];
203 }
204
205 let bkp0r_addr = 0x500cb000 + 0x30;
208 let bkp0r_value = 0xA640;
209 self.debug_write_word32(bkp0r_addr, bkp0r_value)?;
210
211 let gpio_dosr0_addr = 0x500a0008;
213 let mut gpio_dosr0_value = self.debug_read_word32(gpio_dosr0_addr)?;
214 gpio_dosr0_value |= 1 << 21;
216 self.debug_write_word32(gpio_dosr0_addr, gpio_dosr0_value)?;
217
218 let sp = u32::from_le_bytes(
221 stub.data[0..4]
222 .try_into()
223 .expect("slice with exactly 4 bytes"),
224 );
225 let pc = u32::from_le_bytes(
226 stub.data[4..8]
227 .try_into()
228 .expect("slice with exactly 4 bytes"),
229 );
230 self.debug_write_core_reg(PC.id.0, pc)?;
231 self.debug_write_core_reg(SP.id.0, sp)?;
232
233 self.debug_run()?;
235
236 spinner.finish(ProgressStatus::Success);
237
238 Ok(())
239 }
240}
241
242impl SifliTool for SF32LB52Tool {
243 fn create_tool(base: SifliToolBase) -> Box<dyn SifliTool> {
244 let mut port = serialport::new(&base.port_name, 1000000)
245 .timeout(Duration::from_secs(5))
246 .open()
247 .unwrap();
248 port.write_request_to_send(false).unwrap();
249 std::thread::sleep(Duration::from_millis(100));
250
251 let mut tool = Box::new(Self { base, port });
252 if tool.base.before.should_download_stub() {
253 tool.download_stub().expect("Failed to download stub");
254 }
255 tool
256 }
257}
258
259impl SifliToolTrait for SF32LB52Tool {
260 fn port(&mut self) -> &mut Box<dyn SerialPort> {
261 &mut self.port
262 }
263
264 fn base(&self) -> &SifliToolBase {
265 &self.base
266 }
267
268 fn set_speed(&mut self, baud: u32) -> Result<()> {
269 use crate::speed::SpeedTrait;
270 SpeedTrait::set_speed(self, baud)
271 }
272
273 fn soft_reset(&mut self) -> Result<()> {
274 use crate::reset::Reset;
275 Reset::soft_reset(self)
276 }
277}