Skip to main content

sftool_lib/sf32lb52/
mod.rs

1//! SF32LB52 芯片特定实现模块
2
3pub 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
25// 为 SF32LB52Tool 实现 Send 和 Sync
26// 注意:这假设串口操作在设计上是线程安全的,或者我们会确保同一时间只有一个线程访问
27unsafe impl Send for SF32LB52Tool {}
28unsafe impl Sync for SF32LB52Tool {}
29
30impl SF32LB52Tool {
31    /// 执行全部flash擦除的内部方法
32    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        // 发送擦除所有命令
42        let _ = self.command(Command::EraseAll { address });
43
44        let mut buffer = Vec::new();
45        let now = std::time::SystemTime::now();
46
47        // 等待擦除完成
48        loop {
49            let elapsed = now.elapsed().unwrap().as_millis();
50            if elapsed > 30000 {
51                // 擦除可能需要更长时间
52                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            // 检查擦除完成响应
66            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    /// 执行区域擦除的内部方法
77    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        // 发送擦除区域命令
88        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; // 我们假设每擦除1个sector(4KB)最长时间不超过800ms
94        tracing::info!(
95            "Erase region at 0x{:08X} with length 0x{:08X}, timeout: {} ms",
96            address,
97            len,
98            timeout_ms
99        );
100
101        // 等待擦除完成
102        loop {
103            let elapsed = now.elapsed().unwrap().as_millis();
104            if elapsed > timeout_ms {
105                // 擦除可能需要更长时间
106                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            // 检查擦除完成响应
120            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                // 使用RTS引脚复位
142                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            // 如果有限重试,检查是否还有机会
152            if let Some(ref mut attempts) = remaining_attempts {
153                if *attempts == 0 {
154                    break; // 超过最大重试次数则退出循环
155                }
156                *attempts -= 1;
157            }
158
159            let progress = self.progress();
160            let spinner = progress.create_spinner(ProgressOperation::Connect);
161
162            // 尝试连接
163            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        // 1. reset and halt
190        //    1.1. reset_catch_set
191        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        // 1.2. reset_system
197        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()); // MCU已经重启,不一定能收到正确回复
201        std::thread::sleep(std::time::Duration::from_millis(10));
202
203        // 1.3. Re-enter debug mode
204        self.debug_command(SifliUartCommand::Enter)?;
205
206        // 1.4. halt
207        self.debug_halt()?;
208
209        // 1.5. reset_catch_clear
210        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        // 2. Download stub - 支持外部 stub 文件
217        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        // 2.1.1 Set RTC->BKP0R to 0xA640
238        // RTC->BKP0R address is 0x500cb000 + 0x30
239        let bkp0r_addr = 0x500cb000 + 0x30;
240        let bkp0r_value = 0xA640;
241        self.debug_write_word32(bkp0r_addr, bkp0r_value)?;
242
243        // 2.1.2 Set PA21 GPIO DOSR0
244        let gpio_dosr0_addr = 0x500a0008;
245        let mut gpio_dosr0_value = self.debug_read_word32(gpio_dosr0_addr)?;
246        // PA21 is bit 21, set it to 1
247        gpio_dosr0_value |= 1 << 21;
248        self.debug_write_word32(gpio_dosr0_addr, gpio_dosr0_value)?;
249
250        // 3. run ram stub
251        // 3.1. set SP and PC
252        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        // 3.2. run
266        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}