Skip to content

Commit 7d70e13

Browse files
authored
Merge pull request #12 from rust-embedded-community/storage-rework
Rework NorFlash & Storage traits
2 parents 52a1352 + 6a67ff2 commit 7d70e13

File tree

4 files changed

+84
-155
lines changed

4 files changed

+84
-155
lines changed

Cargo.toml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,3 @@ documentation = "https://docs.rs/embedded-storage"
1313
readme = "README.md"
1414
keywords = ["storage"]
1515
categories = ["embedded", "hardware-support", "no-std"]
16-
17-
[dependencies]
18-
nb = "1"
19-
no-std-net = "0.4"
20-
heapless = "^0.5"

src/iter.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{Address, Region};
1+
use crate::Region;
22

33
/// Iterator producing block-region pairs, where each memory block maps to each
44
/// region.
@@ -9,7 +9,7 @@ where
99
{
1010
memory: &'a [u8],
1111
regions: I,
12-
base_address: Address,
12+
base_address: u32,
1313
}
1414

1515
/// Trait allowing us to automatically add an `overlaps` function to all iterators over [`Region`]
@@ -19,25 +19,29 @@ where
1919
I: Iterator<Item = R>,
2020
{
2121
/// Obtain an [`OverlapIterator`] over a subslice of `memory` that overlaps with the region in `self`
22-
fn overlaps(self, memory: &'a [u8], base_address: Address) -> OverlapIterator<R, I>;
22+
fn overlaps(self, memory: &'a [u8], base_address: u32) -> OverlapIterator<R, I>;
2323
}
2424

2525
impl<'a, R, I> Iterator for OverlapIterator<'a, R, I>
2626
where
2727
R: Region,
2828
I: Iterator<Item = R>,
2929
{
30-
type Item = (&'a [u8], R, Address);
30+
type Item = (&'a [u8], R, u32);
3131

3232
fn next(&mut self) -> Option<Self::Item> {
3333
while let Some(region) = self.regions.next() {
3434
// TODO: This might be possible to do in a smarter way?
3535
let mut block_range = (0..self.memory.len())
36-
.skip_while(|index| !region.contains(self.base_address + *index))
37-
.take_while(|index| region.contains(self.base_address + *index));
36+
.skip_while(|index| !region.contains(self.base_address + *index as u32))
37+
.take_while(|index| region.contains(self.base_address + *index as u32));
3838
if let Some(start) = block_range.next() {
3939
let end = block_range.last().unwrap_or(start) + 1;
40-
return Some((&self.memory[start..end], region, self.base_address + start));
40+
return Some((
41+
&self.memory[start..end],
42+
region,
43+
self.base_address + start as u32,
44+
));
4145
}
4246
}
4347
None
@@ -50,7 +54,7 @@ where
5054
R: Region,
5155
I: Iterator<Item = R>,
5256
{
53-
fn overlaps(self, memory: &'a [u8], base_address: Address) -> OverlapIterator<R, I> {
57+
fn overlaps(self, memory: &'a [u8], base_address: u32) -> OverlapIterator<R, I> {
5458
OverlapIterator {
5559
memory,
5660
regions: self,

src/lib.rs

Lines changed: 18 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -2,169 +2,45 @@
22
//!
33
//! Storage traits to allow on and off board storage devices to read and write
44
//! data.
5-
//!
6-
//! Implementation based on `Cuervo`s great work in
7-
//! https://www.ecorax.net/as-above-so-below-1/ and
8-
//! https://www.ecorax.net/as-above-so-below-2/
95
106
#![no_std]
117
#![deny(missing_docs)]
128
#![deny(unsafe_code)]
139

14-
use core::ops::{Add, Sub};
15-
use heapless::{consts::*, Vec};
16-
use nb;
17-
1810
/// Currently contains [`OverlapIterator`]
1911
pub mod iter;
20-
21-
/// An address denotes the read/write address of a single word.
22-
#[derive(Default, Copy, Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
23-
pub struct Address(pub u32);
24-
25-
impl Add<usize> for Address {
26-
type Output = Self;
27-
28-
fn add(self, rhs: usize) -> Self::Output {
29-
Address(self.0 + rhs as u32)
30-
}
31-
}
32-
33-
impl Add<isize> for Address {
34-
type Output = Self;
35-
36-
fn add(self, rhs: isize) -> Self::Output {
37-
Address((self.0 as isize + rhs) as u32)
38-
}
39-
}
40-
impl Sub<usize> for Address {
41-
type Output = Self;
42-
43-
fn sub(self, rhs: usize) -> Self::Output {
44-
Address(self.0 - rhs as u32)
45-
}
46-
}
47-
48-
impl Sub<isize> for Address {
49-
type Output = Self;
50-
51-
fn sub(self, rhs: isize) -> Self::Output {
52-
Address((self.0 as isize - rhs) as u32)
53-
}
54-
}
55-
56-
impl Sub<Address> for Address {
57-
type Output = Self;
58-
59-
fn sub(self, rhs: Address) -> Self::Output {
60-
Address(self.0 - rhs.0)
61-
}
62-
}
12+
/// Technology specific traits for NOR Flashes
13+
pub mod nor_flash;
6314

6415
/// A region denotes a contiguous piece of memory between two addresses.
6516
pub trait Region {
6617
/// Check if `address` is contained in the region of `Self`
67-
fn contains(&self, address: Address) -> bool;
18+
fn contains(&self, address: u32) -> bool;
6819
}
6920

70-
/// Transparent storage trait
71-
pub trait ReadWriteStorage {
21+
/// Transparent read only storage trait
22+
pub trait ReadStorage {
7223
/// An enumeration of storage errors
7324
type Error;
7425

7526
/// Read a slice of data from the storage peripheral, starting the read
76-
/// operation at the given address, and reading until end address
77-
/// (`self.range().1`) or buffer length, whichever comes first.
78-
fn try_read(&mut self, address: Address, bytes: &mut [u8]) -> nb::Result<(), Self::Error>;
79-
80-
/// Write a slice of data to the storage peripheral, starting the write
81-
/// operation at the given address.
82-
fn try_write(&mut self, address: Address, bytes: &[u8]) -> nb::Result<(), Self::Error>;
83-
84-
/// The range of possible addresses within the peripheral.
27+
/// operation at the given address offset, and reading `bytes.len()` bytes.
8528
///
86-
/// (start_addr, end_addr)
87-
fn range(&self) -> (Address, Address);
29+
/// This should throw an error in case `bytes.len()` will be larger than
30+
/// `self.capacity() - offset`.
31+
fn try_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error>;
8832

89-
/// Erase the given storage range, clearing all data within `[from..to]`.
90-
fn try_erase(&mut self, from: Address, to: Address) -> nb::Result<(), Self::Error>;
33+
/// The capacity of the storage peripheral in bytes.
34+
fn capacity(&self) -> usize;
9135
}
9236

93-
/// NOR flash region trait.
94-
pub trait NorFlashRegion {
95-
/// The range of possible addresses within the region.
96-
///
97-
/// (start_addr, end_addr)
98-
fn range(&self) -> (Address, Address);
99-
/// Maximum number of bytes that can be written at once.
100-
fn page_size(&self) -> usize;
101-
/// List of avalable erase sizes in this region.
102-
/// Should be sorted in ascending order.
103-
/// Currently limited to 5 sizes, but could be increased if necessary.
104-
fn erase_sizes(&self) -> Vec<usize, U5>;
105-
}
106-
107-
/// Blanket implementation for all types implementing [`NorFlashRegion`]
108-
impl<T: NorFlashRegion> Region for T {
109-
fn contains(&self, address: Address) -> bool {
110-
let (start, end) = self.range();
111-
address.0 >= start.0 && address.0 < end.0
112-
}
113-
}
114-
115-
/// NOR flash storage trait
116-
pub trait NorFlash {
117-
/// An enumeration of storage errors
118-
type Error;
119-
/// Region type
120-
type Region: NorFlashRegion;
121-
122-
/// Read a slice of data from the storage peripheral, starting the read
123-
/// operation at the given address, and reading until end address
124-
/// (`self.range().1`) or buffer length, whichever comes first.
125-
fn try_read(&mut self, address: Address, bytes: &mut [u8]) -> nb::Result<(), Self::Error>;
126-
37+
/// Transparent read/write storage trait
38+
pub trait Storage: ReadStorage {
12739
/// Write a slice of data to the storage peripheral, starting the write
128-
/// operation at the given address.
129-
///
130-
/// Since this is done on a NOR flash all bytes are anded with the current
131-
/// content in the flash. This means no 0s can to turned into 1s this way.
132-
fn try_write(&mut self, address: Address, bytes: &[u8]) -> nb::Result<(), Self::Error>;
133-
134-
/// Erase the given storage range, clearing all data within `[from..to]`.
135-
/// The given range will contain all 1s afterwards.
136-
///
137-
/// This should return an error if the range is not aligned to a proper
138-
/// erase resolution
139-
fn try_erase(&mut self, from: Address, to: Address) -> nb::Result<(), Self::Error>;
140-
141-
/// Get all distinct memory reagions. These must not overlap, but can be disjoint.
142-
/// Most chips will return a single region, but some chips have regions with
143-
/// different erase sizes.
144-
/// Currently limited to 4 regions, but could be increased if necessary
145-
fn regions(&self) -> Vec<Self::Region, U4>;
146-
}
147-
148-
/// Marker trait for NOR flashes with uniform erase and page sizes across the whole
149-
/// address range
150-
pub trait UniformNorFlash {}
151-
152-
/// Blanket implementation for all types implementing [`NorFlash`] and [`UniformNorFlash`]
153-
impl<T: NorFlash + UniformNorFlash> NorFlashRegion for T {
154-
/// The range of possible addresses within the peripheral.
40+
/// operation at the given address offset (between 0 and `self.capacity()`).
15541
///
156-
/// (start_addr, end_addr)
157-
fn range(&self) -> (Address, Address) {
158-
self.regions()[0].range()
159-
}
160-
/// Maximum number of bytes that can be written at once.
161-
fn page_size(&self) -> usize {
162-
self.regions()[0].page_size()
163-
}
164-
/// List of avalable erase sizes in this region.
165-
/// Should be sorted in ascending order.
166-
/// Currently limited to 5 sizes, but could be increased if necessary.
167-
fn erase_sizes(&self) -> Vec<usize, U5> {
168-
self.regions()[0].erase_sizes()
169-
}
42+
/// **NOTE:**
43+
/// This function will automatically erase any pages necessary to write the given data,
44+
/// and might as such do RMW operations at an undesirable performance impact.
45+
fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error>;
17046
}

src/nor_flash.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/// Read only NOR flash trait.
2+
pub trait ReadNorFlash {
3+
/// An enumeration of storage errors
4+
type Error;
5+
6+
/// The minumum number of bytes the storage peripheral can read
7+
const READ_SIZE: usize;
8+
9+
/// Read a slice of data from the storage peripheral, starting the read
10+
/// operation at the given address offset, and reading `bytes.len()` bytes.
11+
///
12+
/// This should throw an error in case `bytes.len()` will be larger than
13+
/// the peripheral end address.
14+
fn try_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error>;
15+
16+
/// The capacity of the peripheral in bytes.
17+
fn capacity(&self) -> usize;
18+
}
19+
20+
/// NOR flash trait.
21+
pub trait NorFlash: ReadNorFlash {
22+
/// The minumum number of bytes the storage peripheral can write
23+
const WRITE_SIZE: usize;
24+
25+
/// The minumum number of bytes the storage peripheral can erase
26+
const ERASE_SIZE: usize;
27+
28+
/// Erase the given storage range, clearing all data within `[from..to]`.
29+
/// The given range will contain all 1s afterwards.
30+
///
31+
/// This should return an error if the range is not aligned to a proper
32+
/// erase resolution
33+
/// If power is lost during erase, contents of the page are undefined.
34+
/// `from` and `to` must both be multiples of `ERASE_SIZE` and `from` <= `to`.
35+
fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error>;
36+
37+
/// If power is lost during write, the contents of the written words are undefined,
38+
/// but the rest of the page is guaranteed to be unchanged.
39+
/// It is not allowed to write to the same word twice.
40+
/// `offset` and `bytes.len()` must both be multiples of `WRITE_SIZE`.
41+
fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error>;
42+
}
43+
44+
/// Marker trait for NorFlash relaxing the restrictions on `write`.
45+
///
46+
/// Writes to the same word twice are now allowed. The result is the logical AND of the
47+
/// previous data and the written data. That is, it is only possible to change 1 bits to 0 bits.
48+
///
49+
/// If power is lost during write:
50+
/// - Bits that were 1 on flash and are written to 1 are guaranteed to stay as 1
51+
/// - Bits that were 1 on flash and are written to 0 are undefined
52+
/// - Bits that were 0 on flash are guaranteed to stay as 0
53+
/// - Rest of the bits in the page are guaranteed to be unchanged
54+
pub trait MultiwriteNorFlash: NorFlash {}

0 commit comments

Comments
 (0)