#![no_std]
#![deny(unsafe_code)]
use core::fmt::Debug;
use embedded_hal::digital::{OutputPin, PinState};
use embedded_storage::nor_flash::{ErrorType, NorFlashError, NorFlashErrorKind};
mod is25lp064a;
#[cfg(feature = "async")]
mod is25lp064a_async;
pub const PAGE_SIZE: u32 = 256;
pub const N_PAGES: u32 = 32768;
pub const CAPACITY: u32 = PAGE_SIZE * N_PAGES;
pub const SECTOR_SIZE: u32 = PAGE_SIZE * 16;
pub const N_SECTORS: u32 = N_PAGES / 16;
pub const BLOCK_32K_SIZE: u32 = SECTOR_SIZE * 8;
pub const N_BLOCKS_32K: u32 = N_SECTORS / 8;
pub const BLOCK_64K_SIZE: u32 = BLOCK_32K_SIZE * 2;
pub const N_BLOCKS_64K: u32 = N_BLOCKS_32K / 2;
pub struct Is25lp064a<SPI, HOLD, WP> {
spi: SPI,
hold: HOLD,
wp: WP,
}
impl<SPI, HOLD, WP> Is25lp064a<SPI, HOLD, WP> {
pub fn capacity() -> usize {
CAPACITY as usize
}
}
impl<SPI, S: Debug, P: Debug, HOLD, WP> Is25lp064a<SPI, HOLD, WP>
where
SPI: embedded_hal::spi::ErrorType<Error = S>,
HOLD: OutputPin<Error = P>,
WP: OutputPin<Error = P>,
{
pub fn new(spi: SPI, hold: HOLD, wp: WP) -> Result<Self, Error<S, P>> {
let mut flash = Is25lp064a { spi, hold, wp };
flash.hold.set_high().map_err(Error::PinError)?;
flash.wp.set_high().map_err(Error::PinError)?;
Ok(flash)
}
pub fn set_hold(&mut self, value: PinState) -> Result<(), Error<S, P>> {
self.hold.set_state(value).map_err(Error::PinError)?;
Ok(())
}
pub fn set_wp(&mut self, value: PinState) -> Result<(), Error<S, P>> {
self.wp.set_state(value).map_err(Error::PinError)?;
Ok(())
}
}
impl<SPI, S: Debug, P: Debug, HOLD, WP> ErrorType for Is25lp064a<SPI, HOLD, WP>
where
SPI: embedded_hal::spi::ErrorType<Error = S>,
HOLD: OutputPin<Error = P>,
WP: OutputPin<Error = P>,
{
type Error = Error<S, P>;
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error<S: Debug, P: Debug> {
SpiError(S),
PinError(P),
NotAligned,
OutOfBounds,
WriteEnableFail,
ReadbackFail,
}
impl<S: Debug, P: Debug> NorFlashError for Error<S, P> {
fn kind(&self) -> NorFlashErrorKind {
match self {
Error::NotAligned => NorFlashErrorKind::NotAligned,
Error::OutOfBounds => NorFlashErrorKind::OutOfBounds,
_ => NorFlashErrorKind::Other,
}
}
}
#[repr(u8)]
enum Command {
PageProgram = 0x02,
ReadData = 0x03,
ReadStatusRegister1 = 0x05,
WriteEnable = 0x06,
SectorErase = 0x20,
UniqueId = 0x4B,
Block32Erase = 0x52,
Block64Erase = 0xD8,
ChipErase = 0xC7,
EnableReset = 0x66,
PowerDown = 0xB9,
ReleasePowerDown = 0xAB,
Reset = 0x99,
}
fn command_and_address(command: u8, address: u32) -> [u8; 4] {
[
command,
((address & 0xFF0000) >> 16) as u8,
((address & 0x00FF00) >> 8) as u8,
((address & 0x0000FF) >> 0) as u8,
]
}