Skip to main content

sftool_lib/sf32lb57/
mod.rs

1//! SF32LB57 chip-specific implementation.
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::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}