@@ -29,7 +29,9 @@ pub enum I2cError {
2929 Overrun ,
3030 /// Timeout
3131 Timeout ,
32- /// SDA line stuck high during recovery.
32+ /// SCL line stuck low during recovery.
33+ SclStuckLow ,
34+ /// SDA line stuck low during recovery.
3335 SdaStuckLow ,
3436 /// Other error.
3537 Other ,
@@ -80,6 +82,17 @@ impl I2c2Gpio {
8082 self . gpiob . crh . modify ( |_, w| w. cnf10 ( ) . open_drain ( ) . mode10 ( ) . output ( ) ) ;
8183 }
8284
85+ /// Reads the SCL level.
86+ pub fn read_scl ( & self ) -> bool {
87+ self . gpiob . crh . modify ( |_, w| w. cnf10 ( ) . open_drain ( ) . mode10 ( ) . input ( ) ) ;
88+
89+ for _ in 0 ..32 {
90+ self . gpiob . idr . read ( ) ;
91+ }
92+
93+ self . gpiob . idr . read ( ) . idr10 ( ) . is_high ( )
94+ }
95+
8396 /// Sets the SDA level.
8497 pub fn sda ( & self , level : bool ) {
8598 self . gpiob . odr . modify ( |_, w| w. odr11 ( ) . variant ( if level { High } else { Low } ) ) ;
@@ -88,7 +101,7 @@ impl I2c2Gpio {
88101
89102 /// Reads the SDA level.
90103 pub fn read_sda ( & self ) -> bool {
91- self . gpiob . crh . modify ( |_, w| w. mode11 ( ) . input ( ) ) ;
104+ self . gpiob . crh . modify ( |_, w| w. cnf11 ( ) . open_drain ( ) . mode11 ( ) . input ( ) ) ;
92105
93106 for _ in 0 ..32 {
94107 self . gpiob . idr . read ( ) ;
@@ -128,6 +141,12 @@ pub fn recover(i2c: &mut I2c2Master, clocks: &Clocks) -> Result<(), I2cError> {
128141 i2c_gpio. sda ( true ) ;
129142 dwt. delay ( CLOCK_HALF_PERIOD_US ) ;
130143
144+ // Verify SCL is high.
145+ if !i2c_gpio. read_scl ( ) {
146+ defmt:: error!( "I2C SCL is stuck low" ) ;
147+ return Err ( I2cError :: SclStuckLow ) ;
148+ }
149+
131150 // Output clock so that all in-progress transfers end.
132151 defmt:: debug!( "Cycling SCL to end all I2C transfers" ) ;
133152 for _ in 0 ..15 {
@@ -167,11 +186,15 @@ pub fn recover(i2c: &mut I2c2Master, clocks: &Clocks) -> Result<(), I2cError> {
167186 i2c_gpio. sda ( true ) ;
168187 dwt. delay ( CLOCK_HALF_PERIOD_US ) ;
169188
189+ // Reset I2C master peripheral.
190+ defmt:: debug!( "Performing I2C master reset before GPIO release" ) ;
191+ i2c. reset ( ) ;
192+
170193 // Release I2C GPIO control.
171194 drop ( i2c_gpio) ;
172195
173196 // Reset I2C master peripheral.
174- defmt:: debug!( "Performing I2C master reset" ) ;
197+ defmt:: debug!( "Performing I2C master reset after GPIO release " ) ;
175198 i2c. reset ( ) ;
176199
177200 Ok ( ( ) )
0 commit comments