#![no_std]
#![doc = include_str!("../README.md")]
#![deny(unsafe_code)]
#![warn(missing_docs)]
use core::{fmt::Debug, marker::PhantomData};
use embedded_hal::digital::{OutputPin, PinState};
use embedded_storage::nor_flash::{ErrorType, NorFlashError, NorFlashErrorKind};
mod commands_impl;
pub struct Q;
pub struct X;
pub trait NorSeries {
const PAGE_SIZE: u32;
const SECTOR_SIZE: u32;
}
impl NorSeries for Q {
const PAGE_SIZE: u32 = 256;
const SECTOR_SIZE: u32 = Self::PAGE_SIZE * 16;
}
impl NorSeries for X {
const PAGE_SIZE: u32 = 256;
const SECTOR_SIZE: u32 = Self::PAGE_SIZE * 16;
}
pub trait Reset {}
impl Reset for Q {}
#[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,
}
pub struct W25<Series, SPI, HOLD, WP> {
spi: SPI,
hold: HOLD,
wp: WP,
capacity: u32,
_pantom: PhantomData<Series>,
}
impl<Series: NorSeries, SPI, HOLD, WP> W25<Series, SPI, HOLD, WP> {
pub fn capacity(&self) -> u32 {
self.capacity
}
fn n_sectors(&self) -> u32 {
self.capacity / Series::SECTOR_SIZE
}
fn n_blocks_32k(&self) -> u32 {
self.capacity / 32768
}
fn n_blocks_64k(&self) -> u32 {
self.capacity / 65536
}
}
impl<Series: NorSeries, SPI, S: Debug, P: Debug, HOLD, WP> W25<Series, 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, capacity: u32) -> Result<Self, P> {
let mut flash = W25 {
spi,
hold,
wp,
capacity,
_pantom: PhantomData,
};
flash.hold.set_high()?;
flash.wp.set_high()?;
Ok(flash)
}
pub fn set_hold(&mut self, value: PinState) -> Result<(), P> {
self.hold.set_state(value)
}
pub fn set_wp(&mut self, value: PinState) -> Result<(), P> {
self.wp.set_state(value)
}
}
impl<Series: NorSeries, SPI, S: Debug> W25<Series, SPI, (), ()>
where
SPI: embedded_hal::spi::ErrorType<Error = S>,
{
pub fn new_no_pins(spi: SPI, capacity: u32) -> Self {
Self {
spi,
hold: (),
wp: (),
capacity,
_pantom: PhantomData,
}
}
}
impl<Series: NorSeries, SPI, S: Debug, HOLD, WP> ErrorType for W25<Series, SPI, HOLD, WP>
where
SPI: embedded_hal::spi::ErrorType<Error = S>,
{
type Error = Error<S>;
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error<S: Debug> {
SpiError(S),
NotAligned,
OutOfBounds,
WriteEnableFail,
}
impl<S: Debug> NorFlashError for Error<S> {
fn kind(&self) -> NorFlashErrorKind {
match self {
Error::NotAligned => NorFlashErrorKind::NotAligned,
Error::OutOfBounds => NorFlashErrorKind::OutOfBounds,
_ => NorFlashErrorKind::Other,
}
}
}
#[allow(clippy::identity_op)]
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,
]
}