i2c: fix GPIO register mapping, I2C control & EEPROM write operations
This commit is contained in:
parent
f7d3135ec7
commit
16b2df91ca
|
@ -1,20 +1,24 @@
|
|||
use super::I2C;
|
||||
use crate::time::Microseconds;
|
||||
use crate::time::Milliseconds;
|
||||
use embedded_hal::timer::CountDown;
|
||||
|
||||
pub struct EEPROM<'a> {
|
||||
i2c: &'a mut I2C,
|
||||
port: u8,
|
||||
address: u8,
|
||||
page_size: u8,
|
||||
count_down: crate::timer::global::CountDown<Milliseconds>
|
||||
}
|
||||
|
||||
impl<'a> EEPROM<'a> {
|
||||
#[cfg(feature = "target_zc706")]
|
||||
pub fn new(i2c: &'a mut I2C) -> Self {
|
||||
pub fn new(i2c: &'a mut I2C, page_size: u8) -> Self {
|
||||
EEPROM {
|
||||
i2c: i2c,
|
||||
port: 2,
|
||||
address: 0b1010100,
|
||||
page_size: page_size,
|
||||
count_down: unsafe { crate::timer::GlobalTimer::get() }.countdown()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,30 +49,49 @@ impl<'a> EEPROM<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Page write
|
||||
/// Smart multi-page writing
|
||||
/// Using the "Page Write" function of an EEPROM, the memory region for each transaction
|
||||
/// (i.e. from byte `addr` to byte `addr+buf.len()`) should fit under each page
|
||||
/// (i.e. `addr+buf.len()` < `addr/self.page_size+1`); otherwise, a roll-oever occurs,
|
||||
/// where bytes beyond the page end. This smart function takes care of the scenario to avoid
|
||||
/// any roll-over when writing ambiguous memory regions.
|
||||
pub fn write(&mut self, addr: u8, buf: &[u8]) -> Result<(), &'static str> {
|
||||
self.select()?;
|
||||
|
||||
let buf_len = buf.len();
|
||||
let mut pb: u8 = addr % self.page_size;
|
||||
for (i, byte) in buf.iter().enumerate() {
|
||||
if (i == 0) || (pb == 0) {
|
||||
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.write(addr + (i as u8))?;
|
||||
}
|
||||
self.i2c.write(*byte)?;
|
||||
pb += 1;
|
||||
|
||||
if (i == buf_len-1) || (pb == self.page_size) {
|
||||
self.i2c.stop()?;
|
||||
self.poll(1_000_000_000)?;
|
||||
self.poll(1_000)?;
|
||||
pb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Poll
|
||||
pub fn poll(&mut self, timeout_us: u64) -> Result<(), &'static str> {
|
||||
pub fn poll(&mut self, timeout_ms: 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() {
|
||||
self.count_down.start(Milliseconds(timeout_ms));
|
||||
loop {
|
||||
self.i2c.start()?;
|
||||
let ack = self.i2c.write(self.address << 1)?;
|
||||
self.i2c.stop()?;
|
||||
if ack {
|
||||
break
|
||||
};
|
||||
if !self.count_down.waiting() {
|
||||
return Err("I2C polling timeout")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,11 @@ use libregister::{RegisterR, RegisterRW, RegisterW};
|
|||
|
||||
const INVALID_BUS: &'static str = "Invalid I2C bus";
|
||||
|
||||
#[cfg(feature = "target_zc706")]
|
||||
const GPIO_OUTPUT_MASK: u16 = 0xFFFF - 0x000C;
|
||||
|
||||
pub struct I2C {
|
||||
regs: regs::RegisterBlock,
|
||||
regs: regs::RegisterWrapper,
|
||||
count_down: super::timer::global::CountDown<Microseconds>
|
||||
}
|
||||
|
||||
|
@ -23,17 +26,21 @@ impl I2C {
|
|||
// SCL
|
||||
slcr.mio_pin_50.write(
|
||||
slcr::MioPin50::zeroed()
|
||||
.l3_sel(0b000) // GPIO 50
|
||||
.io_type(slcr::IoBufferType::Lvcmos25)
|
||||
.l3_sel(0b000) // as GPIO 50
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
);
|
||||
// SDA
|
||||
slcr.mio_pin_51.write(
|
||||
slcr::MioPin51::zeroed()
|
||||
.l3_sel(0b00) // GPIO 51
|
||||
.io_type(slcr::IoBufferType::Lvcmos25)
|
||||
.l3_sel(0b000) // as GPIO 51
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
);
|
||||
// Reset
|
||||
slcr.gpio_rst_ctrl.reset_gpio();
|
||||
});
|
||||
|
||||
Self::ctor_common()
|
||||
|
@ -42,27 +49,30 @@ impl I2C {
|
|||
fn ctor_common() -> Self {
|
||||
// Setup register block
|
||||
let clocks = Clocks::get();
|
||||
let mut self_ = Self {
|
||||
regs: unsafe { regs::RegisterBlock::new() },
|
||||
let self_ = Self {
|
||||
regs: regs::RegisterWrapper::new(),
|
||||
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown()
|
||||
};
|
||||
|
||||
// Setup GPIO output mask
|
||||
self_.regs.gpio_output_mask.modify(|_, w| {
|
||||
w.scl_m(true).sda_m(true)
|
||||
w.mask(GPIO_OUTPUT_MASK)
|
||||
});
|
||||
// Setup GPIO driver direction
|
||||
self_.regs.gpio_direction.modify(|_, w| {
|
||||
w.scl(true).sda(true)
|
||||
});
|
||||
|
||||
self_.init();
|
||||
self_
|
||||
}
|
||||
|
||||
/// Delay for I2C operations, simple wrapper for nb.
|
||||
fn delay(&mut self, us: u64) {
|
||||
fn delay_us(&mut self, us: u64) {
|
||||
self.count_down.start(Microseconds(us));
|
||||
nb::block!(self.count_down.wait()).unwrap();
|
||||
}
|
||||
|
||||
fn half_period(&mut self) { self.delay(100) }
|
||||
fn half_period(&mut self) { self.delay_us(100) }
|
||||
|
||||
fn sda_i(&mut self) -> bool {
|
||||
self.regs.gpio_input.read().sda()
|
||||
|
@ -171,7 +181,7 @@ impl I2C {
|
|||
for bit in (0..8).rev() {
|
||||
self.sda_oe(data & (1 << bit) == 0);
|
||||
self.half_period();
|
||||
self.scl_o(false);
|
||||
self.scl_oe(false);
|
||||
self.half_period();
|
||||
self.scl_oe(true);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use volatile_register::{RO, WO, RW};
|
||||
|
||||
use libregister::{register, register_bit, register_bits};
|
||||
use libregister::{
|
||||
register, register_at,
|
||||
register_bit, register_bits
|
||||
};
|
||||
|
||||
// With reference to:
|
||||
//
|
||||
|
@ -20,76 +23,71 @@ use libregister::{register, register_bit, register_bits};
|
|||
// Current compatibility:
|
||||
// zc706: GPIO 50, 51 == SCL, SDA
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
pub struct RegisterWrapper {
|
||||
pub gpio_output_mask: &'static mut GPIOOutputMask,
|
||||
pub gpio_input: &'static mut GPIOInput,
|
||||
pub gpio_direction: &'static mut GPIODirection,
|
||||
pub gpio_output_enable: &'static mut GPIOOutputEnable,
|
||||
}
|
||||
|
||||
impl RegisterBlock {
|
||||
pub unsafe fn new() -> Self {
|
||||
impl RegisterWrapper {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
gpio_output_mask: GPIOOutputMask::new(),
|
||||
gpio_input: GPIOInput::new(),
|
||||
gpio_direction: GPIODirection::new(),
|
||||
gpio_output_enable: GPIOOutputEnable::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GPIOOutputMask {
|
||||
#[cfg(feature = "target_zc706")]
|
||||
pub unsafe fn new() -> &'static mut Self {
|
||||
&mut *(0xE000A00C as *mut _)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPIOInput {
|
||||
#[cfg(feature = "target_zc706")]
|
||||
pub unsafe fn new() -> &'static mut Self {
|
||||
&mut *(0xE000A064 as *mut _)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPIOOutputEnable {
|
||||
#[cfg(feature = "target_zc706")]
|
||||
pub unsafe fn new() -> &'static mut Self {
|
||||
&mut *(0xE000A248 as *mut _)
|
||||
}
|
||||
}
|
||||
|
||||
// MASK_DATA_1_MSW:
|
||||
// Maskable output data for MIO[53:48]
|
||||
register!(gpio_output_mask, GPIOOutputMask, RW, u32);
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_at!(GPIOOutputMask, 0xE000A00C, new);
|
||||
// Output for SCL
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_bit!(gpio_output_mask, scl_o, 2);
|
||||
// Output for SDA
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_bit!(gpio_output_mask, sda_o, 3);
|
||||
// Mask for SCL; set to 1 to write to output
|
||||
// Mask for keeping bits except SCL and SDA unchanged
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_bit!(gpio_output_mask, scl_m, 18);
|
||||
// Mask for SDA; set to 1 to write to output
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_bit!(gpio_output_mask, sda_m, 19);
|
||||
register_bits!(gpio_output_mask, mask, u16, 16, 31);
|
||||
|
||||
// DATA_1_RO:
|
||||
// Input data for MIO[53:32]
|
||||
register!(gpio_input, GPIOInput, RO, u32);
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_at!(GPIOInput, 0xE000A064, new);
|
||||
// Input for SCL
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_bit!(gpio_input, scl, 8);
|
||||
register_bit!(gpio_input, scl, 18);
|
||||
// Input for SDA
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_bit!(gpio_input, sda, 9);
|
||||
register_bit!(gpio_input, sda, 19);
|
||||
|
||||
// DIRM_1:
|
||||
// Direction mode for MIO[53:32]; 0/1 = in/out
|
||||
register!(gpio_direction, GPIODirection, RW, u32);
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_at!(GPIODirection, 0xE000A244, new);
|
||||
// Direction for SCL
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_bit!(gpio_direction, scl, 18);
|
||||
// Direction for SDA
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_bit!(gpio_direction, sda, 19);
|
||||
|
||||
// OEN_1:
|
||||
// Output enable for MIO[53:32]
|
||||
register!(gpio_output_enable, GPIOOutputEnable, RW, u32);
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_at!(GPIOOutputEnable, 0xE000A248, new);
|
||||
// Output enable for SCL
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_bit!(gpio_output_enable, scl, 8);
|
||||
register_bit!(gpio_output_enable, scl, 18);
|
||||
// Output enable for SDA
|
||||
#[cfg(feature = "target_zc706")]
|
||||
register_bit!(gpio_output_enable, sda, 9);
|
||||
register_bit!(gpio_output_enable, sda, 19);
|
||||
|
|
|
@ -132,7 +132,7 @@ pub struct RegisterBlock {
|
|||
pub can_rst_ctrl: RW<u32>,
|
||||
pub i2c_rst_ctrl: RW<u32>,
|
||||
pub uart_rst_ctrl: UartRstCtrl,
|
||||
pub gpio_rst_ctrl: RW<u32>,
|
||||
pub gpio_rst_ctrl: GpioRstCtrl,
|
||||
pub lqspi_rst_ctrl: LqspiRstCtrl,
|
||||
pub smc_rst_ctrl: RW<u32>,
|
||||
pub ocm_rst_ctrl: RW<u32>,
|
||||
|
@ -531,6 +531,20 @@ impl UartRstCtrl {
|
|||
}
|
||||
}
|
||||
|
||||
register!(gpio_rst_ctrl, GpioRstCtrl, RW, u32);
|
||||
register_bit!(gpio_rst_ctrl, gpio_cpu1x_rst, 0);
|
||||
register_at!(GpioRstCtrl, 0xF800022C, new);
|
||||
impl GpioRstCtrl {
|
||||
pub fn reset_gpio(&mut self) {
|
||||
self.modify(|_, w|
|
||||
w.gpio_cpu1x_rst(true)
|
||||
);
|
||||
self.modify(|_, w|
|
||||
w.gpio_cpu1x_rst(false)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
register!(lqspi_clk_ctrl, LqspiClkCtrl, RW, u32);
|
||||
register_bit!(lqspi_clk_ctrl, clkact, 0);
|
||||
register_bits_typed!(lqspi_clk_ctrl, src_sel, u8, PllSource, 4, 5);
|
||||
|
|
Loading…
Reference in New Issue