Skip to main content

mx25v/
blocking.rs

1use crate::{
2    _512K, _1M, _2M, _4M, _8M, _16M, 
3    BLOCK32_SIZE, BLOCK64_SIZE, SECTOR_SIZE, 
4    command::Command, 
5    error::Error, 
6    register::*,
7};
8use bit::BitIndex;
9use embedded_hal::spi::Operation;
10use embedded_hal::spi::SpiDevice;
11
12/// Type alias for the MX25V512 subfamily
13pub type MX25V512<SPI>  = MX25V<_512K, false, SPI>;
14/// Type alias for the MX25V5126 subfamily
15pub type MX25V5126<SPI> = MX25V<_512K, false, SPI>;
16/// Type alias for the MX25V512F subfamily
17pub type MX25V512F<SPI> = MX25V<_512K, true, SPI>;
18
19/// Type alias for the MX25V1006 subfamily
20pub type MX25V1006<SPI> = MX25V<_1M, false, SPI>;
21/// Type alias for the MX25V1035 subfamily
22pub type MX25V1035<SPI> = MX25V<_1M, true, SPI>;
23
24/// Type alias for the MX25V2006 subfamily
25pub type MX25V2006<SPI> = MX25V<_2M, false, SPI>;
26/// Type alias for the MX25V2035 subfamily
27pub type MX25V2035<SPI> = MX25V<_2M, true, SPI>;
28
29/// Type alias for the MX25V4006 subfamily
30pub type MX25V4006<SPI> = MX25V<_4M, false, SPI>;
31/// Type alias for the MX25V4035 subfamily
32pub type MX25V4035<SPI> = MX25V<_4M, true, SPI>;
33
34/// Type alias for the MX25V8006 subfamily
35pub type MX25V8006<SPI> = MX25V<_8M, false, SPI>;
36/// Type alias for the MX25V8035 subfamily
37pub type MX25V8035<SPI> = MX25V<_8M, true, SPI>;
38
39/// Type alias for the MX25V1606 subfamily
40pub type MX25V1606<SPI> = MX25V<_16M, false, SPI>;
41/// Type alias for the MX25V1635 subfamily
42pub type MX25V1635<SPI> = MX25V<_16M, true, SPI>;
43
44/// The generic low level MX25R driver
45pub struct MX25V<const SIZE: u32, const QUAD: bool, SPI: SpiDevice> {
46    spi: SPI,
47}
48
49impl<const SIZE: u32, const QUAD: bool, SPI, E> MX25V<SIZE, QUAD, SPI>
50where
51    SPI: SpiDevice<Error = E>,
52{
53    pub const CAPACITY: u32 = SIZE + 1;
54
55    pub fn new(spi: SPI) -> Self {
56        Self { spi }
57    }
58
59    /// Read the wip bit, just less noisy than the `read_status().unwrap().wip_bit`
60    pub fn poll_wip(&mut self) -> Result<(), Error<E>> {
61        if self.read_status()?.wip_bit {
62            return Err(Error::Busy);
63        }
64        Ok(())
65    }
66
67    pub fn wait_wip(&mut self) -> Result<(), Error<E>> {
68        loop {
69            let res = self.poll_wip();
70            match res {
71                Ok(()) => return Ok(()),
72                Err(Error::Busy) => continue,
73                err @ Err(_) => return err,
74            }
75        }
76    }
77
78    pub fn verify_addr(addr: u32) -> Result<u32, Error<E>> {
79        if addr > SIZE {
80            return Err(Error::OutOfBounds);
81        }
82        Ok(addr)
83    }
84
85    fn command_write(&mut self, bytes: &[u8]) -> Result<(), Error<E>> {
86        self.spi.write(bytes).map_err(Error::Spi)
87    }
88    fn command_transfer(&mut self, bytes: &mut [u8]) -> Result<(), Error<E>> {
89        self.spi.transfer_in_place(bytes).map_err(Error::Spi)
90    }
91
92    fn addr_command(&mut self, addr: u32, cmd: Command) -> Result<(), Error<E>> {
93        let addr_val = Self::verify_addr(addr)?;
94        let cmd: [u8; 4] = [
95            cmd as u8,
96            (addr_val >> 16) as u8,
97            (addr_val >> 8) as u8,
98            addr_val as u8,
99        ];
100        self.spi.write(&cmd).map_err(Error::Spi)
101    }
102
103    fn write_read_base(&mut self, write: &[u8], read: &mut [u8]) -> Result<(), Error<E>> {
104        self.spi
105            .transaction(&mut [Operation::Write(write), Operation::Read(read)])
106            .map_err(Error::Spi)
107    }
108
109    fn read_base(&mut self, addr: u32, cmd: Command, buff: &mut [u8]) -> Result<(), Error<E>> {
110        self.wait_wip()?;
111        let addr_val = Self::verify_addr(addr)?;
112        let cmd: [u8; 4] = [
113            cmd as u8,
114            (addr_val >> 16) as u8,
115            (addr_val >> 8) as u8,
116            addr_val as u8,
117        ];
118
119        let res = self.write_read_base(&cmd, buff);
120        #[cfg(feature = "defmt")]
121        if res.is_ok() {
122            defmt::trace!("Read from {=u32}, {=usize}: {:?}", addr, buff.len(), buff);
123        } else {
124            defmt::trace!("Failed to read");
125        }
126        res
127    }
128
129    fn read_base_dummy(
130        &mut self,
131        addr: u32,
132        cmd: Command,
133        buff: &mut [u8],
134    ) -> Result<(), Error<E>> {
135        let addr_val = Self::verify_addr(addr)?;
136        self.wait_wip()?;
137
138        let cmd: [u8; 5] = [
139            cmd as u8,
140            (addr_val >> 16) as u8,
141            (addr_val >> 8) as u8,
142            addr_val as u8,
143            Command::Dummy as u8,
144        ];
145        let res = self.write_read_base(&cmd, buff);
146        #[cfg(feature = "defmt")]
147        if res.is_ok() {
148            defmt::trace!("Read from {=u32}, {=usize}: {:?}", addr, buff.len(), buff);
149        } else {
150            defmt::trace!("Failed to read");
151        }
152        res
153    }
154
155    fn write_base(&mut self, addr: u32, cmd: Command, buff: &[u8]) -> Result<(), Error<E>> {
156        let addr_val: u32 = Self::verify_addr(addr)?;
157        let cmd: [u8; 4] = [
158            cmd as u8,
159            (addr_val >> 16) as u8,
160            (addr_val >> 8) as u8,
161            addr_val as u8,
162        ];
163
164        let res = self
165            .spi
166            .transaction(&mut [Operation::Write(&cmd), Operation::Write(buff)])
167            .map_err(Error::Spi);
168
169        #[cfg(feature = "defmt")]
170        if res.is_ok() {
171            defmt::trace!("write from {=u32}, {=usize}: {:?}", addr, buff.len(), buff);
172        } else {
173            defmt::trace!("Failed to write");
174        }
175        res
176    }
177
178    fn prepare_write(&mut self) -> Result<(), Error<E>> {
179        self.wait_wip()?;
180        self.write_enable()
181    }
182
183    /// Read n bytes from an addresss. 
184    /// 
185    /// See also: [`Self::read_fast`], which allows for a higher maximum SPI clock speed but adds a dummy byte.
186    pub fn read(&mut self, addr: u32, buff: &mut [u8]) -> Result<(), Error<E>> {
187        self.read_base(addr, Command::Read, buff)
188    }
189
190    /// Read n bytes from an address.
191    /// 
192    /// See also: [`Self::read`], which has a more limited maximum SPI frequency but doesn't send a dummy byte.
193    pub fn read_fast(&mut self, addr: u32, buff: &mut [u8]) -> Result<(), Error<E>> {
194        self.read_base_dummy(addr, Command::ReadF, buff)
195    }
196
197    /// Write n bytes to a page. This method can only clear bits to '0', if any bits need to be set to '1' the region must be erased.
198    pub fn write_page(&mut self, addr: u32, buff: &[u8]) -> Result<(), Error<E>> {
199        self.prepare_write()?;
200        self.write_base(addr, Command::ProgramPage, buff)
201    }
202
203    /// Erase a 4kB sector, setting all bits to '1'.
204    pub fn erase_sector(&mut self, addr: u32) -> Result<(), Error<E>> {
205        if !addr.is_multiple_of(SECTOR_SIZE) {
206            return Err(Error::NotAligned);
207        }
208        self.prepare_write()?;
209        self.addr_command(addr, Command::SectorErase)?;
210        #[cfg(feature = "defmt")]
211        defmt::trace!("Erase sector {:?}", addr);
212        Ok(())
213    }
214
215    /// Erase a 64kB block, setting all bits to '1'.
216    pub fn erase_block64(&mut self, addr: u32) -> Result<(), Error<E>> {
217        if !addr.is_multiple_of(BLOCK64_SIZE) {
218            return Err(Error::NotAligned);
219        }
220        self.prepare_write()?;
221        self.addr_command(addr, Command::BlockErase)?;
222        #[cfg(feature = "defmt")]
223        defmt::trace!("Erase block 64 {:?}", addr);
224        Ok(())
225    }
226
227    /// Erase a 32kB block, setting all bits to '1'.
228    pub fn erase_block32(&mut self, addr: u32) -> Result<(), Error<E>> {
229        if !addr.is_multiple_of(BLOCK32_SIZE) {
230            return Err(Error::NotAligned);
231        }
232        self.prepare_write()?;
233        self.addr_command(addr, Command::BlockErase32)?;
234        #[cfg(feature = "defmt")]
235        defmt::trace!("Erase block 32 {:?}", addr);
236        Ok(())
237    }
238
239    /// Erase the whole chip, setting all bits to '1'.
240    pub fn erase_chip(&mut self) -> Result<(), Error<E>> {
241        self.prepare_write()?;
242        self.command_write(&[Command::ChipErase as u8])?;
243        #[cfg(feature = "defmt")]
244        defmt::trace!("Erase chip");
245        Ok(())
246    }
247
248    /// Read using the Serial Flash Discoverable Parameter instruction
249    pub fn read_sfdp(&mut self, addr: u32, buff: &mut [u8]) -> Result<(), Error<E>> {
250        self.read_base_dummy(addr, Command::ReadSfdp, buff)
251    }
252
253    /// Enable write operation, though you shouldn't need this function since it's already handled in the write/erase operations.
254    fn write_enable(&mut self) -> Result<(), Error<E>> {
255        self.command_write(&[Command::WriteEnable as u8])
256    }
257
258    /// Disable write
259    pub fn write_disable(&mut self) -> Result<(), Error<E>> {
260        self.command_write(&[Command::WriteDisable as u8])
261    }
262
263    /// Read the status register
264    pub fn read_status(&mut self) -> Result<StatusRegister, Error<E>> {
265        let mut command: [u8; 2] = [Command::ReadStatus as u8, 0];
266
267        self.command_transfer(&mut command)?;
268        Ok(command[1].into())
269    }
270    
271    /// Suspend the pogram erase
272    pub fn suspend_program_erase(&mut self) -> Result<(), Error<E>> {
273        self.command_write(&[Command::ProgramEraseSuspend as u8])
274    }
275
276    /// Resume program erase
277    pub fn resume_program_erase(&mut self) -> Result<(), Error<E>> {
278        self.command_write(&[Command::ProgramEraseResume as u8])
279    }
280
281    /// Deep powerdown the chip
282    pub fn deep_power_down(&mut self) -> Result<(), Error<E>> {
283        self.command_write(&[Command::DeepPowerDown as u8])
284    }
285
286    /// Set the burst length
287    pub fn set_burst_length(&mut self, burst_length: u8) -> Result<(), Error<E>> {
288        self.command_write(&[Command::SetBurstLength as u8, burst_length])
289    }
290
291    /// Read the identification of the device
292    pub fn read_identification(
293        &mut self,
294    ) -> Result<(ManufacturerId, MemoryType, MemoryDensity), Error<E>> {
295        let mut command = [Command::ReadIdentification as u8, 0, 0, 0];
296        self.command_transfer(&mut command)?;
297        Ok((
298            ManufacturerId(command[1]),
299            MemoryType(command[2]),
300            MemoryDensity(command[3]),
301        ))
302    }
303
304    /// Read the electronic signature of the device
305    pub fn read_electronic_id(&mut self) -> Result<ElectronicId, Error<E>> {
306        let dummy = Command::Dummy as u8;
307        let mut command = [Command::ReadElectronicId as u8, dummy, dummy, dummy, 0];
308        self.command_transfer(&mut command)?;
309        Ok(ElectronicId(command[4]))
310    }
311
312    /// Read the manufacturer ID and the device ID
313    pub fn read_manufacturer_id(&mut self) -> Result<(ManufacturerId, DeviceId), Error<E>> {
314        let dummy = Command::Dummy as u8;
315        let mut command = [Command::ReadManufacturerId as u8, dummy, dummy, 0x00, 0, 0];
316        self.command_transfer(&mut command)?;
317        Ok((ManufacturerId(command[4]), DeviceId(command[5])))
318    }
319
320    /// No operation
321    pub fn nop(&mut self) -> Result<(), Error<E>> {
322        self.command_write(&[Command::Nop as u8])
323    }
324
325    /// Enable reset, though you shouldn't need this function since it's already handled in the reset operation.
326    fn reset_enable(&mut self) -> Result<(), Error<E>> {
327        self.command_write(&[Command::ResetEnable as u8])
328    }
329
330    /// Reset the chip.
331    pub fn reset(&mut self) -> Result<(), Error<E>> {
332        self.reset_enable()?;
333        self.command_write(&[Command::ResetMemory as u8])
334    }
335}
336
337impl<const SIZE: u32, SPI, E> MX25V<SIZE, true, SPI>
338where
339    SPI: SpiDevice<Error = E>,
340{
341    /// Write configuration to the configuration register.
342    pub fn configure(
343        &mut self,
344        block_protected: u8,
345        quad_enable: bool,
346        status_write_disable: bool,
347        dummy_cycle: bool,
348        protected_section: ProtectedArea,
349    ) -> Result<(), Error<E>> {
350        if block_protected > 0x0F {
351            return Err(Error::Value);
352        }
353        self.prepare_write()?;
354        let mut command: [u8; 3] = [Command::WriteStatus as u8, 0, 0];
355        command[1].set_bit_range(2..6, block_protected);
356        command[1].set_bit(6, quad_enable);
357        command[1].set_bit(7, status_write_disable);
358        command[2].set_bit(3, protected_section.into());
359        command[2].set_bit(6, dummy_cycle);
360        self.command_write(&command)?;
361        Ok(())
362    }
363}
364
365impl<const SIZE: u32, SPI, E> MX25V<SIZE, false, SPI>
366where
367    SPI: SpiDevice<Error = E>,
368{
369    /// Write configuration to the configuration register.
370    pub fn configure(
371        &mut self,
372        block_protected: u8,
373        status_write_disable: bool,
374        dummy_cycle: bool,
375        protected_section: ProtectedArea,
376    ) -> Result<(), Error<E>> {
377        if block_protected > 0x0F {
378            return Err(Error::Value);
379        }
380        self.prepare_write()?;
381        let mut command: [u8; 3] = [Command::WriteStatus as u8, 0, 0];
382        command[1].set_bit_range(2..6, block_protected);
383        command[1].set_bit(7, status_write_disable);
384        command[2].set_bit(3, protected_section.into());
385        command[2].set_bit(6, dummy_cycle);
386        self.command_write(&command)?;
387        Ok(())
388    }
389}
390
391/// Implementation of the [`NorFlash`](embedded_storage::nor_flash) trait of the  crate
392mod es {
393
394    use crate::error::Error;
395    use crate::{check_erase, check_write};
396    use crate::{BLOCK32_SIZE, BLOCK64_SIZE, PAGE_SIZE, SECTOR_SIZE};
397    use embedded_hal::spi::SpiDevice;
398    use embedded_storage::nor_flash::{MultiwriteNorFlash, NorFlash, ReadNorFlash};
399
400    use super::MX25V;
401
402    impl<const SIZE: u32, const QUAD: bool, SPI: SpiDevice> embedded_storage::nor_flash::ErrorType for MX25V<SIZE, QUAD, SPI> {
403        type Error = Error<SPI::Error>;
404    }
405
406    impl<const SIZE: u32, const QUAD: bool, SPI: SpiDevice> ReadNorFlash for MX25V<SIZE, QUAD, SPI> {
407        const READ_SIZE: usize = 1;
408
409        fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
410            self.read_fast(offset, bytes)
411        }
412
413        fn capacity(&self) -> usize {
414            // TODO: embedded-storage currently returns a usize which doesn't work for 16-bit or below architectures!
415            Self::CAPACITY.try_into().unwrap_or(usize::MAX)
416        }
417    }
418
419    impl<const SIZE: u32, const QUAD: bool, SPI: SpiDevice> NorFlash for MX25V<SIZE, QUAD, SPI> {
420        const WRITE_SIZE: usize = 1;
421        const ERASE_SIZE: usize = SECTOR_SIZE as usize;
422
423        fn erase(&mut self, mut from: u32, to: u32) -> Result<(), Self::Error> {
424            check_erase(Self::CAPACITY, from, to)?;
425
426            while from < to {
427                self.wait_wip()?;
428                let addr_diff = to - from;
429                if addr_diff.is_multiple_of(BLOCK64_SIZE) {
430                    self.erase_block64(from)?;
431                    from += BLOCK64_SIZE;
432                } else if addr_diff.is_multiple_of(BLOCK32_SIZE) {
433                    self.erase_block32(from)?;
434                    from += BLOCK32_SIZE;
435                } else if addr_diff.is_multiple_of(SECTOR_SIZE) {
436                    self.erase_sector(from)?;
437                    from += SECTOR_SIZE;
438                } else {
439                    return Err(Error::NotAligned);
440                }
441            }
442            Ok(())
443        }
444
445        fn write(&mut self, mut offset: u32, mut bytes: &[u8]) -> Result<(), Self::Error> {
446            check_write(Self::CAPACITY, offset, bytes.len())?;
447
448            // Write first chunk, taking into account that given addres might
449            // point to a location that is not on a page boundary,
450            let chunk_len = (PAGE_SIZE - (offset & 0x000000FF)) as usize;
451            let mut chunk_len = chunk_len.min(bytes.len());
452            self.write_page(offset, &bytes[..chunk_len])?;
453
454            loop {
455                bytes = &bytes[chunk_len..];
456                offset += chunk_len as u32;
457                chunk_len = bytes.len().min(PAGE_SIZE as usize);
458                if chunk_len == 0 {
459                    break;
460                }
461                self.write_page(offset, &bytes[..chunk_len])?;
462            }
463
464            Ok(())
465        }
466    }
467
468    impl<const SIZE: u32, const QUAD: bool, SPI: SpiDevice> MultiwriteNorFlash for MX25V<SIZE, QUAD, SPI> {}
469}