diff --git a/examples/write_verify.rs b/examples/write_verify.rs new file mode 100644 index 0000000..f3a47f0 --- /dev/null +++ b/examples/write_verify.rs @@ -0,0 +1,88 @@ +//! An STM32L073 example that measures write and erase times +//! +//! The flash chip is connected to SPI1 +//! + +#![no_std] +#![no_main] + +extern crate panic_semihosting; + +use cortex_m_rt::entry; +use cortex_m_semihosting::hprintln; + +use hex_display::HexDisplayExt; +use w25q::series25::Flash; + +use stm32l0xx_hal as hal; + +use crate::hal::{pac, prelude::*, rcc::Config, spi::MODE_0}; + +#[entry] +fn main() -> ! { + hprintln!("START"); + let p = pac::Peripherals::take().unwrap(); + let cp = cortex_m::Peripherals::take().unwrap(); + + let mut rcc = p.RCC.freeze(Config::hsi16()); + + let gpiob = p.GPIOB.split(&mut rcc); + + let sck = gpiob.pb3; + let miso = gpiob.pb4; + let mosi = gpiob.pb5; + let cs = gpiob.pb6.into_push_pull_output(); + + let spi = p + .SPI1 + .spi((sck, miso, mosi), MODE_0, 4_000_000.Hz(), &mut rcc); + + let mut flash = Flash::init(spi, cs).unwrap(); + let id = flash.read_jedec_id().unwrap(); + hprintln!("{:?}", id); + let mut fail_count = 0u32; + + const ITERATIONS: usize = 100; + for i in 0..ITERATIONS { + let mut inb = [0u8; 512]; + let mut inb_copy = [0u8; 512]; + let mut outb = [0u8; 512]; + for (n, b) in inb.iter_mut().enumerate() { + *b = (n + i) as u8; + } + inb_copy.copy_from_slice(&inb); + const ADDR: u32 = 0x0000_0000; + match i { + 0..=90 => { + hprintln!("sector erase"); + flash.erase_sectors(ADDR, 1).unwrap(); + } + 91..=98 => { + hprintln!("block erase"); + flash.erase_block(ADDR).unwrap(); + }, + 99..=100 => { + hprintln!("chip erase"); + flash.erase_all().unwrap(); + }, + _ => (), + } + // inb will get overwritten below! + flash.write_bytes(ADDR, &mut inb).unwrap(); + flash.read(ADDR, &mut outb).unwrap(); + if outb != inb_copy { + hprintln!("Failed verification"); + // hprintln!("wrote: {}", inb_copy.hex()); + // hprintln!("read: {}", outb.hex()); + fail_count += 1; + } + hprintln!("write iteration {}/{}", i, ITERATIONS); + } + + if fail_count > 0 { + hprintln!("num failures: {}", fail_count); + } + hprintln!("DONE"); + + loop {} +} diff --git a/src/series25.rs b/src/series25.rs index e7cd5b0..30860f5 100644 --- a/src/series25.rs +++ b/src/series25.rs @@ -233,14 +233,29 @@ impl, CS: OutputPin> Flash { } pub fn write_enable(&mut self) -> Result<(), Error> { - let mut cmd_buf = [Opcode::WriteEnable as u8]; - self.command(&mut cmd_buf)?; + while !self.read_status()?.contains(Status::WEL) { + let mut cmd_buf = [Opcode::WriteEnable as u8]; + self.command(&mut cmd_buf)?; + } Ok(()) } + // Wait for the BUSY flag to clear + // This function also handles the cases where the BUSY + // flag is not set yet (but expected) as well as when the + // BUSY flag is briefly unset to be set again shortly after. + // The latter behavior has been observed on the very popular + // Winbond chip W25Q128JV when executing a chip erase operation. fn wait_done(&mut self) -> Result<(), Error> { // TODO: Consider changing this to a delay based pattern - while self.read_status()?.contains(Status::BUSY) {} + let mut busy = true; + const RETRIES :usize = 10; + while busy { + busy = false; + for _ in 0..RETRIES { + busy |= self.read_status()?.contains(Status::BUSY); + } + } Ok(()) }