spi_flash/
lib.rs

1// Copyright 2020, 2021 Adam Greig
2// Licensed under the Apache-2.0 and MIT licenses.
3
4//! spi-flash
5//!
6//! This crate provides an interface for common SPI flash memories,
7//! including discovering ID and parameters, reading, and writing.
8
9#![cfg_attr(not(feature = "std"), no_std)]
10
11extern crate alloc;
12use alloc::vec::Vec;
13
14use core::convert::TryInto;
15use core::time::Duration;
16#[cfg(feature = "std")]
17use indicatif::{ProgressBar, ProgressStyle};
18#[cfg(feature = "std")]
19use std::time::Instant;
20
21pub mod erase_plan;
22pub mod id;
23pub mod sfdp;
24pub mod sreg;
25
26pub use id::FlashID;
27pub use sfdp::{FlashParams, SFDPAddressBytes, SFDPEraseInst, SFDPStatus1Volatility, SFDPTiming};
28pub use sreg::{StatusRegister1, StatusRegister2, StatusRegister3};
29
30use erase_plan::ErasePlan;
31use sfdp::SFDPHeader;
32
33#[cfg_attr(feature = "std", derive(thiserror::Error, Debug))]
34pub enum Error {
35    #[cfg_attr(feature = "std", error("Mismatch during flash readback verification."))]
36    ReadbackError { address: u32, wrote: u8, read: u8 },
37    #[cfg_attr(feature = "std", error("Invalid manufacturer ID detected."))]
38    InvalidManufacturer,
39    #[cfg_attr(feature = "std", error("Invalid SFDP header."))]
40    InvalidSFDPHeader,
41    #[cfg_attr(feature = "std", error("Invalid parameter in SFDP parameter table."))]
42    InvalidSFDPParams,
43    #[cfg_attr(
44        feature = "std",
45        error("Address out of range for memory: 0x{address:08X}.")
46    )]
47    InvalidAddress { address: u32 },
48    #[cfg_attr(feature = "std", error("No supported reset instruction is available."))]
49    NoResetInstruction,
50    #[cfg_attr(feature = "std", error("No erase instruction has been specified."))]
51    NoEraseInstruction,
52
53    #[cfg(feature = "std")]
54    #[error(transparent)]
55    Access(#[from] anyhow::Error),
56
57    #[cfg(not(feature = "std"))]
58    Access,
59}
60
61pub type Result<T> = core::result::Result<T, Error>;
62
63/// Trait for objects which provide access to SPI flash.
64///
65/// Providers only need to implement `exchange()`, which asserts CS, writes all the bytes
66/// in `data`, then returns all the received bytes. If it provides a performance optimisation,
67/// providers may also implement `write()`, which does not require the received data.
68///
69/// `From<FlashAccess::Error>` must be implemented for `spi_flash::Error`; for example in your
70/// implementation code, add:
71///
72/// ```
73/// # #[derive(thiserror::Error, Debug)] enum MyError {}
74/// impl From<MyError> for spi_flash::Error {
75///     fn from(err: MyError) -> spi_flash::Error {
76///         spi_flash::Error::Access(err.into())
77///     }
78/// }
79/// ```
80pub trait FlashAccess {
81    type Error;
82
83    /// Assert CS, write all bytes in `data` to the SPI bus, then de-assert CS.
84    fn write(&mut self, data: &[u8]) -> core::result::Result<(), Self::Error> {
85        // Default implementation uses `exchange()` and ignores the result data.
86        self.exchange(data)?;
87        Ok(())
88    }
89
90    /// Assert CS, write all bytes in `data` while capturing received data, then de-assert CS.
91    ///
92    /// Returns the received data.
93    fn exchange(&mut self, data: &[u8]) -> core::result::Result<Vec<u8>, Self::Error>;
94
95    /// Wait for at least `duration`.
96    ///
97    /// This delay is advisory and reduces polling traffic based on known
98    /// typical flash instruction times, so may be left unimplemented.
99    ///
100    /// The default implementation uses std::thread::delay on std,
101    /// and is a no-op on no_std.
102    fn delay(&mut self, duration: Duration) {
103        #[cfg(feature = "std")]
104        std::thread::sleep(duration);
105    }
106}
107
108/// SPI Flash.
109///
110/// This struct provides methods for interacting with common SPI flashes.
111pub struct Flash<'a, A: FlashAccess> {
112    access: &'a mut A,
113
114    /// Once read, ID details are cached.
115    id: Option<FlashID>,
116
117    /// Once read, SFDP parameters are cached.
118    params: Option<FlashParams>,
119
120    /// Number of address bytes to use when reading and writing.
121    /// This is set to 3 by default for compatibility, but may
122    /// be set to 2 for legacy memories or 4 for high-density memories.
123    address_bytes: u8,
124
125    /// Total data memory capacity in bytes, up to 4GB.
126    capacity: Option<usize>,
127
128    /// Page size in bytes, used for programming operations.
129    page_size: Option<usize>,
130
131    /// Sector size in bytes, used for the smallest erase operations.
132    erase_size: Option<usize>,
133
134    /// EraseSector instruction opcode.
135    /// This is set to 0x20 by default but may be overridden.
136    erase_opcode: u8,
137}
138
139impl<'a, A: FlashAccess> Flash<'a, A>
140where
141    Error: From<<A as FlashAccess>::Error>,
142{
143    #[cfg(feature = "std")]
144    const DATA_PROGRESS_TPL: &'static str =
145        " {msg} [{bar:40.cyan/black}] {bytes}/{total_bytes} ({bytes_per_sec}; {eta_precise})";
146    #[cfg(feature = "std")]
147    const DATA_FINISHED_TPL: &'static str =
148        " {msg} [{bar:40.green/black}] {bytes}/{total_bytes} ({bytes_per_sec}; {eta_precise})";
149    #[cfg(feature = "std")]
150    const DATA_PROGRESS_CHARS: &'static str = "━╸━";
151
152    /// Create a new Flash instance using the given FlashAccess provider.
153    pub fn new(access: &'a mut A) -> Self {
154        Flash {
155            access,
156            id: None,
157            params: None,
158            address_bytes: 3,
159            capacity: None,
160            page_size: None,
161            erase_size: None,
162            erase_opcode: 0x20,
163        }
164    }
165
166    /// Get the number of address bytes which will be used in read and write commands.
167    pub fn address_bytes(&self) -> u8 {
168        self.address_bytes
169    }
170
171    /// Set the number of address bytes to use with read and write commands.
172    /// By default this is set to 3, and can also be autodiscovered using SFDP.
173    ///
174    /// Panics if `n` is less than 1 or greater than 4.
175    pub fn set_address_bytes(&mut self, n: u8) {
176        assert!(n >= 1, "set_address_bytes: n must be at least 1");
177        assert!(n <= 4, "set_address_bytes: n must not exceed 4");
178        self.address_bytes = n;
179    }
180
181    /// Get the total memory capacity in bytes, if known.
182    pub fn capacity(&self) -> Option<usize> {
183        self.capacity
184    }
185
186    /// Set the total memory capacity in bytes.
187    ///
188    /// If set, or discovered using SFDP, reads and writes are prevented
189    /// from going beyond the memory capacity.
190    pub fn set_capacity(&mut self, n: usize) {
191        self.capacity = Some(n);
192    }
193
194    /// Get the page program size in bytes.
195    pub fn page_size(&self) -> Option<usize> {
196        self.page_size
197    }
198
199    /// Set the page program size in bytes.
200    ///
201    /// This must be known before page program operations can be performed.
202    pub fn set_page_size(&mut self, n: usize) {
203        self.page_size = Some(n);
204    }
205
206    /// Get the sector erase size in bytes, if known.
207    pub fn erase_size(&self) -> Option<usize> {
208        self.erase_size
209    }
210
211    /// Set the sector erase size in bytes.
212    ///
213    /// This must be known before sector erase operations can be performed.
214    pub fn set_erase_size(&mut self, n: usize) {
215        self.erase_size = Some(n);
216    }
217
218    /// Get the opcode used for the Erase Sector instruction.
219    pub fn erase_opcode(&self) -> u8 {
220        self.erase_opcode
221    }
222
223    /// Set the opcode used for the Erase Sector instruction.
224    ///
225    /// This is 0x20 by default.
226    pub fn set_erase_opcode(&mut self, opcode: u8) {
227        self.erase_opcode = opcode;
228    }
229
230    /// Get the flash ID, if it has already been read.
231    ///
232    /// Call `read_id()` to read the ID from the flash.
233    pub fn get_id(&self) -> Option<FlashID> {
234        self.id
235    }
236
237    /// Get the flash parameters, if they have already been read.
238    ///
239    /// Call `read_params()` to read the params from the flash.
240    pub fn get_params(&self) -> Option<FlashParams> {
241        self.params
242    }
243
244    /// Read the device's manufacturer ID and device IDs.
245    ///
246    /// This method additionally brings the flash out of powerdown and resets it.
247    ///
248    /// `self.id` is updated with the new ID; use `get_id()` to
249    /// retrieve it without re-reading the ID from the flash.
250    pub fn read_id(&mut self) -> Result<FlashID> {
251        log::debug!("Reading SPI Flash ID");
252
253        let legacy_id = self.release_power_down()?;
254        self.reset()?;
255
256        let (bank_long, mfn_id_long, device_id_long) = self.read_jedec_id()?;
257        let (bank_short, mfn_id_short, mut device_id_short) = self.read_device_id()?;
258        let unique_id = self.read_unique_id()?;
259
260        // The device may implement any or none of the three identification
261        // instructions; attempt to obtain a valid manufacturer ID and device ID.
262        // If there is no device present or a communication error, we'll probably
263        // receive all-0s or all-1s for all the data.
264        let manufacturer_bank;
265        let manufacturer_id;
266        if mfn_id_long != 0x00 && mfn_id_long != 0xFF {
267            manufacturer_bank = bank_long;
268            manufacturer_id = mfn_id_long;
269        } else if mfn_id_short != 0x00 && mfn_id_short != 0xFF {
270            manufacturer_bank = bank_short;
271            manufacturer_id = mfn_id_short;
272        } else {
273            log::warn!("No valid manufacturer ID found");
274            if legacy_id == 0x00 || legacy_id == 0xFF {
275                log::error!("No device or manufacturer ID found");
276                return Err(Error::InvalidManufacturer);
277            } else {
278                device_id_short = legacy_id;
279                manufacturer_bank = 0;
280                manufacturer_id = 0;
281            }
282        }
283
284        let id = FlashID {
285            manufacturer_bank,
286            manufacturer_id,
287            device_id_long,
288            device_id_short,
289            unique_id,
290        };
291
292        log::debug!("Read ID: {:?}", id);
293        self.id = Some(id);
294        Ok(id)
295    }
296
297    /// Read SFDP JEDEC Basic Flash Parameter table from flash.
298    ///
299    /// Access errors are returned as usual, but if SFDP is not supported
300    /// (no SFDP signature is detected in the first SFDP DWORD) then
301    /// `Ok(None)` is returned instead.
302    ///
303    /// Depending on the version of SFDP supported, some fields may
304    /// not be available.
305    ///
306    /// Once read, the parameters are available using `get_params()`,
307    /// and the parameter values are automatically used for the
308    /// configuration of address bytes, capacity, page size, sector size,
309    /// and erase sector opcode. Additionally, larger erase commands
310    /// described by the SFDP parameters will be used when appropriate.
311    pub fn read_params(&mut self) -> Result<Option<FlashParams>> {
312        log::debug!("Reading SFDP data");
313
314        // Read just SFDP header to get NPH first.
315        let data = self.read_sfdp(0, 8)?;
316        let nph = data[6] as usize + 1;
317
318        // Re-read overall SFDP header including parameter headers.
319        // Handle errors parsing the header by returning Ok(None),
320        // since not all flash devices support SFDP.
321        // After this parse is successful, however, subsequent errors
322        // are returned as errors.
323        let data = self.read_sfdp(0, 8 + nph * 8)?;
324        let header = match SFDPHeader::from_bytes(&data) {
325            Ok(header) => header,
326            Err(_) => return Ok(None),
327        };
328
329        // Check the first parameter header is the JEDEC basic flash parameters,
330        // as required by JESD216.
331        let params = header.params[0];
332        if params.parameter_id != 0xFF00 || params.major != 0x01 {
333            log::error!("Unexpected first SFDP parameter header: expected 0xFF00 version 1.");
334            return Err(Error::InvalidSFDPHeader);
335        }
336
337        // Read SFDP table data and parse into a FlashParams struct.
338        let data = self.read_sfdp(params.ptp, params.plen * 4)?;
339        let params = FlashParams::from_bytes(params.major, params.minor, &data)?;
340        self.params = Some(params);
341
342        // Use params to update settings where posssible.
343        self.address_bytes = match params.address_bytes {
344            SFDPAddressBytes::Three => 3,
345            SFDPAddressBytes::ThreeOrFour => 3,
346            SFDPAddressBytes::Four => 4,
347            _ => 3,
348        };
349        self.capacity = Some(params.capacity_bytes());
350        if let Some(page_size) = params.page_size {
351            self.page_size = Some(page_size as usize);
352        }
353        if let Some((size, opcode)) = params.sector_erase() {
354            self.erase_size = Some(size);
355            self.erase_opcode = opcode;
356        } else if params.legacy_4kb_erase_supported && params.legacy_4kb_erase_inst != 0xFF {
357            self.erase_size = Some(4096);
358            self.erase_opcode = params.legacy_4kb_erase_inst;
359        }
360        log::debug!("Updated settings from parameters:");
361        log::debug!(
362            "Address bytes: {}, capacity: {:?} bytes",
363            self.address_bytes,
364            self.capacity
365        );
366        log::debug!(
367            "Page size: {:?}, erase size: {:?}, erase op: {}",
368            self.page_size,
369            self.erase_size,
370            self.erase_opcode
371        );
372
373        Ok(Some(params))
374    }
375
376    /// Read `length` bytes of data from the attached flash, starting at `address`.
377    ///
378    /// This method uses the FastRead instruction; if it is not supported
379    /// try using `legacy_read()` instead.
380    pub fn read(&mut self, address: u32, length: usize) -> Result<Vec<u8>> {
381        self.check_address_length(address, length)?;
382        let mut param = self.make_address(address);
383        // Dummy byte after address.
384        param.push(0);
385        self.exchange(Command::FastRead, &param, length)
386    }
387
388    /// Read `length` bytes of data from the attached flash, starting at `address`.
389    ///
390    /// This method uses the legacy ReadData instruction, which often has a low
391    /// maximum clock speed compared to other operations, but is more widely supported
392    /// and may be faster for very short reads as it does not require a dummy byte.
393    pub fn legacy_read(&mut self, address: u32, length: usize) -> Result<Vec<u8>> {
394        self.check_address_length(address, length)?;
395        let param = self.make_address(address);
396        self.exchange(Command::ReadData, &param, length)
397    }
398
399    /// Read `length` bytes of data from the attached flash, starting at `address`.
400    ///
401    /// This method is similar to the `read()` method, except it calls the provided
402    /// callback function at regular intervals with the number of bytes read so far.
403    ///
404    /// While `read()` performs a single long SPI exchange, this method performs
405    /// up to 128 separate SPI exchanges to allow progress to be reported.
406    pub fn read_cb<F: Fn(usize)>(&mut self, address: u32, length: usize, cb: F) -> Result<Vec<u8>> {
407        self.check_address_length(address, length)?;
408        let chunk_size = usize::max(1024, length / 128);
409        let start = address as usize;
410        let end = start + length;
411        let mut data = Vec::new();
412        cb(0);
413        for addr in (start..end).step_by(chunk_size) {
414            let size = usize::min(chunk_size, end - addr);
415            let mut param = self.make_address(addr as u32);
416            param.push(0);
417            data.append(&mut self.exchange(Command::FastRead, &param, size)?);
418            cb(data.len());
419        }
420        cb(data.len());
421        Ok(data)
422    }
423
424    /// Read `length` bytes of data from the attached flash, starting at `address`.
425    ///
426    /// This method is similar to the `read()` method, except it renders a progress
427    /// bar to the terminal during the read.
428    ///
429    /// While `read()` performs a single long SPI exchange, this method performs
430    /// up to 128 separate SPI exchanges to allow progress to be reported.
431    #[cfg(feature = "std")]
432    pub fn read_progress(&mut self, address: u32, length: usize) -> Result<Vec<u8>> {
433        let pb = ProgressBar::new(length as u64).with_style(
434            ProgressStyle::with_template(Self::DATA_PROGRESS_TPL)
435                .unwrap()
436                .progress_chars(Self::DATA_PROGRESS_CHARS),
437        );
438        pb.set_message("Reading");
439        let result = self.read_cb(address, length, |n| pb.set_position(n as u64));
440        pb.set_style(
441            ProgressStyle::with_template(Self::DATA_FINISHED_TPL)
442                .unwrap()
443                .progress_chars(Self::DATA_PROGRESS_CHARS),
444        );
445        pb.finish();
446        result
447    }
448
449    /// Erase entire flash chip.
450    ///
451    /// This method uses the ChipErase instruction, so no progress information
452    /// is available, but the typical and maximum times taken may be available
453    /// from the SFDP parameters.
454    ///
455    /// Returns only after erase operation is complete.
456    pub fn erase(&mut self) -> Result<()> {
457        self.write_enable()?;
458        self.command(Command::ChipErase)?;
459        self.wait_while_busy()?;
460        Ok(())
461    }
462
463    /// Erase entire flash chip.
464    ///
465    /// This method is identical to `erase()`, except it draws a progress bar
466    /// to the terminal during the erase operation.
467    ///
468    /// If SFDP data indicates a typical chip erase time, that value is used,
469    /// otherwise the progress bar is drawn as a spinner.
470    #[cfg(feature = "std")]
471    pub fn erase_progress(&mut self) -> Result<()> {
472        let time = self.params.map(|p| p.timing.map(|t| t.chip_erase_time_typ));
473        let pb = if let Some(Some(time)) = time {
474            ProgressBar::new(time.as_millis() as u64).with_style(
475                ProgressStyle::with_template(" {msg} [{bar:40.cyan/black}] {elapsed} < {eta}")
476                    .unwrap()
477                    .progress_chars(Self::DATA_PROGRESS_CHARS),
478            )
479        } else {
480            ProgressBar::new_spinner()
481        };
482        pb.set_message("Erasing");
483        let t0 = Instant::now();
484        self.write_enable()?;
485        self.command(Command::ChipErase)?;
486        while self.is_busy()? {
487            let t = t0.elapsed().as_millis() as u64;
488            pb.set_position(t);
489        }
490        pb.finish();
491        Ok(())
492    }
493
494    /// Program the attached flash with `data` starting at `address`.
495    ///
496    /// Sectors and blocks are erased as required for the new data,
497    /// and existing data outside the new data to write is written
498    /// back if it has to be erased.
499    ///
500    /// If `verify` is true, the programmed data is read back, and
501    /// a ReadbackError will be returned if it did not match what was written.
502    ///
503    /// When available, SFDP parameters are used to generate an efficient
504    /// sequence of erase instructions. If unavailable, the single erase
505    /// instruction in `erase_opcode` is used, and its size of effect
506    /// must be given in `erase_size`. If these are not set, a
507    /// `NoEraseInstruction` is returned.
508    ///
509    /// The programming page size is set by `page_size`, which is
510    /// automatically set when SFDP parameters are read.
511    pub fn program(&mut self, address: u32, data: &[u8], verify: bool) -> Result<()> {
512        self.check_address_length(address, data.len())?;
513
514        // Work out a good erasure plan.
515        let erase_plan = self.make_erase_plan(address, data.len())?;
516
517        // Read data which will be inadvertently erased so we can restore it.
518        let full_data = self.make_restore_data(address, data, &erase_plan)?;
519
520        // Execute erasure plan.
521        self.run_erase_plan(&erase_plan, |_| {})?;
522
523        // Write new data.
524        let start_addr = erase_plan.0[0].2;
525        self.program_data(start_addr, &full_data)?;
526
527        // Optionally do a readback to verify all written data.
528        if verify {
529            let programmed = self.read(start_addr, full_data.len())?;
530            self.verify_readback(start_addr, &full_data, &programmed)?;
531        }
532
533        Ok(())
534    }
535
536    /// Program the attached flash with `data` starting at `address`.
537    ///
538    /// This is identical to `program()`, except it also draws progress bars to the terminal.
539    #[cfg(feature = "std")]
540    pub fn program_progress(&mut self, address: u32, data: &[u8], verify: bool) -> Result<()> {
541        self.check_address_length(address, data.len())?;
542
543        // Work out a good erasure plan.
544        let erase_plan = self.make_erase_plan(address, data.len())?;
545
546        // Read data which will be inadvertently erased so we can restore it.
547        let full_data = self.make_restore_data(address, data, &erase_plan)?;
548
549        // Execute erasure plan.
550        self.run_erase_plan_progress(&erase_plan)?;
551
552        // Write new data.
553        let start_addr = erase_plan.0[0].2;
554        self.program_data_progress(start_addr, &full_data)?;
555
556        // Optionally do a readback to verify all written data.
557        if verify {
558            let programmed = self.read_progress(start_addr, full_data.len())?;
559            self.verify_readback(start_addr, &full_data, &programmed)?;
560        }
561
562        Ok(())
563    }
564
565    /// Reset the attached flash.
566    ///
567    /// The instruction sequence EnableReset 0x66 followed by Reset 0x99
568    /// is sent by default, but if the SFDP parameters indicate that only
569    /// the 0xF0 instruction is supported for reset, that is sent instead.
570    pub fn reset(&mut self) -> Result<()> {
571        let mut do_f0 = false;
572        let mut do_66_99 = true;
573
574        if let Some(params) = self.params {
575            if let Some(op_66_99) = params.reset_inst_66_99 {
576                do_66_99 = op_66_99;
577            }
578            if let Some(op_f0) = params.reset_inst_f0 {
579                do_f0 = op_f0;
580            }
581        }
582
583        if do_66_99 {
584            self.command(Command::EnableReset)?;
585            self.command(Command::Reset)
586        } else if do_f0 {
587            self.command(0xF0)
588        } else {
589            log::error!("No reset instruction available.");
590            Err(Error::NoResetInstruction)
591        }
592    }
593
594    /// Check if any block protect bits are set in status register 1.
595    pub fn is_protected(&mut self) -> Result<bool> {
596        log::debug!("Checking if BP bits are set");
597        let status1 = self.read_status1()?;
598        let (bp0, bp1, bp2) = status1.get_block_protect();
599        log::debug!("BP0: {}, BP1: {}, BP2: {}", bp0, bp1, bp2);
600        Ok(bp0 || bp1 || bp2)
601    }
602
603    /// Set block protection bits.
604    ///
605    /// This sets the block protect bits in status register 1,
606    /// using the non-volatile commands if supported. If available,
607    /// the SFDP parameters are used to determine the correct
608    /// non-volatile instruction.
609    pub fn protect(&mut self, bp0: bool, bp1: bool, bp2: bool) -> Result<()> {
610        log::debug!(
611            "Setting block protection bits to BP0={}, BP1={}, BP2={}",
612            bp0,
613            bp1,
614            bp2
615        );
616        let mut status1 = self.read_status1()?;
617        status1.set_block_protect(bp0, bp1, bp2);
618        self.write_status1(status1)?;
619        self.wait_while_busy()?;
620        Ok(())
621    }
622
623    /// Clear any protection bits that are set.
624    ///
625    /// This checks and clears the block protect bits in status register 1,
626    /// using the non-volatile commands if supported. If available, the SFDP
627    /// parameters are used to determine the correct non-volatile instruction.
628    pub fn unprotect(&mut self) -> Result<()> {
629        log::debug!("Checking if BP bits are set before clearing them");
630        let mut status1 = self.read_status1()?;
631        let (bp0, bp1, bp2) = status1.get_block_protect();
632        if bp0 || bp1 || bp2 {
633            log::debug!("Block protect bits are currently set, clearing.");
634            status1.set_block_protect(false, false, false);
635            self.write_status1(status1)?;
636            self.wait_while_busy()?;
637        }
638        Ok(())
639    }
640
641    /// Clear the write-protect-selection bit in status register 3, if set.
642    ///
643    /// This status bit configures the fine-granularity write protection
644    /// which is a vendor-specific extension that is disabled by default.
645    ///
646    /// Unfortunately it is not possible to determine automatically if a
647    /// flash chip supports the WPS feature or even has a status register 3,
648    /// so this command is not called automatically.
649    pub fn unprotect_wps(&mut self) -> Result<()> {
650        let mut status3 = self.read_status3()?;
651        if status3.get_wps() {
652            log::debug!("WPS bit set, clearing.");
653            status3.set_wps(false);
654            self.write_status3(status3)?;
655            self.wait_while_busy()?;
656        }
657        Ok(())
658    }
659
660    /// Power down the flash.
661    pub fn power_down(&mut self) -> Result<()> {
662        log::debug!("Sending Powerdown command");
663        self.command(Command::Powerdown)
664    }
665
666    /// Power up the flash.
667    ///
668    /// Returns the legacy device ID.
669    pub fn release_power_down(&mut self) -> Result<u8> {
670        log::debug!("Sending Release Powerdown command");
671        let data = self.exchange(Command::ReleasePowerdown, &[0, 0, 0], 1)?;
672        Ok(data[0])
673    }
674
675    /// Program `data` to `address`, automatically split into multiple page program operations.
676    ///
677    /// Note that this does *not* erase the flash beforehand; use `program()` for a higher-level
678    /// erase-program-verify interface.
679    pub fn program_data(&mut self, address: u32, data: &[u8]) -> Result<()> {
680        self.program_data_cb(address, data, |_| {})
681    }
682
683    /// Program `data` to `address`, automatically split into multiple page program operations,
684    /// and draws a progress bar to the terminal.
685    ///
686    /// Note that this does *not* erase the flash beforehand;
687    /// use `program()` for a higher-level erase-program-verify interface.
688    #[cfg(feature = "std")]
689    pub fn program_data_progress(&mut self, address: u32, data: &[u8]) -> Result<()> {
690        let pb = ProgressBar::new(data.len() as u64).with_style(
691            ProgressStyle::with_template(Self::DATA_PROGRESS_TPL)
692                .unwrap()
693                .progress_chars(Self::DATA_PROGRESS_CHARS),
694        );
695        pb.set_message("Writing");
696        self.program_data_cb(address, &data, |n| pb.set_position(n as u64))?;
697        pb.set_style(
698            ProgressStyle::with_template(Self::DATA_FINISHED_TPL)
699                .unwrap()
700                .progress_chars(Self::DATA_PROGRESS_CHARS),
701        );
702        pb.finish();
703        Ok(())
704    }
705
706    /// Program `data` to `address`, automatically split into multiple page program operations.
707    ///
708    /// Note that this does *not* erase the flash beforehand; use `program()` for a higher-level
709    /// erase-program-verify interface.
710    ///
711    /// Calls `cb` with the number of bytes programmed so far after each
712    /// page programming operation.
713    pub fn program_data_cb<F: Fn(usize)>(
714        &mut self,
715        address: u32,
716        mut data: &[u8],
717        cb: F,
718    ) -> Result<()> {
719        let page_size = match self.page_size {
720            Some(page_size) => page_size,
721            None => {
722                log::info!("Page size not known. Using a default of 256 bytes.");
723                log::info!("Set a specific page size using `set_page_size()`.");
724                256
725            }
726        };
727
728        log::trace!(
729            "Programming data to 0x{:08X}, page size {} bytes",
730            address,
731            page_size
732        );
733
734        let mut total_bytes = 0;
735        cb(total_bytes);
736
737        // If the address is not page-aligned, we need to do a
738        // smaller-than-page-size initial program.
739        let first_write = page_size - ((address as usize) % page_size);
740        if first_write != page_size {
741            log::trace!("Programming partial first page of {} bytes", first_write);
742            self.page_program(address, &data[..first_write])?;
743            total_bytes += first_write;
744            data = &data[first_write..];
745            cb(total_bytes);
746        }
747
748        for page_data in data.chunks(page_size) {
749            self.page_program(address + total_bytes as u32, page_data)?;
750            total_bytes += page_data.len();
751            cb(total_bytes);
752        }
753
754        Ok(())
755    }
756
757    /// Send the WriteEnable command, setting the WEL in the status register.
758    pub fn write_enable(&mut self) -> Result<()> {
759        self.command(Command::WriteEnable)
760    }
761
762    /// Program up to one page of data.
763    ///
764    /// This method sets the write-enable latch and then waits for programming to complete,
765    /// including sleeping half the typical page program time if known before polling.
766    ///
767    /// Note that this does *not* erase the flash beforehand;
768    /// use `program()` for a higher-level erase-program-verify interface.
769    pub fn page_program(&mut self, address: u32, data: &[u8]) -> Result<()> {
770        let mut tx = self.make_address(address);
771        tx.extend(data);
772        self.write_enable()?;
773        self.exchange(Command::PageProgram, &tx, 0)?;
774        if let Some(params) = self.params {
775            if let Some(timing) = params.timing {
776                // Only bother sleeping if the expected programming time is greater than 1ms,
777                // otherwise we'll likely have waited long enough just due to round-trip delays.
778                // We always poll the status register at least once to check write completion.
779                if timing.page_prog_time_typ > Duration::from_millis(1) {
780                    self.access.delay(timing.page_prog_time_typ / 2);
781                }
782            }
783        }
784        self.wait_while_busy()?;
785        Ok(())
786    }
787
788    /// Reads the JEDEC manufacturer and long (16-bit) device IDs.
789    ///
790    /// The manufacturer ID may be prefixed with up to 13 of the
791    /// continuation code 0x7F; the number of continuation codes
792    /// is returned as the bank number.
793    ///
794    /// Returns (bank, manufacturer ID, device ID).
795    pub fn read_jedec_id(&mut self) -> Result<(u8, u8, u16)> {
796        // Attempt to read assuming a single-byte manufacturer ID.
797        let data = self.exchange(Command::ReadJEDECID, &[], 3)?;
798        if data[0] != 0x7F {
799            Ok((0, data[0], u16::from_be_bytes([data[1], data[2]])))
800        } else {
801            // If the first byte is continuation, read 16 bytes, to allow
802            // up to 13 continuation bytes, and then parse it to find the IDs.
803            let data = self.exchange(Command::ReadJEDECID, &[], 16)?;
804            for n in 1..=13 {
805                if data[n] != 0x7F {
806                    return Ok((
807                        n as u8,
808                        data[n],
809                        u16::from_be_bytes([data[n + 1], data[n + 2]]),
810                    ));
811                }
812            }
813            log::error!("Found more than 11 continuation bytes in manufacturer ID");
814            Err(Error::InvalidManufacturer)
815        }
816    }
817
818    /// Reads the JEDEC manufacturer and short (8-bit) device IDs.
819    ///
820    /// The manufacturer ID may be prefixed with up to 13 of the
821    /// continuation code 0x7F; the number of continuation codes
822    /// is returned as the bank number.
823    ///
824    /// Returns (bank, manufacturer ID, device ID).
825    pub fn read_device_id(&mut self) -> Result<(u8, u8, u8)> {
826        // Attempt to read assuming a single-byte manufacturer ID.
827        let data = self.exchange(Command::ReadDeviceID, &[0, 0, 0], 2)?;
828        if data[0] != 0x7F {
829            Ok((0, data[0], data[1]))
830        } else {
831            // If the first byte is continuation, read 15 bytes, to allow
832            // up to 13 continuation bytes, and then parse it to find the IDs.
833            let data = self.exchange(Command::ReadJEDECID, &[0, 0, 0], 15)?;
834            for n in 1..=13 {
835                if data[n] != 0x7F {
836                    return Ok((n as u8, data[n], data[n + 1]));
837                }
838            }
839            log::error!("Found more than 11 continuation bytes in manufacturer ID");
840            Err(Error::InvalidManufacturer)
841        }
842    }
843
844    /// Read the device's 64-bit unique ID, if present.
845    pub fn read_unique_id(&mut self) -> Result<u64> {
846        self.exchange(Command::ReadUniqueID, &[0, 0, 0, 0], 8)
847            .map(|data| u64::from_be_bytes(data.try_into().unwrap()))
848    }
849
850    /// Read status register 1.
851    pub fn read_status1(&mut self) -> Result<StatusRegister1> {
852        self.exchange(Command::ReadStatusRegister1, &[], 1)
853            .map(|data| StatusRegister1(data[0]))
854    }
855
856    /// Read status register 2.
857    ///
858    /// This status register is less widely supported and SFDP does
859    /// not indicate whether or not it is present.
860    pub fn read_status2(&mut self) -> Result<StatusRegister2> {
861        self.exchange(Command::ReadStatusRegister2, &[], 1)
862            .map(|data| StatusRegister2(data[0]))
863    }
864
865    /// Read status register 3.
866    ///
867    /// This status register is less widely supported and SFDP does
868    /// not indicate whether or not it is present.
869    pub fn read_status3(&mut self) -> Result<StatusRegister3> {
870        self.exchange(Command::ReadStatusRegister3, &[], 1)
871            .map(|data| StatusRegister3(data[0]))
872    }
873
874    /// Write status register 1.
875    ///
876    /// This method does *not* require you call `write_enable()` first.
877    ///
878    /// If the SFDP parameters indicate a specific command should be used
879    /// to enable writing to status register 1, that is used, otherwise the
880    /// default WriteEnable of 0x06 is used.
881    fn write_status1(&mut self, status1: StatusRegister1) -> Result<()> {
882        let we_opcode = if let Some(params) = self.params {
883            match params.status_1_vol {
884                Some(SFDPStatus1Volatility::NonVolatile06) => 0x06,
885                Some(SFDPStatus1Volatility::Volatile06) => 0x06,
886                Some(SFDPStatus1Volatility::Volatile50) => 0x50,
887                Some(SFDPStatus1Volatility::NonVolatile06Volatile50) => 0x06,
888                Some(SFDPStatus1Volatility::Mixed06) => 0x06,
889                _ => {
890                    if params.legacy_block_protect_volatile {
891                        params.legacy_volatile_write_en_inst
892                    } else {
893                        Command::WriteEnable.into()
894                    }
895                }
896            }
897        } else {
898            Command::WriteEnable.into()
899        };
900        self.command(we_opcode)?;
901        let s1 = self.read_status1()?;
902        log::debug!("Set WEL, s1 now: {:02X}", s1.0);
903        self.write(Command::WriteStatusRegister1, &[status1.0])
904    }
905
906    /// Write status register 2.
907    pub fn write_status2(&mut self, status2: StatusRegister2) -> Result<()> {
908        self.write_enable()?;
909        self.write(Command::WriteStatusRegister2, &[status2.0])
910    }
911
912    /// Write status register 3.
913    pub fn write_status3(&mut self, status3: StatusRegister3) -> Result<()> {
914        self.write_enable()?;
915        self.write(Command::WriteStatusRegister3, &[status3.0])
916    }
917
918    /// Check if the device is currently busy performing an operation.
919    ///
920    /// If the flash parameters indicate support for the Flag Status Register
921    /// instruction (0x70), it is used, otherwise legacy polling of status
922    /// register 1 is used.
923    pub fn is_busy(&mut self) -> Result<bool> {
924        // If we have read parameters and flag status polling is supported, use that.
925        // Bit 7 of FSR is 0=busy and 1=ready.
926        if let Some(params) = self.params {
927            if let Some(busy_poll_flag) = params.busy_poll_flag {
928                if busy_poll_flag {
929                    let fsr = self.exchange(Command::ReadFlagStatusRegister, &[], 1)?[0];
930                    return Ok(fsr & 0b1000_0000 == 0);
931                }
932            }
933        }
934
935        // Otherwise and by default, poll status register 1 instead.
936        self.read_status1().map(|status| status.get_busy())
937    }
938
939    /// Wait until the device stops being busy.
940    ///
941    /// This polls using `is_busy()`, which uses the flag status
942    /// register if available or otherwise uses status register 1.
943    pub fn wait_while_busy(&mut self) -> Result<()> {
944        while self.is_busy()? {}
945        Ok(())
946    }
947
948    /// Read SFDP register data.
949    ///
950    /// `addr` is always sent as a 24-bit address, regardless of the address_bytes setting.
951    pub fn read_sfdp(&mut self, addr: u32, len: usize) -> Result<Vec<u8>> {
952        let bytes = addr.to_be_bytes();
953        self.exchange(Command::ReadSFDPRegister, &bytes[1..], 1 + len)
954            .map(|data| data[1..].to_vec())
955    }
956
957    /// Writes `command` and `data` to the flash memory, then returns `nbytes` of response.
958    pub fn exchange<C: Into<u8>>(
959        &mut self,
960        command: C,
961        data: &[u8],
962        nbytes: usize,
963    ) -> Result<Vec<u8>> {
964        let mut tx = alloc::vec![command.into()];
965        tx.extend(data);
966        log::trace!("SPI exchange: write {:02X?}, read {} bytes", &tx, nbytes);
967        tx.extend(alloc::vec![0u8; nbytes]);
968        let rx = self.access.exchange(&tx)?;
969        log::trace!("SPI exchange: read {:02X?}", &rx[1 + data.len()..]);
970        Ok(rx[1 + data.len()..].to_vec())
971    }
972
973    /// Writes `command` and `data` to the flash memory, without reading the response.
974    pub fn write<C: Into<u8>>(&mut self, command: C, data: &[u8]) -> Result<()> {
975        let mut tx = alloc::vec![command.into()];
976        tx.extend(data);
977        log::trace!("SPI write: {:02X?}", &tx);
978        self.access.write(&tx)?;
979        Ok(())
980    }
981
982    /// Convenience method for issuing a single command and not caring about the returned data
983    pub fn command<C: Into<u8>>(&mut self, command: C) -> Result<()> {
984        self.write(command, &[])?;
985        Ok(())
986    }
987
988    /// Checks if `address` and `length` together are permissible:
989    /// * `address` must not exceed the current number of address bytes
990    /// * Both `address` and `address+length` must be within the flash memory bounds,
991    ///   if the capacity is known.
992    /// Returns either Err(Error::InvalidAddress) or Ok(()).
993    fn check_address_length(&self, address: u32, length: usize) -> Result<()> {
994        log::trace!("Checking address={:08X} length={}", address, length);
995        let start = address as usize;
996        let end = (address as usize) + length - 1;
997        let max_addr = 1 << (self.address_bytes * 8);
998
999        if (end & (max_addr - 1)) < start {
1000            log::error!("Operation would wrap");
1001            Err(Error::InvalidAddress {
1002                address: end as u32,
1003            })
1004        } else if end > max_addr {
1005            log::error!("Operation would exceed largest address");
1006            Err(Error::InvalidAddress {
1007                address: end as u32,
1008            })
1009        } else {
1010            match self.capacity {
1011                Some(capacity) if (end >= capacity) => {
1012                    log::error!("Operation would exceed flash capacity");
1013                    Err(Error::InvalidAddress {
1014                        address: end as u32,
1015                    })
1016                }
1017                _ => Ok(()),
1018            }
1019        }
1020    }
1021
1022    /// Generate a 1-, 2-, 3-, or 4-byte address, depending on current `address_bytes` setting.
1023    ///
1024    /// Panics if address_bytes is not 1-, 2, 3, or 4.
1025    fn make_address(&self, addr: u32) -> Vec<u8> {
1026        let bytes = addr.to_be_bytes();
1027        bytes[(4 - self.address_bytes as usize)..].to_vec()
1028    }
1029
1030    /// Work out what combination of erase operations to run to efficiently
1031    /// erase the specified memory.
1032    fn make_erase_plan(&self, address: u32, length: usize) -> Result<ErasePlan> {
1033        log::debug!(
1034            "Creating erase plan for address={} length={}",
1035            address,
1036            length
1037        );
1038        // Erase instructions: (size in bytes, opcode).
1039        let mut insts = Vec::new();
1040
1041        // Find available erase instructions.
1042        if let Some(params) = self.params {
1043            if params.erase_insts.iter().any(|&inst| inst.is_some()) {
1044                log::trace!("Using SFDP erase instructions.");
1045                for inst in params.erase_insts.iter().flatten() {
1046                    insts.push((inst.size as usize, inst.opcode, inst.time_typ));
1047                }
1048            } else if params.legacy_4kb_erase_supported {
1049                log::trace!("No erase instructions in SFDP, using legacy 4kB erase.");
1050                insts.push((4096, params.legacy_4kb_erase_inst, None));
1051            } else {
1052                log::trace!("SFDP indicates no erase instructions available.");
1053            }
1054        }
1055        if insts.is_empty() {
1056            if let Some(erase_size) = self.erase_size {
1057                log::trace!("No SFDP erase instructions found, using `erase_size` parameter.");
1058                insts.push((erase_size, self.erase_opcode, None));
1059            } else {
1060                log::warn!("No erase instructions could be found.");
1061                log::warn!("Try setting one manually using `Flash::set_erase_size()`.");
1062                return Err(Error::NoEraseInstruction);
1063            }
1064        }
1065        insts.sort();
1066
1067        // Create plan given the list of available erase instructions.
1068        Ok(ErasePlan::new(&insts, address as usize, length))
1069    }
1070
1071    /// Read all the bytes before `address` in memory which will be erased by `plan`.
1072    fn read_erase_preamble(&mut self, address: u32, plan: &ErasePlan) -> Result<Vec<u8>> {
1073        let base = plan.0[0].2;
1074        let len = address - base;
1075        if len > 0 {
1076            log::debug!("Reading erase preamble: base={} len={}", base, len);
1077            self.read(base, len as usize)
1078        } else {
1079            Ok(Vec::new())
1080        }
1081    }
1082
1083    /// Read all the bytes after `address + length` in memory which will be erased by `plan`.
1084    ///
1085    /// If all those bytes are 0xFF, returns an empty Vec instead, as they won't be changed
1086    /// by the erase operation.
1087    fn read_erase_postamble(
1088        &mut self,
1089        address: u32,
1090        length: usize,
1091        plan: &ErasePlan,
1092    ) -> Result<Vec<u8>> {
1093        let (_, size, base, _) = plan.0.last().unwrap();
1094        let start = address + (length as u32);
1095        let len = (*base as usize + *size) - start as usize;
1096        if len > 0 {
1097            log::debug!("Reading erase postamble: addr={} len={}", start, len);
1098            let data = self.read(start, len)?;
1099            // If all the postamble is already 0xFF, there's no point reprogramming it.
1100            if data.iter().all(|x| *x == 0xFF) {
1101                Ok(Vec::new())
1102            } else {
1103                Ok(data)
1104            }
1105        } else {
1106            Ok(Vec::new())
1107        }
1108    }
1109
1110    /// Extend `data` by adding any preamble and postamble required to preserve
1111    /// existing data after erasing and reprogramming.
1112    fn make_restore_data(
1113        &mut self,
1114        address: u32,
1115        data: &[u8],
1116        erase_plan: &ErasePlan,
1117    ) -> Result<Vec<u8>> {
1118        let preamble = self.read_erase_preamble(address, &erase_plan)?;
1119        let postamble = self.read_erase_postamble(address, data.len(), &erase_plan)?;
1120        let mut full_data = preamble;
1121        full_data.extend(data);
1122        full_data.extend(&postamble);
1123        Ok(full_data)
1124    }
1125
1126    /// Execute the sequence of erase operations from `plan`.
1127    ///
1128    /// `cb` is called with the number of bytes erased so far.
1129    fn run_erase_plan<F: Fn(usize)>(&mut self, plan: &ErasePlan, cb: F) -> Result<()> {
1130        let mut total_erased = 0;
1131        cb(total_erased);
1132        for (opcode, size, base, duration) in plan.0.iter() {
1133            log::trace!(
1134                "Executing erase plan: Erase 0x{:02X} ({} bytes) from 0x{:08X}",
1135                opcode,
1136                size,
1137                base
1138            );
1139            let addr = self.make_address(*base);
1140            self.write_enable()?;
1141            self.write(*opcode, &addr)?;
1142            if let Some(duration) = duration {
1143                self.access.delay(*duration / 2);
1144            }
1145            self.wait_while_busy()?;
1146            total_erased += size;
1147            cb(total_erased);
1148        }
1149        cb(total_erased);
1150        Ok(())
1151    }
1152
1153    /// Execute the sequence of erase operations from `plan`, and draw a progress bar
1154    /// to the terminal.
1155    #[cfg(feature = "std")]
1156    fn run_erase_plan_progress(&mut self, plan: &ErasePlan) -> Result<()> {
1157        let erase_size = plan.total_size() as u64;
1158        let pb = ProgressBar::new(erase_size).with_style(
1159            ProgressStyle::with_template(Self::DATA_PROGRESS_TPL)
1160                .unwrap()
1161                .progress_chars(Self::DATA_PROGRESS_CHARS),
1162        );
1163        pb.set_message("Erasing");
1164        self.run_erase_plan(&plan, |n| pb.set_position(n as u64))?;
1165        pb.set_style(
1166            ProgressStyle::with_template(Self::DATA_FINISHED_TPL)
1167                .unwrap()
1168                .progress_chars(Self::DATA_PROGRESS_CHARS),
1169        );
1170        pb.finish();
1171        Ok(())
1172    }
1173
1174    /// Verify programmed data matches new flash contents.
1175    ///
1176    /// Returns Err::ReadbackError on mismatch.
1177    fn verify_readback(&mut self, address: u32, data: &[u8], new_data: &[u8]) -> Result<()> {
1178        let mismatch = data
1179            .iter()
1180            .zip(new_data)
1181            .enumerate()
1182            .find(|(_, (a, b))| a != b);
1183        match mismatch {
1184            Some((idx, (a, b))) => {
1185                let addr = address + idx as u32;
1186                log::error!(
1187                    "Readback mismatch at 0x{:08X}: Wrote 0x{:02X}, read 0x{:02X}",
1188                    addr,
1189                    a,
1190                    b
1191                );
1192                if self.is_protected()? {
1193                    log::error!("Flash write protection appears to be enabled, try unprotecting.");
1194                }
1195                Err(Error::ReadbackError {
1196                    address: addr,
1197                    wrote: *a,
1198                    read: *b,
1199                })
1200            }
1201            None => Ok(()),
1202        }
1203    }
1204}
1205
1206/// Standard SPI flash command opcodes.
1207///
1208/// These are taken from the Winbond W25Q16JV datasheet, but most are
1209/// widely applicable. If SFDP is supported, it is used to discover
1210/// the relevant erase opcodes and sizes.
1211///
1212/// Only single I/O commands are listed.
1213#[derive(Copy, Clone, Debug, num_enum::IntoPrimitive)]
1214#[allow(unused)]
1215#[repr(u8)]
1216enum Command {
1217    // Core instruction set.
1218    // These commands are almost universally available.
1219    WriteEnable = 0x06,
1220    WriteDisable = 0x04,
1221    ReadData = 0x03,
1222    PageProgram = 0x02,
1223    ReadStatusRegister1 = 0x05,
1224    WriteStatusRegister1 = 0x01,
1225
1226    // Standard instruction set.
1227    // These commands are typically available.
1228    ReadJEDECID = 0x9F,
1229    FastRead = 0x0B,
1230    Powerdown = 0xB9,
1231    ReleasePowerdown = 0xAB,
1232    ReadDeviceID = 0x90,
1233    ChipErase = 0xC7,
1234
1235    // Extended instruction set.
1236    // These commands may be available.
1237    ReadUniqueID = 0x4B,
1238    ReadSFDPRegister = 0x5A,
1239    ReadStatusRegister2 = 0x35,
1240    ReadStatusRegister3 = 0x15,
1241    ReadFlagStatusRegister = 0x70,
1242    WriteStatusRegister2 = 0x31,
1243    WriteStatusRegister3 = 0x11,
1244    WriteEnableVolatile = 0x50,
1245    EnableReset = 0x66,
1246    Reset = 0x99,
1247    ProgramSuspend = 0x75,
1248    ProgramResume = 0x7A,
1249
1250    // Erase instructions.
1251    // The size affected by each erase operation can vary.
1252    // Typical sizes are 4kB for sector erase, 32kB for block erase 1,
1253    // and 64kB for block erase 2.
1254    SectorErase = 0x20,
1255    BlockErase1 = 0x52,
1256    BlockErase2 = 0xD8,
1257
1258    // Security/lock related instructions.
1259    EraseSecurityRegisters = 0x44,
1260    ProgramSecurityRegisters = 0x42,
1261    ReadSecurityRegisters = 0x48,
1262    IndividualBlockLock = 0x36,
1263    IndividualBlockUnlock = 0x39,
1264    ReadBlockLock = 0x3D,
1265    GlobalBlockLock = 0x7E,
1266    GlobalBlockUnlock = 0x98,
1267}