spi_memory_async/
series25.rs

1//! Driver for 25-series SPI Flash and EEPROM chips.
2
3use crate::{utils::HexSlice, Error};
4use bitflags::bitflags;
5use core::fmt;
6use core::marker::PhantomData;
7pub use core::task::Poll;
8pub use embedded_hal_async::{
9    delay::DelayNs,
10    spi::{Operation, SpiDevice},
11};
12pub use embedded_storage_async;
13
14#[derive(defmt::Format)]
15/// 3-Byte JEDEC manufacturer and device identification.
16pub struct Identification {
17    /// Data collected
18    /// - First byte is the manufacturer's ID code from eg JEDEC Publication No. 106AJ
19    /// - The trailing bytes are a manufacturer-specific device ID.
20    bytes: [u8; 3],
21
22    /// The number of continuations that precede the main manufacturer ID
23    continuations: u8,
24}
25
26impl Identification {
27    /// Build an Identification from JEDEC ID bytes.
28    pub fn from_jedec_id(buf: &[u8]) -> Identification {
29        // Example response for Cypress part FM25V02A:
30        // 7F 7F 7F 7F 7F 7F C2 22 08  (9 bytes)
31        // 0x7F is a "continuation code", not part of the core manufacturer ID
32        // 0xC2 is the company identifier for Cypress (Ramtron)
33
34        // Find the end of the continuation bytes (0x7F)
35        let mut start_idx = 0;
36        for (i, item) in buf.iter().enumerate().take(buf.len() - 2) {
37            if *item != 0x7F {
38                start_idx = i;
39                break;
40            }
41        }
42
43        Self {
44            bytes: [buf[start_idx], buf[start_idx + 1], buf[start_idx + 2]],
45            continuations: start_idx as u8,
46        }
47    }
48
49    /// The JEDEC manufacturer code for this chip.
50    pub fn mfr_code(&self) -> u8 {
51        self.bytes[0]
52    }
53
54    /// The manufacturer-specific device ID for this chip.
55    pub fn device_id(&self) -> &[u8] {
56        self.bytes[1..].as_ref()
57    }
58
59    /// Number of continuation codes in this chip ID.
60    ///
61    /// For example the ARM Ltd identifier is `7F 7F 7F 7F 3B` (5 bytes), so
62    /// the continuation count is 4.
63    pub fn continuation_count(&self) -> u8 {
64        self.continuations
65    }
66}
67
68impl fmt::Debug for Identification {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        f.debug_tuple("Identification")
71            .field(&HexSlice(self.bytes))
72            .finish()
73    }
74}
75
76#[allow(unused)] // TODO support more features
77enum Opcode {
78    /// Read the 8-bit legacy device ID.
79    ReadDeviceId = 0xAB,
80    /// Read the 8-bit manufacturer and device IDs.
81    ReadMfDId = 0x90,
82    /// Read 16-bit manufacturer ID and 8-bit device ID.
83    ReadJedecId = 0x9F,
84    /// Set the write enable latch.
85    WriteEnable = 0x06,
86    /// Clear the write enable latch.
87    WriteDisable = 0x04,
88    /// Read the 8-bit status register.
89    ReadStatus = 0x05,
90    /// Write the 8-bit status register. Not all bits are writeable.
91    WriteStatus = 0x01,
92    Read = 0x03,
93    PageProg = 0x02, // directly writes to EEPROMs too
94    SectorErase = 0x20,
95    BlockErase = 0xD8,
96    ChipErase = 0xC7,
97}
98
99bitflags! {
100    /// Status register bits.
101    pub struct Status: u8 {
102        /// Erase or write in progress.
103        const BUSY = 1 << 0;
104        /// Status of the **W**rite **E**nable **L**atch.
105        const WEL = 1 << 1;
106        /// The 3 protection region bits.
107        const PROT = 0b00011100;
108        /// **S**tatus **R**egister **W**rite **D**isable bit.
109        const SRWD = 1 << 7;
110    }
111}
112
113/// Trait for defining the size of a flash.
114pub trait FlashParameters {
115    /// The page write size in bytes.
116    const PAGE_SIZE: usize;
117    /// The sector erase size in bytes.
118    const SECTOR_SIZE: usize;
119    /// The block erase size in bytes.
120    const BLOCK_SIZE: usize;
121    /// The total chip size in bytes.
122    const CHIP_SIZE: usize;
123}
124
125/// Driver for 25-series SPI Flash chips.
126///
127/// # Type Parameters
128///
129/// * **`SPI`**: The SPI master to which the flash chip is attached.
130/// * **`FlashParams`**: Memory size.
131/// * **`Delay`**: Delay provider.
132#[derive(Debug, defmt::Format)]
133pub struct Flash<SPI, FlashParams, Delay> {
134    spi: SPI,
135    delay: Delay,
136    poll_delay_us: u32,
137    params: PhantomData<FlashParams>,
138}
139
140impl<SPI, FlashParams, Delay> FlashParameters for Flash<SPI, FlashParams, Delay>
141where
142    FlashParams: FlashParameters,
143{
144    const PAGE_SIZE: usize = FlashParams::PAGE_SIZE;
145    const SECTOR_SIZE: usize = FlashParams::SECTOR_SIZE;
146    const BLOCK_SIZE: usize = FlashParams::BLOCK_SIZE;
147    const CHIP_SIZE: usize = FlashParams::CHIP_SIZE;
148}
149
150impl<SPI, FlashParams, Delay> Flash<SPI, FlashParams, Delay>
151where
152    SPI: SpiDevice<u8>,
153    Delay: DelayNs,
154    FlashParams: FlashParameters,
155{
156    /// Creates a new 26-series flash driver.
157    ///
158    /// # Parameters
159    ///
160    /// * **`spi`**: An SPI master. Must be configured to operate in the correct
161    ///   mode for the device.
162    /// * **`delay`**: A [`DelayNs`] implementation.
163    /// * **`poll_delay_us`**: The delay between polling the chip when waiting for an operation to complete.
164    pub async fn init(
165        spi: SPI,
166        delay: Delay,
167        poll_delay_us: u32,
168        _params: FlashParams,
169    ) -> Result<Self, Error<SPI>> {
170        let mut this = Flash {
171            spi,
172            delay,
173            poll_delay_us,
174            params: PhantomData,
175        };
176
177        // If the MCU is reset and an old operation is still ongoing, wait for it to finish.
178        this.wait_done().await?;
179
180        Ok(this)
181    }
182
183    /// Get the size of a page which can be written.
184    pub const fn page_write_size(&self) -> usize {
185        FlashParams::PAGE_SIZE
186    }
187
188    /// Get the size of a sector which can be erased.
189    pub const fn sector_erase_size(&self) -> usize {
190        FlashParams::SECTOR_SIZE
191    }
192
193    /// Get the size of a block which can be erased.
194    pub const fn block_erase_size(&self) -> usize {
195        FlashParams::BLOCK_SIZE
196    }
197
198    /// Get the size of the flash chip.
199    pub const fn chip_size(&self) -> usize {
200        FlashParams::CHIP_SIZE
201    }
202
203    async fn command_transfer(&mut self, bytes: &mut [u8]) -> Result<(), Error<SPI>> {
204        self.spi.transfer_in_place(bytes).await.map_err(Error::Spi)
205    }
206
207    async fn command_write(&mut self, bytes: &[u8]) -> Result<(), Error<SPI>> {
208        self.spi.write(bytes).await.map_err(Error::Spi)
209    }
210
211    /// Reads the JEDEC manufacturer/device identification.
212    pub async fn read_jedec_id(&mut self) -> Result<Identification, Error<SPI>> {
213        // Optimistically read 12 bytes, even though some identifiers will be shorter
214        let mut buf: [u8; 12] = [0; 12];
215        buf[0] = Opcode::ReadJedecId as u8;
216        self.command_transfer(&mut buf).await?;
217
218        // Skip buf[0] (SPI read response byte)
219        Ok(Identification::from_jedec_id(&buf[1..]))
220    }
221
222    /// Reads the status register.
223    pub async fn read_status(&mut self) -> Result<Status, Error<SPI>> {
224        let mut buf = [Opcode::ReadStatus as u8, 0];
225        self.command_transfer(&mut buf).await?;
226
227        Ok(Status::from_bits_truncate(buf[1]))
228    }
229
230    async fn write_enable(&mut self) -> Result<(), Error<SPI>> {
231        let cmd_buf = [Opcode::WriteEnable as u8];
232        self.command_write(&cmd_buf).await
233    }
234
235    pub async fn wait_done(&mut self) -> Result<(), Error<SPI>> {
236        while self.read_status().await?.contains(Status::BUSY) {
237            self.delay.delay_us(self.poll_delay_us).await;
238        }
239        Ok(())
240    }
241
242    /// Reads flash contents into `buf`, starting at `addr`.
243    ///
244    /// Note that `addr` is not fully decoded: Flash chips will typically only
245    /// look at the lowest `N` bits needed to encode their size, which means
246    /// that the contents are "mirrored" to addresses that are a multiple of the
247    /// flash size. Only 24 bits of `addr` are transferred to the device in any
248    /// case, limiting the maximum size of 25-series SPI flash chips to 16 MiB.
249    ///
250    /// # Parameters
251    ///
252    /// * `addr`: 24-bit address to start reading at.
253    /// * `buf`: Destination buffer to fill.
254    pub async fn read(&mut self, addr: u32, buf: &mut [u8]) -> Result<(), Error<SPI>> {
255        // TODO what happens if `buf` is empty?
256
257        let cmd_buf = [
258            Opcode::Read as u8,
259            (addr >> 16) as u8,
260            (addr >> 8) as u8,
261            addr as u8,
262        ];
263
264        self.spi
265            .transaction(&mut [Operation::Write(&cmd_buf), Operation::Read(buf)])
266            .await
267            .map_err(Error::Spi)
268    }
269
270    /// Erases a sector from the memory chip.
271    ///
272    /// # Parameters
273    /// * `addr`: The address to start erasing at. If the address is not on a sector boundary,
274    ///   the lower bits can be ignored in order to make it fit.
275    pub async fn erase_sector(&mut self, addr: u32) -> Result<(), Error<SPI>> {
276        self.write_enable().await?;
277
278        let cmd_buf = [
279            Opcode::SectorErase as u8,
280            (addr >> 16) as u8,
281            (addr >> 8) as u8,
282            addr as u8,
283        ];
284        self.command_write(&cmd_buf).await?;
285        self.wait_done().await
286    }
287
288    /// Erases a block from the memory chip.
289    ///
290    /// # Parameters
291    /// * `addr`: The address to start erasing at. If the address is not on a block boundary,
292    ///   the lower bits can be ignored in order to make it fit.
293    pub async fn erase_block(&mut self, addr: u32) -> Result<(), Error<SPI>> {
294        self.write_enable().await?;
295
296        let cmd_buf = [
297            Opcode::BlockErase as u8,
298            (addr >> 16) as u8,
299            (addr >> 8) as u8,
300            addr as u8,
301        ];
302        self.command_write(&cmd_buf).await?;
303        self.wait_done().await
304    }
305
306    /// Writes bytes onto the memory chip. This method is supposed to assume that the sectors
307    /// it is writing to have already been erased and should not do any erasing themselves.
308    ///
309    /// # Parameters
310    /// * `addr`: The address to write to.
311    /// * `data`: The bytes to write to `addr`.
312    pub async fn write_bytes(&mut self, mut addr: u32, mut data: &[u8]) -> Result<(), Error<SPI>> {
313        while !data.is_empty() {
314            // The flash can only to page aligned writes, chunk data to correct format.
315            let page_offset = addr as usize % Self::PAGE_SIZE;
316            let len = (Self::PAGE_SIZE - page_offset)
317                .min(Self::PAGE_SIZE)
318                .min(data.len());
319            let (write_data, rest) = data.split_at(len);
320
321            self.write_enable().await?;
322
323            let cmd_buf = [
324                Opcode::PageProg as u8,
325                (addr >> 16) as u8,
326                (addr >> 8) as u8,
327                addr as u8,
328            ];
329            self.spi
330                .transaction(&mut [Operation::Write(&cmd_buf), Operation::Write(write_data)])
331                .await
332                .map_err(Error::Spi)?;
333
334            self.wait_done().await?;
335
336            addr += len as u32;
337            data = rest;
338        }
339
340        Ok(())
341    }
342
343    /// Erases the memory chip fully.
344    ///
345    /// Warning: Full erase operations can take a significant amount of time.
346    /// Check your device's datasheet for precise numbers.
347    pub async fn erase_all(&mut self) -> Result<(), Error<SPI>> {
348        self.write_enable().await?;
349        let cmd_buf = [Opcode::ChipErase as u8];
350        self.command_write(&cmd_buf).await?;
351        self.wait_done().await
352    }
353
354    /// Erases a range of sectors. The range is expressed in bytes. These bytes need to be a multiple of SECTOR_SIZE.
355    /// If the range starts at SECTOR_SIZE * 3 then the erase starts at the fourth sector.
356    /// All sectors are erased in the range [start_sector..end_sector].
357    /// The start address may not be a higher value than the end address.
358    ///
359    /// # Arguments
360    /// * `start_address` - Address of the first byte of the start of the range of sectors that need to be erased.
361    /// * `end_address` - Address of the first byte of the end of the range of sectors that need to be erased.
362    pub async fn erase_range(
363        &mut self,
364        start_address: u32,
365        end_address: u32,
366    ) -> Result<(), Error<SPI>> {
367        self.write_enable().await?;
368        let sector_size: u32 = FlashParams::SECTOR_SIZE as u32;
369
370        if start_address % sector_size != 0 {
371            return Err(Error::NotAligned);
372        }
373
374        if end_address % sector_size != 0 {
375            return Err(Error::NotAligned);
376        }
377
378        if start_address > end_address {
379            return Err(Error::OutOfBounds);
380        }
381
382        let start_sector = start_address / sector_size;
383        let end_sector = end_address / sector_size;
384
385        for sector in start_sector..end_sector {
386            self.erase_sector(sector * sector_size).await.unwrap();
387        }
388
389        Ok(())
390    }
391}
392
393impl<SPI, FlashParams, Delay> embedded_storage::nor_flash::ErrorType
394    for Flash<SPI, FlashParams, Delay>
395where
396    SPI: SpiDevice<u8>,
397{
398    type Error = Error<SPI>;
399}
400
401impl<SPI, FlashParams, Delay> embedded_storage_async::nor_flash::ReadNorFlash
402    for Flash<SPI, FlashParams, Delay>
403where
404    SPI: SpiDevice<u8>,
405    Delay: DelayNs,
406    FlashParams: FlashParameters,
407{
408    const READ_SIZE: usize = 1;
409
410    async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
411        self.read(offset, bytes).await
412    }
413
414    fn capacity(&self) -> usize {
415        FlashParams::CHIP_SIZE
416    }
417}
418
419impl<SPI, FlashParams, Delay> embedded_storage_async::nor_flash::NorFlash
420    for Flash<SPI, FlashParams, Delay>
421where
422    SPI: SpiDevice<u8>,
423    Delay: DelayNs,
424    FlashParams: FlashParameters,
425{
426    const WRITE_SIZE: usize = 1;
427
428    const ERASE_SIZE: usize = FlashParams::SECTOR_SIZE;
429
430    async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
431        self.erase_range(from, to).await
432    }
433
434    async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
435        self.write_bytes(offset, bytes).await
436    }
437}
438
439#[cfg(test)]
440mod tests {
441    use super::*;
442
443    #[test]
444    fn test_decode_jedec_id() {
445        let cypress_id_bytes = [0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xC2, 0x22, 0x08];
446        let ident = Identification::from_jedec_id(&cypress_id_bytes);
447        assert_eq!(0xC2, ident.mfr_code());
448        assert_eq!(6, ident.continuation_count());
449        let device_id = ident.device_id();
450        assert_eq!(device_id[0], 0x22);
451        assert_eq!(device_id[1], 0x08);
452    }
453}