embedded_storage/
nor_flash.rs

1use crate::{iter::IterableByOverlaps, ReadStorage, Region, Storage};
2
3/// Read only NOR flash trait.
4pub trait ReadNorFlash {
5	/// An enumeration of storage errors
6	type Error;
7
8	/// The minumum number of bytes the storage peripheral can read
9	const READ_SIZE: usize;
10
11	/// Read a slice of data from the storage peripheral, starting the read
12	/// operation at the given address offset, and reading `bytes.len()` bytes.
13	///
14	/// This should throw an error in case `bytes.len()` will be larger than
15	/// the peripheral end address.
16	fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error>;
17
18	/// The capacity of the peripheral in bytes.
19	fn capacity(&self) -> usize;
20}
21
22/// NOR flash trait.
23pub trait NorFlash: ReadNorFlash {
24	/// The minumum number of bytes the storage peripheral can write
25	const WRITE_SIZE: usize;
26
27	/// The minumum number of bytes the storage peripheral can erase
28	const ERASE_SIZE: usize;
29
30	/// Erase the given storage range, clearing all data within `[from..to]`.
31	/// The given range will contain all 1s afterwards.
32	///
33	/// This should return an error if the range is not aligned to a proper
34	/// erase resolution
35	/// If power is lost during erase, contents of the page are undefined.
36	/// `from` and `to` must both be multiples of `ERASE_SIZE` and `from` <= `to`.
37	fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error>;
38
39	/// If power is lost during write, the contents of the written words are undefined,
40	/// but the rest of the page is guaranteed to be unchanged.
41	/// It is not allowed to write to the same word twice.
42	/// `offset` and `bytes.len()` must both be multiples of `WRITE_SIZE`.
43	fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error>;
44}
45
46/// Marker trait for NorFlash relaxing the restrictions on `write`.
47///
48/// Writes to the same word twice are now allowed. The result is the logical AND of the
49/// previous data and the written data. That is, it is only possible to change 1 bits to 0 bits.
50///
51/// If power is lost during write:
52/// - Bits that were 1 on flash and are written to 1 are guaranteed to stay as 1
53/// - Bits that were 1 on flash and are written to 0 are undefined
54/// - Bits that were 0 on flash are guaranteed to stay as 0
55/// - Rest of the bits in the page are guaranteed to be unchanged
56pub trait MultiwriteNorFlash: NorFlash {}
57
58struct Page {
59	pub start: u32,
60	pub size: usize,
61}
62
63impl Page {
64	fn new(index: u32, size: usize) -> Self {
65		Self {
66			start: index * size as u32,
67			size,
68		}
69	}
70
71	/// The end address of the page
72	const fn end(&self) -> u32 {
73		self.start + self.size as u32
74	}
75}
76
77impl Region for Page {
78	/// Checks if an address offset is contained within the page
79	fn contains(&self, address: u32) -> bool {
80		(self.start <= address) && (self.end() > address)
81	}
82}
83
84///
85pub struct RmwNorFlashStorage<'a, S> {
86	storage: S,
87	merge_buffer: &'a mut [u8],
88}
89
90impl<'a, S> RmwNorFlashStorage<'a, S>
91where
92	S: NorFlash,
93{
94	/// Instantiate a new generic `Storage` from a `NorFlash` peripheral
95	///
96	/// **NOTE** This will panic if the provided merge buffer,
97	/// is smaller than the erase size of the flash peripheral
98	pub fn new(nor_flash: S, merge_buffer: &'a mut [u8]) -> Self {
99		if merge_buffer.len() < S::ERASE_SIZE {
100			panic!("Merge buffer is too small");
101		}
102
103		Self {
104			storage: nor_flash,
105			merge_buffer,
106		}
107	}
108}
109
110impl<'a, S> ReadStorage for RmwNorFlashStorage<'a, S>
111where
112	S: ReadNorFlash,
113{
114	type Error = S::Error;
115
116	fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
117		// Nothing special to be done for reads
118		self.storage.read(offset, bytes)
119	}
120
121	fn capacity(&self) -> usize {
122		self.storage.capacity()
123	}
124}
125
126impl<'a, S> Storage for RmwNorFlashStorage<'a, S>
127where
128	S: NorFlash,
129{
130	fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
131		// Perform read/modify/write operations on the byte slice.
132		let last_page = self.storage.capacity() / S::ERASE_SIZE;
133
134		// `data` is the part of `bytes` contained within `page`,
135		// and `addr` in the address offset of `page` + any offset into the page as requested by `address`
136		for (data, page, addr) in (0..last_page as u32)
137			.map(move |i| Page::new(i, S::ERASE_SIZE))
138			.overlaps(bytes, offset)
139		{
140			let offset_into_page = addr.saturating_sub(page.start) as usize;
141
142			self.storage
143				.read(page.start, &mut self.merge_buffer[..S::ERASE_SIZE])?;
144
145			// If we cannot write multiple times to the same page, we will have to erase it
146			self.storage.erase(page.start, page.end())?;
147			self.merge_buffer[..S::ERASE_SIZE]
148				.iter_mut()
149				.skip(offset_into_page)
150				.zip(data)
151				.for_each(|(byte, input)| *byte = *input);
152			self.storage
153				.write(page.start, &self.merge_buffer[..S::ERASE_SIZE])?;
154		}
155		Ok(())
156	}
157}
158
159///
160pub struct RmwMultiwriteNorFlashStorage<'a, S> {
161	storage: S,
162	merge_buffer: &'a mut [u8],
163}
164
165impl<'a, S> RmwMultiwriteNorFlashStorage<'a, S>
166where
167	S: MultiwriteNorFlash,
168{
169	/// Instantiate a new generic `Storage` from a `NorFlash` peripheral
170	///
171	/// **NOTE** This will panic if the provided merge buffer,
172	/// is smaller than the erase size of the flash peripheral
173	pub fn new(nor_flash: S, merge_buffer: &'a mut [u8]) -> Self {
174		if merge_buffer.len() < S::ERASE_SIZE {
175			panic!("Merge buffer is too small");
176		}
177
178		Self {
179			storage: nor_flash,
180			merge_buffer,
181		}
182	}
183}
184
185impl<'a, S> ReadStorage for RmwMultiwriteNorFlashStorage<'a, S>
186where
187	S: ReadNorFlash,
188{
189	type Error = S::Error;
190
191	fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
192		// Nothing special to be done for reads
193		self.storage.read(offset, bytes)
194	}
195
196	fn capacity(&self) -> usize {
197		self.storage.capacity()
198	}
199}
200
201impl<'a, S> Storage for RmwMultiwriteNorFlashStorage<'a, S>
202where
203	S: MultiwriteNorFlash,
204{
205	fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
206		// Perform read/modify/write operations on the byte slice.
207		let last_page = self.storage.capacity() / S::ERASE_SIZE;
208
209		// `data` is the part of `bytes` contained within `page`,
210		// and `addr` in the address offset of `page` + any offset into the page as requested by `address`
211		for (data, page, addr) in (0..last_page as u32)
212			.map(move |i| Page::new(i, S::ERASE_SIZE))
213			.overlaps(bytes, offset)
214		{
215			let offset_into_page = addr.saturating_sub(page.start) as usize;
216
217			self.storage
218				.read(page.start, &mut self.merge_buffer[..S::ERASE_SIZE])?;
219
220			let rhs = &self.merge_buffer[offset_into_page..S::ERASE_SIZE];
221			let is_subset = data.iter().zip(rhs.iter()).all(|(a, b)| *a & *b == *a);
222
223			// Check if we can write the data block directly, under the limitations imposed by NorFlash:
224			// - We can only change 1's to 0's
225			if is_subset {
226				// Use `merge_buffer` as allocation for padding `data` to `WRITE_SIZE`
227				let offset = addr as usize % S::WRITE_SIZE;
228				let aligned_end = data.len() % S::WRITE_SIZE + offset + data.len();
229				self.merge_buffer[..aligned_end].fill(0xff);
230				self.merge_buffer[offset..offset + data.len()].copy_from_slice(data);
231				self.storage
232					.write(addr - offset as u32, &self.merge_buffer[..aligned_end])?;
233			} else {
234				self.storage.erase(page.start, page.end())?;
235				self.merge_buffer[..S::ERASE_SIZE]
236					.iter_mut()
237					.skip(offset_into_page)
238					.zip(data)
239					.for_each(|(byte, input)| *byte = *input);
240				self.storage
241					.write(page.start, &self.merge_buffer[..S::ERASE_SIZE])?;
242			}
243		}
244		Ok(())
245	}
246}