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::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
26// 为 SF32LB52Tool 实现 Send 和 Sync
27// 注意:这假设串口操作在设计上是线程安全的,或者我们会确保同一时间只有一个线程访问
28unsafe impl Send for SF32LB52Tool {}
29unsafe impl Sync for SF32LB52Tool {}
30
31impl SF32LB52Tool {
32    /// 执行全部flash擦除的内部方法
33    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        // 发送擦除所有命令
43        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    /// 执行区域擦除的内部方法
58    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        // 发送擦除区域命令
69        let _ = self.command(Command::Erase { address, len });
70
71        let timeout_ms = (len as u128 / (4 * 1024) + 1) * 800; // 我们假设每擦除1个sector(4KB)最长时间不超过800ms
72        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                // 使用RTS引脚复位
103                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            // 如果有限重试,检查是否还有机会
114            if let Some(ref mut attempts) = remaining_attempts {
115                if *attempts == 0 {
116                    break; // 超过最大重试次数则退出循环
117                }
118                *attempts -= 1;
119            }
120
121            let progress = self.progress();
122            let spinner = progress.create_spinner(ProgressOperation::Connect);
123
124            // 尝试连接
125            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        // 1. reset and halt
152        //    1.1. reset_catch_set
153        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        // 1.2. reset_system
159        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()); // MCU已经重启,不一定能收到正确回复
163        sleep_with_cancel(
164            &self.base.cancel_token,
165            std::time::Duration::from_millis(10),
166        )?;
167
168        // 1.3. Re-enter debug mode
169        self.debug_command(SifliUartCommand::Enter)?;
170
171        // 1.4. halt
172        self.debug_halt()?;
173
174        // 1.5. reset_catch_clear
175        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        // 2. Download stub - 支持外部 stub 文件
185        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        // 2.1.1 Set RTC->BKP0R to 0xA640
206        // RTC->BKP0R address is 0x500cb000 + 0x30
207        let bkp0r_addr = 0x500cb000 + 0x30;
208        let bkp0r_value = 0xA640;
209        self.debug_write_word32(bkp0r_addr, bkp0r_value)?;
210
211        // 2.1.2 Set PA21 GPIO DOSR0
212        let gpio_dosr0_addr = 0x500a0008;
213        let mut gpio_dosr0_value = self.debug_read_word32(gpio_dosr0_addr)?;
214        // PA21 is bit 21, set it to 1
215        gpio_dosr0_value |= 1 << 21;
216        self.debug_write_word32(gpio_dosr0_addr, gpio_dosr0_value)?;
217
218        // 3. run ram stub
219        // 3.1. set SP and PC
220        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        // 3.2. run
234        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}