diff --git a/firmware/src/i2c.rs b/firmware/src/i2c.rs index 8f7d2cd..f489e8d 100644 --- a/firmware/src/i2c.rs +++ b/firmware/src/i2c.rs @@ -2,8 +2,7 @@ //! //! See `gateware/i2c.py` for register information -use crate::timer::busy_wait_us; -use crate::{read_reg, write_reg}; +use crate::{read_reg, write_reg, timer::busy_wait_us}; use core::arch::asm; use embedded_hal::blocking::i2c::{Operation, Read, SevenBitAddress, Transactional, Write}; @@ -33,25 +32,39 @@ use core::fmt::Write as _; impl LitexI2c { pub fn new(base_addr: u32) -> Self { - LitexI2c { base_addr } + let mut device = LitexI2c { base_addr }; + device.set_scl(true); + device.set_sda(true); + device.set_oe(true); + + device } - fn set_scl(&mut self, val: u32) { + fn set_reg(&mut self, offset: u32, set: bool) { + static mut reg_state: u32 = 0; + unsafe { - write_reg(self.base_addr + REG_W, (val & 0x01) << FIELD_W_SCL); + if set { + reg_state |= (1 << offset); + } else { + reg_state &= !(1 << offset); + } + + write_reg(self.base_addr + REG_W, reg_state); } } - fn set_sda(&mut self, val: u32) { - unsafe { - write_reg(self.base_addr + REG_W, (val & 0x01) << FIELD_W_SDA); - } + fn set_scl(&mut self, set: bool) { + defmt::debug!("set scl {}", set); + self.set_reg(FIELD_W_SCL, set); } - fn set_oe(&mut self, val: u32) { - unsafe { - write_reg(self.base_addr + REG_W, (val & 0x01) << FIELD_W_OE); - } + fn set_sda(&mut self, set: bool) { + self.set_reg(FIELD_W_SDA, set); + } + + fn set_oe(&mut self, set: bool) { + self.set_reg(FIELD_W_OE, set); } fn get_sda(&mut self) -> u8 { @@ -63,12 +76,11 @@ impl LitexI2c { /// /// Assumes SCL and SDA have been high due to bus inactivity unsafe fn start(&mut self) { - self.set_oe(1); - self.set_scl(1); - self.set_sda(1); + self.set_scl(true); + self.set_sda(true); busy_wait_us(WAIT_PERIOD_US); - self.set_sda(0); + self.set_sda(false); busy_wait_us(WAIT_PERIOD_US); } @@ -76,16 +88,15 @@ impl LitexI2c { /// /// Assumes it was called after an ACK bit unsafe fn repeated_start(&mut self) { - self.set_scl(0); - self.set_sda(1); - self.set_oe(1); + self.set_scl(false); + self.set_sda(true); busy_wait_us(WAIT_PERIOD_US); - self.set_scl(1); + self.set_scl(true); busy_wait_us(WAIT_PERIOD_US); // TODO does this third half-clock break timing? - self.set_sda(0); + self.set_sda(false); busy_wait_us(WAIT_PERIOD_US); } @@ -93,49 +104,44 @@ impl LitexI2c { /// /// Assumes it was called after an ACK bit unsafe fn stop(&mut self) { - self.set_scl(0); - self.set_sda(0); - self.set_oe(1); + self.set_scl(false); + self.set_sda(false); busy_wait_us(WAIT_PERIOD_US); - self.set_scl(1); + self.set_scl(true); busy_wait_us(WAIT_PERIOD_US); // TODO does this third half-clock break timing? - //self.set_oe(0); // Disable and let pullup take bus high - self.set_sda(1); + //self.set_oe(false); // Disable and let pullup take bus high + self.set_sda(true); busy_wait_us(WAIT_PERIOD_US); } unsafe fn write_byte(&mut self, byte: u8) { - self.set_oe(1); // Take SDA to write data out - for i in 0..8 { // Write data out before we clock high - self.set_scl(0); + self.set_scl(false); busy_wait_us(WAIT_PERIOD_US); // Clock data in - self.set_scl(1); - self.set_sda(byte as u32 >> (7 - i)); + self.set_sda((byte >> (7 - i)) & 0x01 != 0); + self.set_scl(true); busy_wait_us(WAIT_PERIOD_US) } } unsafe fn read_byte(&mut self) -> u8 { - self.set_oe(0); // De-assert to read data - let mut out = 0; for i in 0..8 { - self.set_scl(0); + self.set_scl(false); busy_wait_us(WAIT_PERIOD_US); - self.set_scl(1); + self.set_scl(true); busy_wait_us(WAIT_PERIOD_US); // TODO sampling at the end of the clock may not work 100% of the time // ideally should sample in the middle - out |= (self.get_sda() << 7 - i); + out |= (self.get_sda() << (7 - i)); } out @@ -143,24 +149,22 @@ impl LitexI2c { // Returns if there was an ACK unsafe fn get_ack(&mut self) -> bool { - self.set_oe(0); // Release SDA to read ACK - self.set_sda(1); - self.set_scl(0); + self.set_scl(false); + self.set_sda(true); busy_wait_us(WAIT_PERIOD_US); - self.set_scl(1); + self.set_scl(true); busy_wait_us(WAIT_PERIOD_US); self.get_sda() == 0 } unsafe fn set_ack(&mut self, ack: bool) { - self.set_oe(1); // Take SDA - self.set_sda(!ack as u32); - self.set_scl(0); + self.set_scl(false); busy_wait_us(WAIT_PERIOD_US); - self.set_scl(1); + self.set_sda(!ack); + self.set_scl(true); busy_wait_us(WAIT_PERIOD_US); } } @@ -176,13 +180,16 @@ impl Write for LitexI2c { // Write address and write bit self.write_byte((address << 1) | 0); if !self.get_ack() { + defmt::debug!("write addr fail"); self.stop(); return Err(Error::Nack); } for b in bytes { self.write_byte(*b); + defmt::debug!("write data "); if !self.get_ack() { + defmt::debug!("write data fail"); self.stop(); return Err(Error::Nack); } diff --git a/firmware/src/main.rs b/firmware/src/main.rs index aa0369c..24c4a90 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -139,7 +139,8 @@ fn main() -> ! { match dac.write_config( &mut i2c, mcp4726::Config { - vref_source: mcp4726::VRef::UnbufferedVRef, + //vref_source: mcp4726::VRef::UnbufferedVRef, + vref_source: mcp4726::VRef::UnbufferedVDD, operation: mcp4726::PowerDown::NormalOperation, use_2x_gain: false, }, @@ -148,20 +149,22 @@ fn main() -> ! { Err(_) => defmt::debug!("Write config failed"), } - //match dac.read_status(&mut i2c) { - // Ok(status) => { - // defmt::debug!( - // "DAC status: ready: {}, powered: {}", - // status.ready, - // status.device_powered - // ); + match dac.read_status(&mut i2c) { + Ok(status) => { + defmt::debug!( + "DAC status: ready: {}, powered: {}", + status.ready, + status.device_powered + ); - // if sock.can_send() { - // write!(sock, "DAC: ready: {}, powered: {}", status.ready, status.device_powered); - // } - // } - // Err(_) => defmt::debug!("Error reading from DAC"), - //}; + if sock.can_send() { + write!(sock, "DAC: ready: {}, powered: {}", status.ready, status.device_powered); + } + } + Err(_) => defmt::debug!("Error reading from DAC"), + }; + + dac.write_dac(&mut i2c, 800); //if toggle { // sampler::clear_buffers();