-
Notifications
You must be signed in to change notification settings - Fork 22
Adding support for the SPI stack chips #10
base: master
Are you sure you want to change the base?
Changes from 22 commits
06d9b55
08197ad
cbd5159
233effe
e28690d
e07ac1d
ceda1d6
4bfdf97
a3422c2
7a4755a
7e41934
8a518a0
e82af20
a2e816e
fd9b3bc
fa2488a
a6d2db2
816d9f1
8127c02
33834ca
4e3b729
e72f625
eebfde2
a446e71
1474850
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
//! Provides an implementation for switching between the two dies stacked upon each other inside the W25M series | ||
use crate::{BlockDevice, Error, Read}; | ||
use embedded_hal::blocking::spi::Transfer; | ||
use embedded_hal::digital::v2::OutputPin; | ||
use core::marker::PhantomData; | ||
use core::mem; | ||
|
||
#[allow(missing_debug_implementations)] | ||
pub struct Die0; | ||
#[allow(missing_debug_implementations)] | ||
pub struct Die1; | ||
|
||
/// All dies which are supposed to be supported by the W25M struct have to implement this trait | ||
pub trait Stackable<SPI: Transfer<u8>, CS: OutputPin>: BlockDevice<SPI, CS> + Read<SPI, CS> + Sized { | ||
fn new(spi: SPI, cs: CS) -> Result<Self, Error<SPI, CS>>; | ||
/// Returns the SPI and chip select objects so they can be used elsewhere | ||
fn free(self) -> (SPI, CS); | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct Flash<DIE0, DIE1, DIE> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add documentation to this type that explains what the type parameters are for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. If you bound it by a trait that is only implemented by the 2 types that are supposed to be used though, users wouldn't be able to name invalid There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean technically the user is just supposed to _ the type state as the constructor only produces Die0 types, so if a user starts to mess around with the state parameter he is most likely doing something wrong isn't he? |
||
{ | ||
inner: Inner<DIE0, DIE1>, | ||
_die: PhantomData<DIE>, | ||
} | ||
|
||
#[derive(Debug)] | ||
enum Inner<DIE0, DIE1> { | ||
Die0(DIE0), | ||
Die1(DIE1), | ||
Dummy, | ||
} | ||
|
||
impl<DIE0, DIE1> Flash<DIE0, DIE1, Die0> | ||
{ | ||
/// Creates a new W25M device | ||
/// | ||
/// At | ||
/// the moment the only way to call this function is sadly | ||
/// ``` | ||
/// let mut flash: Flash<W25N<_, _>, W25N<_, _>, _> = Flash::init(spi, cs).unwrap(); | ||
/// ``` | ||
/// TODO: Improve this API, its not very convenient | ||
pub fn init<SPI, CS>(spi: SPI, cs: CS) -> Result<Flash<DIE0, DIE1, Die0>, Error<SPI, CS>> | ||
where | ||
SPI: Transfer<u8>, | ||
CS: OutputPin, | ||
DIE0: Stackable<SPI, CS>, | ||
DIE1: Stackable<SPI, CS>, | ||
{ | ||
Ok(Flash{ | ||
inner: Inner::Die0(DIE0::new(spi, cs)?), | ||
_die: PhantomData | ||
}) | ||
} | ||
} | ||
|
||
impl<DIE0, DIE1> Flash<DIE0, DIE1, Die0> | ||
|
||
{ | ||
pub fn switch_die<SPI, CS>(mut self) -> Result<Flash<DIE0, DIE1, Die1>, Error<SPI, CS>> | ||
where DIE0: Stackable<SPI, CS>, | ||
DIE1: Stackable<SPI, CS>, | ||
SPI: Transfer<u8>, | ||
CS: OutputPin { | ||
let (mut spi, mut cs) = match mem::replace(&mut self.inner, Inner::Dummy) { | ||
Inner::Die0(die) => die.free(), | ||
_ => unreachable!() | ||
}; | ||
let mut command = [0xC2, 0x01]; | ||
cs.set_low().map_err(Error::Gpio)?; | ||
let spi_result = spi.transfer(&mut command).map_err(Error::Spi); | ||
cs.set_high().map_err(Error::Gpio)?; | ||
spi_result?; | ||
|
||
Ok(Flash{ | ||
inner: Inner::Die1(DIE1::new(spi, cs)?), | ||
_die: PhantomData | ||
}) | ||
} | ||
} | ||
|
||
impl<DIE0, DIE1> Flash<DIE0, DIE1, Die1> | ||
{ | ||
pub fn switch_die<SPI, CS>(mut self) -> Result<Flash<DIE0, DIE1, Die0>, Error<SPI, CS>> | ||
where DIE0: Stackable<SPI, CS>, | ||
DIE1: Stackable<SPI, CS>, | ||
SPI: Transfer<u8>, | ||
CS: OutputPin | ||
{ | ||
let (mut spi, mut cs) = match mem::replace(&mut self.inner, Inner::Dummy) { | ||
Inner::Die1(die) => die.free(), | ||
_ => unreachable!() | ||
}; | ||
|
||
let mut command = [0xC2, 0x00]; | ||
cs.set_low().map_err(Error::Gpio)?; | ||
let spi_result = spi.transfer(&mut command).map_err(Error::Spi); | ||
cs.set_high().map_err(Error::Gpio)?; | ||
spi_result?; | ||
|
||
|
||
Ok(Flash{ | ||
inner: Inner::Die0(DIE0::new(spi, cs)?), | ||
_die: PhantomData | ||
}) | ||
} | ||
} | ||
hargoniX marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
impl<DIE0, DIE1, SPI, CS, DIE> BlockDevice<SPI, CS> for Flash<DIE0, DIE1, DIE> | ||
where DIE0: Stackable<SPI, CS>, | ||
DIE1: Stackable<SPI, CS>, | ||
SPI: Transfer<u8>, | ||
CS: OutputPin | ||
{ | ||
fn erase(&mut self, addr: u32, amount: usize) -> Result<(), Error<SPI, CS>> { | ||
match &mut self.inner { | ||
Inner::Die0(die) => die.erase(addr, amount), | ||
Inner::Die1(die) => die.erase(addr, amount), | ||
_ => unreachable!() | ||
} | ||
} | ||
|
||
fn erase_all(&mut self) -> Result<(), Error<SPI, CS>> { | ||
match &mut self.inner { | ||
Inner::Die0(die) => die.erase_all(), | ||
Inner::Die1(die) => die.erase_all(), | ||
_ => unreachable!() | ||
} | ||
} | ||
|
||
fn write_bytes(&mut self, addr: u32, data: &mut [u8]) -> Result<(), Error<SPI, CS>> { | ||
match &mut self.inner { | ||
Inner::Die0(die) => die.write_bytes(addr, data), | ||
Inner::Die1(die) => die.write_bytes(addr, data), | ||
_ => unreachable!() | ||
} | ||
} | ||
} | ||
|
||
impl<DIE0, DIE1, SPI, CS, DIE> Read<SPI, CS> for Flash<DIE0, DIE1, DIE> | ||
where DIE0: Stackable<SPI, CS>, | ||
DIE1: Stackable<SPI, CS>, | ||
SPI: Transfer<u8>, | ||
CS: OutputPin | ||
{ | ||
fn read(&mut self, addr: u32, buf: &mut [u8]) -> Result<(), Error<SPI, CS>> { | ||
match &mut self.inner { | ||
Inner::Die0(die) => die.read(addr, buf), | ||
Inner::Die1(die) => die.read(addr, buf), | ||
_ => unreachable!() | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These can just
#[derive(Debug)]
, there shouldn't be any harm in thatThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also make them
enum
s instead ofstruct
s since they're just used as type markers