Commit fae8c121 authored by A Sundbom's avatar A Sundbom
Browse files

Merge branch 'eeprom' into 'master'

EEPROM Driver

See merge request axel.sundbom/lpc43xx-hal!4
Showing with 250 additions and 4 deletions
+250 -4
[package]
name = "lpc43xx-hal"
version = "0.2.0"
authors = ["Axel Sundbom <axel.sundbom@grepit.se>", "Nils Fitinghoff <nils.fitinghoff@grepit.se>"]
version = "0.2.1"
authors = ["Axel Sundbom <axel.sundbom@grepit.se>", "Nils Fitinghoff <nils.fitinghoff@grepit.se>", "Emil Kitti <emil.kitti@grepit.se>"]
edition = "2018"
repository = "https://git.grepit.se/axel.sundbom/lpc43xx-hal.git"
......
#![no_main]
#![no_std]
extern crate panic_halt;
use cortex_m::asm;
use rtfm::app;
use lpc43xx_hal as driver;
use driver::eeprom;
use driver::eeprom::{Read, Write};
use driver::time::U32Ext;
#[app(device = lpc43xx_pac)]
const APP: () = {
static mut EEPROM: eeprom::EEPROM = ();
#[init]
fn init() -> init::LateResources {
let eeprom_reg = device.EEPROM;
let eeprom = eeprom::EEPROM::new(eeprom_reg, 12.mhz());
init::LateResources {
EEPROM: eeprom,
}
}
#[idle(resources = [EEPROM])]
fn idle() -> ! {
let eeprom = resources.EEPROM;
let write_data: [u32; 8] = [1,2,3,4,5,6,7,8];
let mut read_buffer: [u32; 8] = [0; 8];
eeprom.write(29, &write_data);
eeprom.read(29, &mut read_buffer);
asm::bkpt();
assert!(
write_data == read_buffer,
"Data should be the same");
loop {
cortex_m::asm::wfi();
}
}
};
......@@ -15,7 +15,6 @@ use driver::time::U32Ext;
#[app(device = lpc43xx_pac)]
const APP: () = {
static mut TEST: u32 = ();
static mut I2C: i2c::I2C = ();
#[init]
......@@ -44,7 +43,6 @@ const APP: () = {
12.mhz());
init::LateResources {
TEST: 32,
I2C: i2c,
}
}
......
src/eeprom.rs 0 → 100644
use core::ptr;
use crate::pac;
use crate::time::{MegaHertz, KiloHertz, Hertz};
const EEPROM_START: u32 = 0x2004_0000;
const EEPROM_PAGE_SIZE: u32 = 32;
const EEPROM_PAGES: u32 = 128;
const EEPROM_SIZE: u32 = EEPROM_PAGES * EEPROM_PAGE_SIZE;
const EEPROM_OPTIMAL_CLK_SPEED: KiloHertz = KiloHertz(1500);
/// EEPROM Write trait
pub trait Write {
type Error;
/// Write to a specific word aligned eepprom address.
fn write(&mut self, addr: u32, data: &[u32]) -> Result<(), Self::Error>;
}
/// EEPROM Read trait
pub trait Read {
type Error;
/// Read from a specific word aligned eepprom address.
fn read(&mut self, addr: u32, buffer: &mut [u32]) -> Result<(), Self::Error>;
}
/// The different programming modes the EEPROM can be in.
pub enum AutoProgramming {
Manual = 0b00,
AutoSingle = 0b01,
AutoLast = 0b10,
}
/// The power states the EEPROM can be in.
pub enum PowerState {
On,
Off,
}
/// Errors which EEPROM can return.
pub enum EEPROMError {
PageDoesNotExist,
PageOutOfBounds,
OutOfBounds,
OutOfPage
}
/// EEPROM struct.
pub struct EEPROM {
peripheral: pac::EEPROM,
}
impl EEPROM {
/// Create a new instance of EEPROM.
pub fn new(p: pac::EEPROM, pclk: MegaHertz) -> Self {
let pclk_hz: Hertz = pclk.into();
let opt_clk_hz: Hertz = EEPROM_OPTIMAL_CLK_SPEED.into();
let clk_div = (pclk_hz.0 / opt_clk_hz.0 - 1) as u16;
p.clkdiv.modify(|_, w| unsafe {
w.
clkdiv().bits(clk_div)
});
EEPROM {
peripheral: p,
}
}
/// Set the power state of the EEPROM.
pub fn power_state(&self, ps: PowerState) {
self.peripheral.pwrdwn.modify(|_, w| {
match ps {
PowerState::Off => {
w.pwrdwn().set_bit()
},
PowerState::On | _ => {
w.pwrdwn().clear_bit()
},
}
});
}
/// Start programming/erasing the EEPROM.
pub fn start_programming(&self) {
self.peripheral.cmd.modify(|_, w| unsafe {
w.
// start a erase/program page
cmd().bits(0b110)
});
}
/// Set the autoporgramming mode.
pub fn auto_prog(&self, auto_prog: AutoProgramming) {
self.peripheral.autoprog.modify(|_, w| unsafe {
w.
autoprog().bits(auto_prog as u8)
});
}
/// Write some data to a specific page in the EEPROM.
pub fn write_to_page(&self, page: u32, offset: u32, data: &[u32]) -> Result<(), EEPROMError> {
self.auto_prog(AutoProgramming::Manual);
if page > EEPROM_PAGES {
return Err(EEPROMError::PageDoesNotExist)
};
if offset + (data.len() as u32) > EEPROM_PAGE_SIZE {
return Err(EEPROMError::PageOutOfBounds);
};
let addr = EEPROM_START + page * EEPROM_PAGE_SIZE + offset * 4;
// Write the data to EEPROM registers
for (i, d) in data.iter().enumerate() {
unsafe {
ptr::write_volatile((addr + (i as u32)*4) as *mut u32, *d);
}
}
// Start the EEPROM programming
self.start_programming();
// Wait for the page to be written.
while {
self.peripheral.intstat.read().end_of_prog().bit_is_clear()
} {}
// Clear interrupt register
self.peripheral.intstatclr.write(|w| w.prog_clr_st().set_bit());
Ok(())
}
}
impl Write for EEPROM {
type Error = EEPROMError;
fn write(&mut self, addr: u32, mut data: &[u32]) -> Result<(), Self::Error> {
if addr >= EEPROM_SIZE {
return Err(EEPROMError::OutOfBounds);
};
let start_page = addr / EEPROM_PAGE_SIZE;
let start_page_offset = addr % EEPROM_PAGE_SIZE;
let left_of_page = EEPROM_PAGE_SIZE - start_page_offset;
if (data.len() as u32) < left_of_page {
self.write_to_page(start_page, start_page_offset, data)?;
} else {
self.write_to_page(
start_page,
start_page_offset,
&data[0..(left_of_page as usize)])?;
data = &data[(left_of_page as usize)..];
for (i, chunk) in data.chunks(EEPROM_PAGE_SIZE as usize).enumerate() {
self.write_to_page(start_page + (i as u32) + 1, 0, chunk)?;
}
}
Ok(())
}
}
impl Read for EEPROM {
type Error = EEPROMError;
fn read(&mut self, addr: u32, buffer: &mut [u32]) -> Result<(), Self::Error> {
if addr >= EEPROM_SIZE {
return Err(EEPROMError::OutOfBounds);
};
for (i, b) in buffer.iter_mut().enumerate() {
*b = unsafe {
ptr::read_volatile((EEPROM_START + addr*4 + (i as u32)*4) as *mut u32)
}
}
Ok(())
}
}
......@@ -28,6 +28,8 @@ pub mod spi;
pub mod time;
/// Basic 16-bit timers
pub mod timer;
/// EEPROM
pub mod eeprom;
/// MAX11253 ADC Support
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment