embedded_storage/
nor_flash.rs

1use crate::{iter::IterableByOverlaps, ReadStorage, Region, Storage};
2
3/// NOR flash errors.
4///
5/// NOR flash implementations must use an error type implementing this trait. This permits generic
6/// code to extract a generic error kind.
7pub trait NorFlashError: core::fmt::Debug {
8	/// Convert a specific NOR flash error into a generic error kind.
9	fn kind(&self) -> NorFlashErrorKind;
10}
11
12impl NorFlashError for core::convert::Infallible {
13	fn kind(&self) -> NorFlashErrorKind {
14		match *self {}
15	}
16}
17
18/// A trait that NorFlash implementations can use to share an error type.
19pub trait ErrorType {
20	/// Errors returned by this NOR flash.
21	type Error: NorFlashError;
22}
23
24/// NOR flash error kinds.
25///
26/// NOR flash implementations must map their error to those generic error kinds through the
27/// [`NorFlashError`] trait.
28#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
29#[non_exhaustive]
30pub enum NorFlashErrorKind {
31	/// The arguments are not properly aligned.
32	NotAligned,
33
34	/// The arguments are out of bounds.
35	OutOfBounds,
36
37	/// Error specific to the implementation.
38	Other,
39}
40
41impl NorFlashError for NorFlashErrorKind {
42	fn kind(&self) -> NorFlashErrorKind {
43		*self
44	}
45}
46
47impl core::fmt::Display for NorFlashErrorKind {
48	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
49		match self {
50			Self::NotAligned => write!(f, "Arguments are not properly aligned"),
51			Self::OutOfBounds => write!(f, "Arguments are out of bounds"),
52			Self::Other => write!(f, "An implementation specific error occurred"),
53		}
54	}
55}
56
57/// Read only NOR flash trait.
58pub trait ReadNorFlash: ErrorType {
59	/// The minumum number of bytes the storage peripheral can read
60	const READ_SIZE: usize;
61
62	/// Read a slice of data from the storage peripheral, starting the read
63	/// operation at the given address offset, and reading `bytes.len()` bytes.
64	///
65	/// # Errors
66	///
67	/// Returns an error if the arguments are not aligned or out of bounds. The implementation
68	/// can use the [`check_read`] helper function.
69	fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error>;
70
71	/// The capacity of the peripheral in bytes.
72	fn capacity(&self) -> usize;
73}
74
75/// Return whether a read operation is within bounds.
76pub fn check_read<T: ReadNorFlash>(
77	flash: &T,
78	offset: u32,
79	length: usize,
80) -> Result<(), NorFlashErrorKind> {
81	check_slice(flash, T::READ_SIZE, offset, length)
82}
83
84/// NOR flash trait.
85pub trait NorFlash: ReadNorFlash {
86	/// The minumum number of bytes the storage peripheral can write
87	const WRITE_SIZE: usize;
88
89	/// The minumum number of bytes the storage peripheral can erase
90	const ERASE_SIZE: usize;
91
92	/// Erase the given storage range, clearing all data within `[from..to]`.
93	/// The given range will contain all 1s afterwards.
94	///
95	/// If power is lost during erase, contents of the page are undefined.
96	///
97	/// # Errors
98	///
99	/// Returns an error if the arguments are not aligned or out of bounds (the case where `to >
100	/// from` is considered out of bounds). The implementation can use the [`check_erase`]
101	/// helper function.
102	fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error>;
103
104	/// If power is lost during write, the contents of the written words are undefined,
105	/// but the rest of the page is guaranteed to be unchanged.
106	/// It is not allowed to write to the same word twice.
107	///
108	/// # Errors
109	///
110	/// Returns an error if the arguments are not aligned or out of bounds. The implementation
111	/// can use the [`check_write`] helper function.
112	fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error>;
113}
114
115/// Return whether an erase operation is aligned and within bounds.
116pub fn check_erase<T: NorFlash>(flash: &T, from: u32, to: u32) -> Result<(), NorFlashErrorKind> {
117	let (from, to) = (from as usize, to as usize);
118	if from > to || to > flash.capacity() {
119		return Err(NorFlashErrorKind::OutOfBounds);
120	}
121	if from % T::ERASE_SIZE != 0 || to % T::ERASE_SIZE != 0 {
122		return Err(NorFlashErrorKind::NotAligned);
123	}
124	Ok(())
125}
126
127/// Return whether a write operation is aligned and within bounds.
128pub fn check_write<T: NorFlash>(
129	flash: &T,
130	offset: u32,
131	length: usize,
132) -> Result<(), NorFlashErrorKind> {
133	check_slice(flash, T::WRITE_SIZE, offset, length)
134}
135
136fn check_slice<T: ReadNorFlash>(
137	flash: &T,
138	align: usize,
139	offset: u32,
140	length: usize,
141) -> Result<(), NorFlashErrorKind> {
142	let offset = offset as usize;
143	if length > flash.capacity() || offset > flash.capacity() - length {
144		return Err(NorFlashErrorKind::OutOfBounds);
145	}
146	if offset % align != 0 || length % align != 0 {
147		return Err(NorFlashErrorKind::NotAligned);
148	}
149	Ok(())
150}
151
152impl<T: ErrorType> ErrorType for &mut T {
153	type Error = T::Error;
154}
155
156impl<T: ReadNorFlash> ReadNorFlash for &mut T {
157	const READ_SIZE: usize = T::READ_SIZE;
158
159	fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
160		T::read(self, offset, bytes)
161	}
162
163	fn capacity(&self) -> usize {
164		T::capacity(self)
165	}
166}
167
168impl<T: NorFlash> NorFlash for &mut T {
169	const WRITE_SIZE: usize = T::WRITE_SIZE;
170	const ERASE_SIZE: usize = T::ERASE_SIZE;
171
172	fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
173		T::erase(self, from, to)
174	}
175
176	fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
177		T::write(self, offset, bytes)
178	}
179}
180
181/// Marker trait for NorFlash relaxing the restrictions on `write`.
182///
183/// Writes to the same word twice are now allowed. The result is the logical AND of the
184/// previous data and the written data. That is, it is only possible to change 1 bits to 0 bits.
185///
186/// If power is lost during write:
187/// - Bits that were 1 on flash and are written to 1 are guaranteed to stay as 1
188/// - Bits that were 1 on flash and are written to 0 are undefined
189/// - Bits that were 0 on flash are guaranteed to stay as 0
190/// - Rest of the bits in the page are guaranteed to be unchanged
191pub trait MultiwriteNorFlash: NorFlash {}
192
193struct Page {
194	pub start: u32,
195	pub size: usize,
196}
197
198impl Page {
199	fn new(index: u32, size: usize) -> Self {
200		Self {
201			start: index * size as u32,
202			size,
203		}
204	}
205
206	/// The end address of the page
207	const fn end(&self) -> u32 {
208		self.start + self.size as u32
209	}
210}
211
212impl Region for Page {
213	/// Checks if an address offset is contained within the page
214	fn contains(&self, address: u32) -> bool {
215		(self.start <= address) && (self.end() > address)
216	}
217}
218
219///
220pub struct RmwNorFlashStorage<'a, S> {
221	storage: S,
222	merge_buffer: &'a mut [u8],
223}
224
225impl<'a, S> RmwNorFlashStorage<'a, S>
226where
227	S: NorFlash,
228{
229	/// Instantiate a new generic `Storage` from a `NorFlash` peripheral
230	///
231	/// **NOTE** This will panic if the provided merge buffer,
232	/// is smaller than the erase size of the flash peripheral
233	pub fn new(nor_flash: S, merge_buffer: &'a mut [u8]) -> Self {
234		if merge_buffer.len() < S::ERASE_SIZE {
235			panic!("Merge buffer is too small");
236		}
237
238		Self {
239			storage: nor_flash,
240			merge_buffer,
241		}
242	}
243}
244
245impl<'a, S> ReadStorage for RmwNorFlashStorage<'a, S>
246where
247	S: ReadNorFlash,
248{
249	type Error = S::Error;
250
251	fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
252		// Nothing special to be done for reads
253		self.storage.read(offset, bytes)
254	}
255
256	fn capacity(&self) -> usize {
257		self.storage.capacity()
258	}
259}
260
261impl<'a, S> Storage for RmwNorFlashStorage<'a, S>
262where
263	S: NorFlash,
264{
265	fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
266		// Perform read/modify/write operations on the byte slice.
267		let last_page = self.storage.capacity() / S::ERASE_SIZE;
268
269		// `data` is the part of `bytes` contained within `page`,
270		// and `addr` in the address offset of `page` + any offset into the page as requested by `address`
271		for (data, page, addr) in (0..last_page as u32)
272			.map(move |i| Page::new(i, S::ERASE_SIZE))
273			.overlaps(bytes, offset)
274		{
275			let offset_into_page = addr.saturating_sub(page.start) as usize;
276
277			self.storage
278				.read(page.start, &mut self.merge_buffer[..S::ERASE_SIZE])?;
279
280			// If we cannot write multiple times to the same page, we will have to erase it
281			self.storage.erase(page.start, page.end())?;
282			self.merge_buffer[..S::ERASE_SIZE]
283				.iter_mut()
284				.skip(offset_into_page)
285				.zip(data)
286				.for_each(|(byte, input)| *byte = *input);
287			self.storage
288				.write(page.start, &self.merge_buffer[..S::ERASE_SIZE])?;
289		}
290		Ok(())
291	}
292}
293
294///
295pub struct RmwMultiwriteNorFlashStorage<'a, S> {
296	storage: S,
297	merge_buffer: &'a mut [u8],
298}
299
300impl<'a, S> RmwMultiwriteNorFlashStorage<'a, S>
301where
302	S: MultiwriteNorFlash,
303{
304	/// Instantiate a new generic `Storage` from a `NorFlash` peripheral
305	///
306	/// **NOTE** This will panic if the provided merge buffer,
307	/// is smaller than the erase size of the flash peripheral
308	pub fn new(nor_flash: S, merge_buffer: &'a mut [u8]) -> Self {
309		if merge_buffer.len() < S::ERASE_SIZE {
310			panic!("Merge buffer is too small");
311		}
312
313		Self {
314			storage: nor_flash,
315			merge_buffer,
316		}
317	}
318}
319
320impl<'a, S> ReadStorage for RmwMultiwriteNorFlashStorage<'a, S>
321where
322	S: ReadNorFlash,
323{
324	type Error = S::Error;
325
326	fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
327		// Nothing special to be done for reads
328		self.storage.read(offset, bytes)
329	}
330
331	fn capacity(&self) -> usize {
332		self.storage.capacity()
333	}
334}
335
336impl<'a, S> Storage for RmwMultiwriteNorFlashStorage<'a, S>
337where
338	S: MultiwriteNorFlash,
339{
340	fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
341		// Perform read/modify/write operations on the byte slice.
342		let last_page = self.storage.capacity() / S::ERASE_SIZE;
343
344		// `data` is the part of `bytes` contained within `page`,
345		// and `addr` in the address offset of `page` + any offset into the page as requested by `address`
346		for (data, page, addr) in (0..last_page as u32)
347			.map(move |i| Page::new(i, S::ERASE_SIZE))
348			.overlaps(bytes, offset)
349		{
350			let offset_into_page = addr.saturating_sub(page.start) as usize;
351
352			self.storage
353				.read(page.start, &mut self.merge_buffer[..S::ERASE_SIZE])?;
354
355			let rhs = &self.merge_buffer[offset_into_page..S::ERASE_SIZE];
356			let is_subset = data.iter().zip(rhs.iter()).all(|(a, b)| *a & *b == *a);
357
358			// Check if we can write the data block directly, under the limitations imposed by NorFlash:
359			// - We can only change 1's to 0's
360			if is_subset {
361				// Use `merge_buffer` as allocation for padding `data` to `WRITE_SIZE`
362				let offset = addr as usize % S::WRITE_SIZE;
363				let aligned_end = data.len() % S::WRITE_SIZE + offset + data.len();
364				self.merge_buffer[..aligned_end].fill(0xff);
365				self.merge_buffer[offset..offset + data.len()].copy_from_slice(data);
366				self.storage
367					.write(addr - offset as u32, &self.merge_buffer[..aligned_end])?;
368			} else {
369				self.storage.erase(page.start, page.end())?;
370				self.merge_buffer[..S::ERASE_SIZE]
371					.iter_mut()
372					.skip(offset_into_page)
373					.zip(data)
374					.for_each(|(byte, input)| *byte = *input);
375				self.storage
376					.write(page.start, &self.merge_buffer[..S::ERASE_SIZE])?;
377			}
378		}
379		Ok(())
380	}
381}