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
12pub type MX25V512<SPI> = MX25V<_512K, false, SPI>;
14pub type MX25V5126<SPI> = MX25V<_512K, false, SPI>;
16pub type MX25V512F<SPI> = MX25V<_512K, true, SPI>;
18
19pub type MX25V1006<SPI> = MX25V<_1M, false, SPI>;
21pub type MX25V1035<SPI> = MX25V<_1M, true, SPI>;
23
24pub type MX25V2006<SPI> = MX25V<_2M, false, SPI>;
26pub type MX25V2035<SPI> = MX25V<_2M, true, SPI>;
28
29pub type MX25V4006<SPI> = MX25V<_4M, false, SPI>;
31pub type MX25V4035<SPI> = MX25V<_4M, true, SPI>;
33
34pub type MX25V8006<SPI> = MX25V<_8M, false, SPI>;
36pub type MX25V8035<SPI> = MX25V<_8M, true, SPI>;
38
39pub type MX25V1606<SPI> = MX25V<_16M, false, SPI>;
41pub type MX25V1635<SPI> = MX25V<_16M, true, SPI>;
43
44pub 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 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 pub fn read(&mut self, addr: u32, buff: &mut [u8]) -> Result<(), Error<E>> {
187 self.read_base(addr, Command::Read, buff)
188 }
189
190 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 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 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 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 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 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 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 fn write_enable(&mut self) -> Result<(), Error<E>> {
255 self.command_write(&[Command::WriteEnable as u8])
256 }
257
258 pub fn write_disable(&mut self) -> Result<(), Error<E>> {
260 self.command_write(&[Command::WriteDisable as u8])
261 }
262
263 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 pub fn suspend_program_erase(&mut self) -> Result<(), Error<E>> {
273 self.command_write(&[Command::ProgramEraseSuspend as u8])
274 }
275
276 pub fn resume_program_erase(&mut self) -> Result<(), Error<E>> {
278 self.command_write(&[Command::ProgramEraseResume as u8])
279 }
280
281 pub fn deep_power_down(&mut self) -> Result<(), Error<E>> {
283 self.command_write(&[Command::DeepPowerDown as u8])
284 }
285
286 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 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 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 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 pub fn nop(&mut self) -> Result<(), Error<E>> {
322 self.command_write(&[Command::Nop as u8])
323 }
324
325 fn reset_enable(&mut self) -> Result<(), Error<E>> {
327 self.command_write(&[Command::ResetEnable as u8])
328 }
329
330 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 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 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
391mod 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 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 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}