1use crate::{utils::HexSlice, Error};
4use bitflags::bitflags;
5use core::marker::PhantomData;
6pub use core::task::Poll;
7use core::{convert::TryInto, fmt};
8pub use embedded_hal_async::{
9 delay::DelayNs,
10 spi::{Operation, SpiDevice},
11};
12pub use embedded_storage_async;
13
14#[derive(defmt::Format)]
15pub struct Identification {
17 bytes: [u8; 3],
21
22 continuations: u8,
24}
25
26impl Identification {
27 pub fn from_jedec_id(buf: &[u8]) -> Identification {
29 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 pub fn mfr_code(&self) -> u8 {
51 self.bytes[0]
52 }
53
54 pub fn device_id(&self) -> &[u8] {
56 self.bytes[1..].as_ref()
57 }
58
59 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)] enum Opcode {
78 ReadDeviceId = 0xAB,
80 ReadMfDId = 0x90,
82 ReadJedecId = 0x9F,
84 WriteEnable = 0x06,
86 WriteDisable = 0x04,
88 ReadStatus = 0x05,
90 WriteStatus = 0x01,
92 Read = 0x03,
93 PageProg = 0x02, SectorErase = 0x20,
95 BlockErase = 0xD8,
96 ChipErase = 0xC7,
97}
98
99bitflags! {
100 pub struct Status: u8 {
102 const BUSY = 1 << 0;
104 const WEL = 1 << 1;
106 const PROT = 0b00011100;
108 const SRWD = 1 << 7;
110 }
111}
112
113pub trait FlashParameters {
115 const PAGE_SIZE: usize;
117 const SECTOR_SIZE: usize;
119 const BLOCK_SIZE: usize;
121 const CHIP_SIZE: usize;
123}
124
125#[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 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 this.wait_done().await?;
179
180 Ok(this)
181 }
182
183 pub const fn page_write_size(&self) -> usize {
185 FlashParams::PAGE_SIZE
186 }
187
188 pub const fn sector_erase_size(&self) -> usize {
190 FlashParams::SECTOR_SIZE
191 }
192
193 pub const fn block_erase_size(&self) -> usize {
195 FlashParams::BLOCK_SIZE
196 }
197
198 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 pub async fn read_jedec_id(&mut self) -> Result<Identification, Error<SPI>> {
213 let mut buf: [u8; 12] = [0; 12];
215 buf[0] = Opcode::ReadJedecId as u8;
216 self.command_transfer(&mut buf).await?;
217
218 Ok(Identification::from_jedec_id(&buf[1..]))
220 }
221
222 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 pub async fn read(&mut self, addr: u32, buf: &mut [u8]) -> Result<(), Error<SPI>> {
255 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 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 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 pub async fn write_bytes(&mut self, addr: u32, data: &[u8]) -> Result<(), Error<SPI>> {
314 self.write_enable().await?;
315
316 let cmd_buf = [
317 Opcode::PageProg as u8,
318 (addr >> 16) as u8,
319 (addr >> 8) as u8,
320 addr as u8,
321 ];
322 self.spi
323 .transaction(&mut [
324 Operation::Write(&cmd_buf),
325 Operation::Write(&data[..FlashParams::PAGE_SIZE.min(data.len())]),
326 ])
327 .await
328 .map_err(Error::Spi)?;
329
330 self.wait_done().await
331 }
332
333 pub async fn erase_all(&mut self) -> Result<(), Error<SPI>> {
338 self.write_enable().await?;
339 let cmd_buf = [Opcode::ChipErase as u8];
340 self.command_write(&cmd_buf).await?;
341 self.wait_done().await
342 }
343
344 pub async fn erase_range(
353 &mut self,
354 start_address: u32,
355 end_address: u32,
356 ) -> Result<(), Error<SPI>> {
357 self.write_enable().await?;
358 let sector_size: u32 = FlashParams::SECTOR_SIZE.try_into().unwrap();
359
360 if start_address % sector_size != 0 {
361 return Err(Error::NotAligned);
362 }
363
364 if end_address % sector_size != 0 {
365 return Err(Error::NotAligned);
366 }
367
368 if start_address > end_address {
369 return Err(Error::OutOfBounds);
370 }
371
372 let start_sector = start_address / sector_size;
373 let end_sector = end_address / sector_size;
374
375 for sector in start_sector..end_sector {
376 self.erase_sector(sector).await.unwrap();
377 }
378
379 Ok(())
380 }
381}
382
383impl<SPI, FlashParams, Delay> embedded_storage::nor_flash::ErrorType
384 for Flash<SPI, FlashParams, Delay>
385where
386 SPI: SpiDevice<u8>,
387{
388 type Error = Error<SPI>;
389}
390
391impl<SPI, FlashParams, Delay> embedded_storage_async::nor_flash::ReadNorFlash
392 for Flash<SPI, FlashParams, Delay>
393where
394 SPI: SpiDevice<u8>,
395 Delay: DelayNs,
396 FlashParams: FlashParameters,
397{
398 const READ_SIZE: usize = 1;
399
400 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
401 self.read(offset, bytes).await
402 }
403
404 fn capacity(&self) -> usize {
405 FlashParams::CHIP_SIZE.try_into().unwrap()
406 }
407}
408
409impl<SPI, FlashParams, Delay> embedded_storage_async::nor_flash::NorFlash
410 for Flash<SPI, FlashParams, Delay>
411where
412 SPI: SpiDevice<u8>,
413 Delay: DelayNs,
414 FlashParams: FlashParameters,
415{
416 const WRITE_SIZE: usize = 1;
417
418 const ERASE_SIZE: usize = FlashParams::SECTOR_SIZE;
419
420 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
421 self.erase_range(from, to).await
422 }
423
424 async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
425 self.write_bytes(offset, bytes).await
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use super::*;
432
433 #[test]
434 fn test_decode_jedec_id() {
435 let cypress_id_bytes = [0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xC2, 0x22, 0x08];
436 let ident = Identification::from_jedec_id(&cypress_id_bytes);
437 assert_eq!(0xC2, ident.mfr_code());
438 assert_eq!(6, ident.continuation_count());
439 let device_id = ident.device_id();
440 assert_eq!(device_id[0], 0x22);
441 assert_eq!(device_id[1], 0x08);
442 }
443}