re-work NVM interface
This commit is contained in:
parent
0f3614465f
commit
a1a5156caf
@ -2,12 +2,15 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use core::fmt::write;
|
||||
|
||||
use cortex_m::{asm, register::control::read};
|
||||
use cortex_m_rt::entry;
|
||||
use embedded_hal::delay::DelayNs;
|
||||
use panic_rtt_target as _;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use va108xx_hal::{pac, pwm::CountDownTimer, time::Hertz};
|
||||
use vorago_reb1::m95m01::M95M01;
|
||||
use vorago_reb1::m95m01::{M95M01, PAGE_SIZE};
|
||||
|
||||
const CLOCK_FREQ: Hertz = Hertz::from_raw(50_000_000);
|
||||
|
||||
@ -25,39 +28,30 @@ fn main() -> ! {
|
||||
panic!("status register unexpected values");
|
||||
}
|
||||
|
||||
let mut orig_content: [u8; 16] = [0; 16];
|
||||
let mut read_buf: [u8; 16] = [0; 16];
|
||||
let write_buf: [u8; 16] = [0; 16];
|
||||
for (idx, val) in read_buf.iter_mut().enumerate() {
|
||||
*val = idx as u8;
|
||||
let mut orig_content: [u8; 512] = [0; 512];
|
||||
let mut read_buf: [u8; 512] = [0; 512];
|
||||
let mut write_buf: [u8; 512] = [0; 512];
|
||||
for (idx, val) in write_buf.iter_mut().enumerate() {
|
||||
*val = ((idx as u16) % (u8::MAX as u16 + 1)) as u8;
|
||||
}
|
||||
nvm.read(0x4000, &mut orig_content).unwrap();
|
||||
nvm.read(0, &mut orig_content).unwrap();
|
||||
|
||||
// One byte write and read.
|
||||
nvm.write(0x4000, &write_buf[0..1]).unwrap();
|
||||
nvm.read(0x4000, &mut read_buf[0..1]).unwrap();
|
||||
assert_eq!(write_buf[0], read_buf[0]);
|
||||
read_buf.fill(0);
|
||||
nvm.write_page(0, 0, &[1, 2, 3, 4]).unwrap();
|
||||
nvm.read(0, &mut read_buf[0..4]).unwrap();
|
||||
|
||||
// Four bytes write and read.
|
||||
nvm.write(0x4000, &write_buf[0..4]).unwrap();
|
||||
nvm.read(0x4000, &mut read_buf[0..4]).unwrap();
|
||||
assert_eq!(&read_buf[0..4], &write_buf[0..4]);
|
||||
read_buf.fill(0);
|
||||
|
||||
// Full sixteen bytes
|
||||
nvm.write(0x4000, &write_buf).unwrap();
|
||||
nvm.read(0x4000, &mut read_buf).unwrap();
|
||||
// Read the whole content. Write will internally be split across two page bounaries.
|
||||
nvm.write(0, &write_buf).unwrap();
|
||||
// Memory can be read in one go.
|
||||
nvm.read(0, &mut read_buf).unwrap();
|
||||
assert_eq!(&read_buf, &write_buf);
|
||||
read_buf.fill(0);
|
||||
|
||||
// 3 bytes
|
||||
nvm.write(0x4000, &write_buf[0..3]).unwrap();
|
||||
nvm.read(0x4000, &mut read_buf[0..3]).unwrap();
|
||||
assert_eq!(&read_buf[0..3], &write_buf[0..3]);
|
||||
// Write along page boundary
|
||||
nvm.write(PAGE_SIZE - 2, &write_buf[0..8]).unwrap();
|
||||
nvm.read(PAGE_SIZE - 2, &mut read_buf[0..8]).unwrap();
|
||||
assert_eq!(&read_buf[0..8], &write_buf[0..8]);
|
||||
|
||||
// Write back original content.
|
||||
nvm.write(0x4000, &orig_content).unwrap();
|
||||
nvm.write(0, &orig_content);
|
||||
loop {
|
||||
timer.delay_ms(500);
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
use core::convert::Infallible;
|
||||
use embedded_hal::spi::SpiBus;
|
||||
|
||||
pub const PAGE_SIZE: usize = 256;
|
||||
|
||||
bitfield::bitfield! {
|
||||
pub struct StatusReg(u8);
|
||||
impl Debug;
|
||||
@ -53,6 +55,9 @@ pub struct M95M01 {
|
||||
pub spi: RomSpi,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct PageBoundaryExceededError;
|
||||
|
||||
impl M95M01 {
|
||||
pub fn new(syscfg: &mut pac::Sysconfig, sys_clk: impl Into<Hertz>, spi: pac::Spic) -> Self {
|
||||
let spi = RomSpi::new(
|
||||
@ -105,7 +110,7 @@ impl M95M01 {
|
||||
self.spi.write(&[WRSR, reg.0])
|
||||
}
|
||||
|
||||
fn common_init_write_and_read(&mut self, address: u32, reg: u8) -> Result<(), Infallible> {
|
||||
fn common_init_write_and_read(&mut self, address: usize, reg: u8) -> Result<(), Infallible> {
|
||||
nb::block!(self.writes_are_done())?;
|
||||
self.spi.flush()?;
|
||||
if reg == WRITE {
|
||||
@ -114,13 +119,14 @@ impl M95M01 {
|
||||
} else {
|
||||
self.spi.write_fifo_unchecked(READ as u32);
|
||||
}
|
||||
self.spi.write_fifo_unchecked((address >> 16) & 0xff);
|
||||
self.spi.write_fifo_unchecked((address >> 8) & 0xff);
|
||||
self.spi.write_fifo_unchecked(address & 0xff);
|
||||
self.spi.write_fifo_unchecked((address as u32 >> 16) & 0xff);
|
||||
self.spi
|
||||
.write_fifo_unchecked((address as u32 & 0x00ff00) >> 8);
|
||||
self.spi.write_fifo_unchecked(address as u32 & 0xff);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn common_read(&mut self, address: u32) -> Result<(), Infallible> {
|
||||
fn common_read(&mut self, address: usize) -> Result<(), Infallible> {
|
||||
self.common_init_write_and_read(address, READ)?;
|
||||
for _ in 0..4 {
|
||||
// Pump the FIFO.
|
||||
@ -131,24 +137,60 @@ impl M95M01 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write(&mut self, address: u32, data: &[u8]) -> Result<(), Infallible> {
|
||||
self.common_init_write_and_read(address, WRITE)?;
|
||||
pub fn write(&mut self, mut address: usize, mut data: &[u8]) -> Result<(), Infallible> {
|
||||
// Loop until all data is written
|
||||
while !data.is_empty() {
|
||||
// Calculate the page and the offset within the page from the address
|
||||
let page = address / PAGE_SIZE;
|
||||
let offset = address % PAGE_SIZE;
|
||||
|
||||
// Calculate how much space is left in the current page
|
||||
let space_left = PAGE_SIZE - offset;
|
||||
|
||||
// Determine how much data to write in the current page
|
||||
let to_write = data.len().min(space_left);
|
||||
|
||||
// Write the current portion of the data
|
||||
self.write_page(page, offset, &data[..to_write]).unwrap();
|
||||
|
||||
// Update the address and data for the next iteration
|
||||
address += to_write;
|
||||
data = &data[to_write..];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_page(
|
||||
&mut self,
|
||||
page: usize,
|
||||
offset: usize,
|
||||
data: &[u8],
|
||||
) -> Result<(), PageBoundaryExceededError> {
|
||||
// Check that the total data to be written does not exceed the page boundary
|
||||
if offset + data.len() > PAGE_SIZE {
|
||||
return Err(PageBoundaryExceededError);
|
||||
}
|
||||
|
||||
self.common_init_write_and_read(page * PAGE_SIZE + offset, WRITE)
|
||||
.unwrap();
|
||||
for val in data.iter().take(data.len() - 1) {
|
||||
nb::block!(self.spi.write_fifo(*val as u32))?;
|
||||
nb::block!(self.spi.write_fifo(*val as u32)).unwrap();
|
||||
self.spi.read_fifo_unchecked();
|
||||
}
|
||||
nb::block!(self
|
||||
.spi
|
||||
.write_fifo(*data.last().unwrap() as u32 | BMSTART_BMSTOP_MASK))?;
|
||||
self.spi.flush()?;
|
||||
nb::block!(self.writes_are_done())?;
|
||||
.write_fifo(*data.last().unwrap() as u32 | BMSTART_BMSTOP_MASK))
|
||||
.unwrap();
|
||||
self.spi.flush().unwrap();
|
||||
nb::block!(self.writes_are_done()).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read(&mut self, address: u32, buf: &mut [u8]) -> Result<(), Infallible> {
|
||||
pub fn read(&mut self, address: usize, buf: &mut [u8]) -> Result<(), Infallible> {
|
||||
self.common_read(address)?;
|
||||
for val in buf.iter_mut() {
|
||||
nb::block!(self.spi.write_fifo(0))?;
|
||||
self.spi.write_fifo_unchecked(0);
|
||||
*val = (nb::block!(self.spi.read_fifo()).unwrap() & 0xff) as u8;
|
||||
}
|
||||
nb::block!(self.spi.write_fifo(BMSTART_BMSTOP_MASK))?;
|
||||
@ -156,10 +198,10 @@ impl M95M01 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn verify(&mut self, address: u32, data: &[u8]) -> Result<bool, Infallible> {
|
||||
pub fn verify(&mut self, address: usize, data: &[u8]) -> Result<bool, Infallible> {
|
||||
self.common_read(address)?;
|
||||
for val in data.iter() {
|
||||
nb::block!(self.spi.write_fifo(0))?;
|
||||
self.spi.write_fifo_unchecked(0);
|
||||
let read_val = (nb::block!(self.spi.read_fifo()).unwrap() & 0xff) as u8;
|
||||
if read_val != *val {
|
||||
return Ok(false);
|
||||
|
Loading…
Reference in New Issue
Block a user