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