From f7d3135ec76051a0d1b04c35e60c5d4b78cdfcbf Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Wed, 5 Aug 2020 20:10:30 +0800 Subject: [PATCH] i2c: implement EEPROM operations; add CountDown waiting indication --- libboard_zynq/src/i2c/eeprom.rs | 84 +++++++++++++++++++++++++++++++ libboard_zynq/src/i2c/mod.rs | 3 +- libboard_zynq/src/timer/global.rs | 9 ++++ 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 libboard_zynq/src/i2c/eeprom.rs diff --git a/libboard_zynq/src/i2c/eeprom.rs b/libboard_zynq/src/i2c/eeprom.rs new file mode 100644 index 0000000..f7987c1 --- /dev/null +++ b/libboard_zynq/src/i2c/eeprom.rs @@ -0,0 +1,84 @@ +use super::I2C; +use crate::time::Microseconds; +use embedded_hal::timer::CountDown; + +pub struct EEPROM<'a> { + i2c: &'a mut I2C, + port: u8, + address: u8, +} + +impl<'a> EEPROM<'a> { + #[cfg(feature = "target_zc706")] + pub fn new(i2c: &'a mut I2C) -> Self { + EEPROM { + i2c: i2c, + port: 2, + address: 0b1010100, + } + } + + #[cfg(feature = "target_zc706")] + fn select(&mut self) -> Result<(), &'static str> { + let mask: u16 = 1 << self.port; + self.i2c.pca9548_select(0b1110100, mask as u8)?; + Ok(()) + } + + /// Random read + pub fn read<'r>(&mut self, addr: u8, buf: &'r mut [u8]) -> Result<(), &'static str> { + self.select()?; + + self.i2c.start()?; + self.i2c.write(self.address << 1)?; + self.i2c.write(addr)?; + + self.i2c.restart()?; + self.i2c.write((self.address << 1) | 1)?; + let buf_len = buf.len(); + for (i, byte) in buf.iter_mut().enumerate() { + *byte = self.i2c.read(i < buf_len - 1)?; + } + + self.i2c.stop()?; + + Ok(()) + } + + /// Page write + pub fn write(&mut self, addr: u8, buf: &[u8]) -> Result<(), &'static str> { + self.select()?; + + self.i2c.start()?; + self.i2c.write(self.address << 1)?; + self.i2c.write(addr)?; + for (i, byte) in buf.iter().enumerate() { + self.i2c.write(*byte)?; + } + + self.i2c.stop()?; + self.poll(1_000_000_000)?; + + Ok(()) + } + + /// Poll + pub fn poll(&mut self, timeout_us: u64) -> Result<(), &'static str> { + self.select()?; + + self.i2c.count_down.start(Microseconds(timeout_us)); + while !self.i2c.write((self.address << 1) | 1)? { + if !self.i2c.count_down.waiting() { + return Err("I2C polling timeout") + } + } + + Ok(()) + } + + pub fn read_eui48<'r>(&mut self) -> Result<[u8; 6], &'static str> { + let mut buffer = [0u8; 6]; + self.read(0xFA, &mut buffer)?; + Ok(buffer) + } +} \ No newline at end of file diff --git a/libboard_zynq/src/i2c/mod.rs b/libboard_zynq/src/i2c/mod.rs index e10ec80..24ef31f 100644 --- a/libboard_zynq/src/i2c/mod.rs +++ b/libboard_zynq/src/i2c/mod.rs @@ -1,8 +1,7 @@ //! I2C Bit-banging Controller mod regs; -use log::{error, info, warn}; -use crate::{print, println}; +pub mod eeprom; use super::clocks::Clocks; use super::slcr; use super::time::Microseconds; diff --git a/libboard_zynq/src/timer/global.rs b/libboard_zynq/src/timer/global.rs index 9b46c79..1875e76 100644 --- a/libboard_zynq/src/timer/global.rs +++ b/libboard_zynq/src/timer/global.rs @@ -138,6 +138,15 @@ where } } +impl CountDown +where + GlobalTimer: TimeSource, +{ + pub fn waiting(&self) -> bool { + self.timer.now() <= self.timeout + } +} + /// embedded-hal sync API impl embedded_hal::blocking::delay::DelayMs for GlobalTimer { fn delay_ms(&mut self, ms: u64) {