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