1#![no_std]
2#![doc = include_str!("../README.md")]
3#![deny(unsafe_code)]
4#![warn(missing_docs)]
5
6use core::{fmt::Debug, marker::PhantomData};
7use derive_more::TryFrom;
8use embassy_futures::yield_now;
9use embedded_hal::digital::{OutputPin, PinState};
10use embedded_hal_async::spi::SpiDevice;
11use embedded_storage::nor_flash::{ErrorType, NorFlashError, NorFlashErrorKind};
12
13mod commands_impl;
14
15pub struct Q;
17pub struct X;
19
20pub trait NorSeries {
22 const PAGE_SIZE: u32;
24 const SECTOR_SIZE: u32;
26}
27
28impl NorSeries for Q {
29 const PAGE_SIZE: u32 = 256;
30 const SECTOR_SIZE: u32 = Self::PAGE_SIZE * 16;
31}
32
33impl NorSeries for X {
34 const PAGE_SIZE: u32 = 256;
35 const SECTOR_SIZE: u32 = Self::PAGE_SIZE * 16;
36}
37
38pub trait Reset {}
40
41impl Reset for Q {}
42
43#[repr(u8)]
45enum Command {
46 PageProgram = 0x02,
47 ReadData = 0x03,
48 ReadStatusRegister1 = 0x05,
49 WriteEnable = 0x06,
50 SectorErase = 0x20,
51 JedecId = 0x9F,
52 UniqueId = 0x4B,
53 Block32Erase = 0x52,
54 Block64Erase = 0xD8,
55 ChipErase = 0xC7,
56 EnableReset = 0x66,
57 PowerDown = 0xB9,
58 ReleasePowerDown = 0xAB,
59 Reset = 0x99,
60}
61
62pub struct W25<Series, SPI, HOLD, WP> {
64 spi: SPI,
65 hold: HOLD,
66 wp: WP,
67 capacity: u32,
68 _pantom: PhantomData<Series>,
69}
70
71impl<Series: NorSeries, SPI, HOLD, WP> W25<Series, SPI, HOLD, WP> {
72 pub fn capacity(&self) -> u32 {
74 self.capacity
75 }
76
77 fn n_sectors(&self) -> u32 {
78 self.capacity / Series::SECTOR_SIZE
79 }
80
81 fn n_blocks_32k(&self) -> u32 {
82 self.capacity / 32768
83 }
84
85 fn n_blocks_64k(&self) -> u32 {
86 self.capacity / 65536
87 }
88}
89
90impl<Series: NorSeries, SPI, S: Debug, P: Debug, HOLD, WP> W25<Series, SPI, HOLD, WP>
91where
92 SPI: embedded_hal::spi::ErrorType<Error = S> + embedded_hal_async::spi::SpiDevice,
93 HOLD: OutputPin<Error = P>,
94 WP: OutputPin<Error = P>,
95{
96 pub async fn new(spi: SPI, hold: HOLD, wp: WP, capacity: u32) -> Result<Self, InitError<S, P>> {
102 let mut flash = W25 {
103 spi,
104 hold,
105 wp,
106 capacity,
107 _pantom: PhantomData,
108 };
109
110 flash.hold.set_high().map_err(InitError::PinError)?;
111 flash.wp.set_high().map_err(InitError::PinError)?;
112
113 while flash.busy().await? {
115 yield_now().await;
118 }
119
120 Ok(flash)
121 }
122
123 pub fn set_hold(&mut self, value: PinState) -> Result<(), P> {
130 self.hold.set_state(value)
131 }
132
133 pub fn set_wp(&mut self, value: PinState) -> Result<(), P> {
140 self.wp.set_state(value)
141 }
142}
143
144impl<Series: NorSeries, SPI, S: Debug> W25<Series, SPI, (), ()>
145where
146 SPI: embedded_hal::spi::ErrorType<Error = S> + embedded_hal_async::spi::SpiDevice,
147{
148 pub async fn new_no_pins(spi: SPI, capacity: u32) -> Result<Self, Error<S>> {
154 let mut flash = Self {
155 spi,
156 hold: (),
157 wp: (),
158 capacity,
159 _pantom: PhantomData,
160 };
161
162 while flash.busy().await? {
164 yield_now().await;
167 }
168
169 Ok(flash)
170 }
171}
172
173#[derive(Debug)]
175#[cfg_attr(feature = "defmt", derive(defmt::Format))]
176#[non_exhaustive]
177pub enum InitError<S: Debug, P: Debug> {
178 DeviceError(Error<S>),
180 PinError(P),
182 ManufacturerNotRecognized(u8),
184 DeviceNotRecognized(u8),
186}
187
188impl<S: Debug, P: Debug> From<Error<S>> for InitError<S, P> {
189 fn from(value: Error<S>) -> Self {
190 Self::DeviceError(value)
191 }
192}
193
194impl<Series: NorSeries, SPI, S: Debug, P: Debug, HOLD, WP> W25<Series, SPI, HOLD, WP>
195where
196 SPI: SpiDevice<Error = S>,
197 HOLD: OutputPin<Error = P>,
198 WP: OutputPin<Error = P>,
199{
200 pub async fn new_autodetect(spi: SPI, hold: HOLD, wp: WP) -> Result<Self, InitError<S, P>> {
202 let mut flash = W25 {
203 spi,
204 hold,
205 wp,
206 capacity: 0, _pantom: PhantomData,
208 };
209
210 flash.hold.set_high().map_err(InitError::PinError)?;
211 flash.wp.set_high().map_err(InitError::PinError)?;
212
213 let jedec_id = flash.jedec_id().await?;
214 let manufacturer = jedec_id.manufacturer();
215 if jedec_id.manufacturer() != JedecId::MANUFACTURER {
216 return Err(InitError::ManufacturerNotRecognized(manufacturer));
217 }
218
219 let major_device_id = jedec_id
220 .major_device_id()
221 .map_err(InitError::DeviceNotRecognized)?;
222
223 flash.capacity = major_device_id.capacity();
225
226 while flash.busy().await? {
228 yield_now().await;
231 }
232
233 Ok(flash)
234 }
235}
236
237impl<Series: NorSeries, SPI, S: Debug, HOLD, WP> ErrorType for W25<Series, SPI, HOLD, WP>
238where
239 SPI: embedded_hal::spi::ErrorType<Error = S>,
240{
241 type Error = Error<S>;
242}
243
244#[derive(Debug)]
247#[cfg_attr(feature = "defmt", derive(defmt::Format))]
248#[non_exhaustive]
249pub enum Error<S: Debug> {
250 SpiError(S),
252 NotAligned,
254 OutOfBounds,
256 WriteEnableFail,
258}
259
260impl<S: Debug> NorFlashError for Error<S> {
261 fn kind(&self) -> NorFlashErrorKind {
262 match self {
263 Error::NotAligned => NorFlashErrorKind::NotAligned,
264 Error::OutOfBounds => NorFlashErrorKind::OutOfBounds,
265 _ => NorFlashErrorKind::Other,
266 }
267 }
268}
269
270#[allow(clippy::identity_op)]
271fn command_and_address(command: u8, address: u32) -> [u8; 4] {
272 [
273 command,
274 ((address & 0xFF0000) >> 16) as u8,
276 ((address & 0x00FF00) >> 8) as u8,
277 ((address & 0x0000FF) >> 0) as u8,
278 ]
279}
280
281#[derive(Debug, Clone, Copy, TryFrom)]
286#[cfg_attr(feature = "defmt", derive(defmt::Format))]
287#[repr(u8)]
288#[try_from(repr)]
289pub enum MajorDeviceId {
290 W25_05 = 0x05,
292 W25_10 = 0x10,
294 W25_20 = 0x11,
296 W25_40 = 0x12,
298 W25_80 = 0x13,
300 W25_16 = 0x14,
302 W25_32 = 0x15,
304 W25_64 = 0x16,
306 W25_128 = 0x17,
308 W25_256 = 0x18,
310 W25_512 = 0x19,
312 W25_01 = 0x20,
314 W25_02 = 0x21,
316}
317
318impl MajorDeviceId {
319 pub const fn capacity(&self) -> u32 {
321 let capacity_kilobits = match *self {
322 MajorDeviceId::W25_05 => 512,
323 MajorDeviceId::W25_10 => 1024,
324 MajorDeviceId::W25_20 => 2 * 1024,
325 MajorDeviceId::W25_40 => 4 * 1024,
326 MajorDeviceId::W25_80 => 8 * 1024,
327 MajorDeviceId::W25_16 => 16 * 1024,
328 MajorDeviceId::W25_32 => 32 * 1024,
329 MajorDeviceId::W25_64 => 64 * 1024,
330 MajorDeviceId::W25_128 => 128 * 1024,
331 MajorDeviceId::W25_256 => 256 * 1024,
332 MajorDeviceId::W25_512 => 512 * 1024,
333 MajorDeviceId::W25_01 => 1024 * 1024,
334 MajorDeviceId::W25_02 => 2 * 1024 * 1024,
335 };
336
337 const FACTOR_KILOBITS_BYTES: u32 = 1024 / 8;
338 capacity_kilobits * FACTOR_KILOBITS_BYTES
339 }
340}
341
342pub struct JedecId([u8; 3]);
344
345impl JedecId {
346 pub const MANUFACTURER: u8 = 0xEF;
348
349 pub const fn manufacturer(&self) -> u8 {
353 self.0[0]
354 }
355
356 pub fn major_device_id(&self) -> Result<MajorDeviceId, u8> {
361 let b_jedec = self.0[2];
362 let b_device_id = match b_jedec {
363 0x20 => 0x19, _ => b_jedec.checked_sub(1).ok_or(b_jedec)?,
365 };
366 MajorDeviceId::try_from(b_device_id).map_err(|_e| b_jedec)
367 }
368
369 pub const fn minor_device_id(&self) -> u8 {
371 self.0[1]
372 }
373}