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::sf32lb52::ram_command::DownloadStub;
13use crate::{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
22// 为 SF32LB52Tool 实现 Send 和 Sync
23// 注意:这假设串口操作在设计上是线程安全的,或者我们会确保同一时间只有一个线程访问
24unsafe impl Send for SF32LB52Tool {}
25unsafe impl Sync for SF32LB52Tool {}
26
27impl SF32LB52Tool {
28    /// 执行全部flash擦除的内部方法
29    pub fn internal_erase_all(&mut self, address: u32) -> Result<(), std::io::Error> {
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        // 发送擦除所有命令
37        let _ = self.command(Command::EraseAll { address });
38
39        let mut buffer = Vec::new();
40        let now = std::time::SystemTime::now();
41
42        // 等待擦除完成
43        loop {
44            let elapsed = now.elapsed().unwrap().as_millis();
45            if elapsed > 30000 {
46                // 擦除可能需要更长时间
47                tracing::error!("response string is {}", String::from_utf8_lossy(&buffer));
48                return Err(std::io::Error::new(
49                    std::io::ErrorKind::TimedOut,
50                    "Erase timeout",
51                ));
52            }
53
54            let mut byte = [0];
55            let ret = self.port().read_exact(&mut byte);
56            if ret.is_err() {
57                continue;
58            }
59            buffer.push(byte[0]);
60
61            // 检查擦除完成响应
62            if buffer.windows(2).any(|window| window == b"OK") {
63                break;
64            }
65        }
66
67        spinner.finish_with_message(format!("Erase flash successfully: 0x{:08X}", address));
68
69        Ok(())
70    }
71
72    /// 执行区域擦除的内部方法
73    pub fn internal_erase_region(&mut self, address: u32, len: u32) -> Result<(), std::io::Error> {
74        use ram_command::{Command, RamCommand};
75
76        let progress = self.progress();
77        let spinner =
78            progress.create_spinner(format!("Erasing entire flash at 0x{:08X}...", address));
79
80        // 发送擦除区域命令
81        let _ = self.command(Command::Erase { address, len });
82
83        let mut buffer = Vec::new();
84        let now = std::time::SystemTime::now();
85
86        let timeout_ms = (len as u128 / (4 * 1024) + 1) * 800; // 我们假设每擦除1个sector(4KB)最长时间不超过800ms
87        tracing::info!(
88            "Erase region at 0x{:08X} with length 0x{:08X}, timeout: {} ms",
89            address,
90            len,
91            timeout_ms
92        );
93
94        // 等待擦除完成
95        loop {
96            let elapsed = now.elapsed().unwrap().as_millis();
97            if elapsed > timeout_ms {
98                // 擦除可能需要更长时间
99                tracing::error!("response string is {}", String::from_utf8_lossy(&buffer));
100                return Err(std::io::Error::new(
101                    std::io::ErrorKind::TimedOut,
102                    "Erase timeout",
103                ));
104            }
105
106            let mut byte = [0];
107            let ret = self.port().read_exact(&mut byte);
108            if ret.is_err() {
109                continue;
110            }
111            buffer.push(byte[0]);
112
113            // 检查擦除完成响应
114            if buffer.windows(2).any(|window| window == b"OK") {
115                break;
116            }
117        }
118
119        spinner.finish_with_message(format!(
120            "Erase region successfully: 0x{:08X} (length: {} bytes)",
121            address, len
122        ));
123
124        Ok(())
125    }
126
127    fn attempt_connect(&mut self) -> Result<(), std::io::Error> {
128        use crate::Operation;
129        use crate::common::sifli_debug::{SifliUartCommand, SifliUartResponse};
130
131        let infinite_attempts = self.base.connect_attempts <= 0;
132        let mut remaining_attempts = if infinite_attempts {
133            None
134        } else {
135            Some(self.base.connect_attempts)
136        };
137        loop {
138            if self.base.before == Operation::DefaultReset {
139                // 使用RTS引脚复位
140                self.port.write_request_to_send(true)?;
141                std::thread::sleep(Duration::from_millis(100));
142                self.port.write_request_to_send(false)?;
143                std::thread::sleep(Duration::from_millis(100));
144            }
145            let value = match self.debug_command(SifliUartCommand::Enter) {
146                Ok(SifliUartResponse::Enter) => Ok(()),
147                _ => Err(std::io::Error::new(
148                    std::io::ErrorKind::Other,
149                    "Failed to enter debug mode",
150                )),
151            };
152            // 如果有限重试,检查是否还有机会
153            if let Some(ref mut attempts) = remaining_attempts {
154                if *attempts == 0 {
155                    break; // 超过最大重试次数则退出循环
156                }
157                *attempts -= 1;
158            }
159
160            let progress = self.progress();
161            let spinner = progress.create_spinner("Connecting to chip...");
162
163            // 尝试连接
164            match value {
165                Ok(_) => {
166                    spinner.finish_with_message("Connected success!");
167                    return Ok(());
168                }
169                Err(_) => {
170                    spinner.finish_with_message("Failed to connect to the chip, retrying...");
171                    std::thread::sleep(Duration::from_millis(500));
172                }
173            }
174        }
175        Err(std::io::Error::new(
176            std::io::ErrorKind::Other,
177            "Failed to connect to the chip",
178        ))
179    }
180
181    fn download_stub_impl(&mut self) -> Result<(), std::io::Error> {
182        use crate::common::sifli_debug::SifliUartCommand;
183        use crate::ram_stub::{self, CHIP_FILE_NAME};
184        use probe_rs::MemoryMappedRegister;
185        use probe_rs::architecture::arm::core::armv7m::{Aircr, Demcr};
186        use probe_rs::architecture::arm::core::registers::cortex_m::{PC, SP};
187
188        let progress = self.progress();
189        let spinner = progress.create_spinner("Download stub...");
190
191        // 1. reset and halt
192        //    1.1. reset_catch_set
193        let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
194        let mut demcr = Demcr(demcr);
195        demcr.set_vc_corereset(true);
196        self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
197
198        // 1.2. reset_system
199        let mut aircr = Aircr(0);
200        aircr.vectkey();
201        aircr.set_sysresetreq(true);
202        let _ = self.debug_write_word32(Aircr::get_mmio_address() as u32, aircr.into()); // MCU已经重启,不一定能收到正确回复
203        std::thread::sleep(std::time::Duration::from_millis(10));
204
205        // 1.3. Re-enter debug mode
206        self.debug_command(SifliUartCommand::Enter)?;
207
208        // 1.4. halt
209        self.debug_halt()?;
210
211        // 1.5. reset_catch_clear
212        let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
213        let mut demcr = Demcr(demcr);
214        demcr.set_vc_corereset(false);
215        self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
216
217        std::thread::sleep(std::time::Duration::from_millis(100));
218        // 2. Download stub
219        let stub = ram_stub::RamStubFile::get(
220            CHIP_FILE_NAME
221                .get(format!("sf32lb52_{}", self.base.memory_type).as_str())
222                .expect("REASON"),
223        );
224        let Some(stub) = stub else {
225            spinner.finish_with_message("No stub file found for the given chip and memory type");
226            return Err(std::io::Error::new(
227                std::io::ErrorKind::NotFound,
228                "No stub file found for the given chip and memory type",
229            ));
230        };
231
232        let packet_size = if self.base.compat { 256 } else { 64 * 1024 };
233
234        let mut addr = 0x2005_A000;
235        let mut data = &stub.data[..];
236        while !data.is_empty() {
237            let chunk = &data[..std::cmp::min(data.len(), packet_size)];
238            self.debug_write_memory(addr, chunk)?;
239            addr += chunk.len() as u32;
240            data = &data[chunk.len()..];
241        }
242
243        // 2.1.1 Set RTC->BKP0R to 0xA640
244        // RTC->BKP0R address is 0x500cb000 + 0x30
245        let bkp0r_addr = 0x500cb000 + 0x30;
246        let bkp0r_value = 0xA640;
247        self.debug_write_word32(bkp0r_addr, bkp0r_value)?;
248
249        // 2.1.2 Set PA21 GPIO DOSR0
250        let gpio_dosr0_addr = 0x500a0008;
251        let mut gpio_dosr0_value = self.debug_read_word32(gpio_dosr0_addr)?;
252        // PA21 is bit 21, set it to 1
253        gpio_dosr0_value |= 1 << 21;
254        self.debug_write_word32(gpio_dosr0_addr, gpio_dosr0_value)?;
255
256        // 3. run ram stub
257        // 3.1. set SP and PC
258        let sp = u32::from_le_bytes(
259            stub.data[0..4]
260                .try_into()
261                .expect("slice with exactly 4 bytes"),
262        );
263        let pc = u32::from_le_bytes(
264            stub.data[4..8]
265                .try_into()
266                .expect("slice with exactly 4 bytes"),
267        );
268        self.debug_write_core_reg(PC.id.0, pc)?;
269        self.debug_write_core_reg(SP.id.0, sp)?;
270
271        // 3.2. run
272        self.debug_run()?;
273
274        spinner.finish_with_message("Download stub success!");
275
276        Ok(())
277    }
278}
279
280impl SifliTool for SF32LB52Tool {
281    fn create_tool(base: SifliToolBase) -> Box<dyn SifliTool> {
282        let mut port = serialport::new(&base.port_name, 1000000)
283            .timeout(Duration::from_secs(5))
284            .open()
285            .unwrap();
286        port.write_request_to_send(false).unwrap();
287        std::thread::sleep(Duration::from_millis(100));
288
289        let mut tool = Box::new(Self { base, port });
290        tool.download_stub().expect("Failed to download stub");
291        tool
292    }
293}
294
295impl SifliToolTrait for SF32LB52Tool {
296    fn port(&mut self) -> &mut Box<dyn SerialPort> {
297        &mut self.port
298    }
299
300    fn base(&self) -> &SifliToolBase {
301        &self.base
302    }
303
304    fn set_speed(&mut self, baud: u32) -> Result<(), std::io::Error> {
305        use crate::speed::SpeedTrait;
306        SpeedTrait::set_speed(self, baud)
307    }
308
309    fn soft_reset(&mut self) -> Result<(), std::io::Error> {
310        use crate::reset::Reset;
311        Reset::soft_reset(self)
312    }
313}