From 91445620ee25c84d656eadf787ae9254ec99fc72 Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Wed, 23 Jun 2021 17:07:58 +0800 Subject: [PATCH] i2c: fix SCL/SDA race conditions & handle slave holding SCL after ack --- libboard_zynq/src/i2c/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libboard_zynq/src/i2c/mod.rs b/libboard_zynq/src/i2c/mod.rs index 8290903..04168d4 100644 --- a/libboard_zynq/src/i2c/mod.rs +++ b/libboard_zynq/src/i2c/mod.rs @@ -150,16 +150,18 @@ impl I2c { self.sda_oe(true); self.half_period(); self.scl_oe(true); + while self.scl_i() {} // ensure SCL is low before start() returns // postcondition: SCL and SDA low Ok(()) } pub fn restart(&mut self) -> Result<(), &'static str> { - // precondition SCL and SDA low + // precondition: any self.sda_oe(false); self.half_period(); self.scl_oe(false); self.half_period(); + // enter the precondition for start(): SCL and SDA high self.start()?; // postcondition: SCL and SDA low Ok(()) @@ -188,6 +190,7 @@ impl I2c { self.scl_oe(false); self.half_period(); self.scl_oe(true); + while self.scl_i() {} // ensure SCL is low before start() returns } self.sda_oe(false); self.half_period(); @@ -196,6 +199,7 @@ impl I2c { // Read ack/nack let ack = !self.sda_i(); self.scl_oe(true); + while self.scl_i() {} // ensure SCL is low before start() returns self.sda_oe(true); // postcondition: SCL and SDA low @@ -215,6 +219,7 @@ impl I2c { self.half_period(); if self.sda_i() { data |= 1 << bit } self.scl_oe(true); + while self.scl_i() {} // ensure SCL is low before start() returns } // Send ack/nack self.sda_oe(ack); @@ -222,6 +227,7 @@ impl I2c { self.scl_oe(false); self.half_period(); self.scl_oe(true); + while self.scl_i() {} // ensure SCL is low before start() returns self.sda_oe(true); // postcondition: SCL and SDA low