Skip to content

Commit ccb08a3

Browse files
author
Deepika
committed
Added reset recovery for I2C
Hardware Reset API should do the recovery of I2C bus, but in absence of reset pin connected to slave device we need software recovery of I2C bus.
1 parent c6fef82 commit ccb08a3

File tree

2 files changed

+75
-6
lines changed

2 files changed

+75
-6
lines changed

drivers/I2C.cpp

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
1617
#include "drivers/I2C.h"
18+
#include "drivers/DigitalInOut.h"
19+
#include "platform/mbed_wait_api.h"
1720

1821
#if DEVICE_I2C
1922

@@ -32,13 +35,15 @@ I2C::I2C(PinName sda, PinName scl) :
3235
#endif
3336
_i2c(), _hz(100000)
3437
{
35-
// No lock needed in the constructor
36-
38+
lock();
3739
// The init function also set the frequency to 100000
38-
i2c_init(&_i2c, sda, scl);
39-
40+
_sda = sda;
41+
_scl = scl;
42+
recover(sda, scl);
43+
i2c_init(&_i2c, _sda, _scl);
4044
// Used to avoid unnecessary frequency updates
4145
_owner = this;
46+
unlock();
4247
}
4348

4449
void I2C::frequency(int hz)
@@ -135,6 +140,53 @@ void I2C::unlock()
135140
_mutex->unlock();
136141
}
137142

143+
int I2C::recover(PinName sda, PinName scl)
144+
{
145+
DigitalInOut pin_sda(sda, PIN_INPUT, PullNone, 1);
146+
DigitalInOut pin_scl(scl, PIN_INPUT, PullNone, 1);
147+
148+
// Read and verify if recovery is required
149+
if (pin_scl == 1) {
150+
if (pin_sda == 1) {
151+
// Return successfuly as SDA and SCL is high
152+
return 0;
153+
}
154+
} else {
155+
// Return as SCL is low and no access to become master.
156+
return I2C_ERROR_BUS_BUSY;
157+
}
158+
159+
// Send clock pulses, for device to recover 9
160+
pin_scl.mode(PullNone);
161+
pin_scl.output();
162+
int count = 9;
163+
while (count--) {
164+
pin_scl.mode(PullNone);
165+
pin_scl = 0;
166+
wait_us(5);
167+
pin_scl.mode(PullUp);
168+
pin_scl = 1;
169+
wait_us(5);
170+
}
171+
172+
// Send Stop
173+
pin_sda.output();
174+
pin_sda = 0;
175+
wait_us(5);
176+
pin_scl = 1;
177+
wait_us(5);
178+
pin_sda = 1;
179+
wait_us(5);
180+
181+
pin_sda.input();
182+
pin_scl.input();
183+
if ((pin_scl == 0) || (pin_sda == 0)) {
184+
// Return as SCL is low and no access to become master.
185+
return I2C_ERROR_BUS_BUSY;
186+
}
187+
return 0;
188+
}
189+
138190
#if DEVICE_I2C_ASYNCH
139191

140192
int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t &callback, int event, bool repeated)
@@ -169,10 +221,10 @@ void I2C::irq_handler_asynch(void)
169221
if (_callback && event) {
170222
_callback.call(event);
171223
}
224+
172225
if (event) {
173226
unlock_deep_sleep();
174227
}
175-
176228
}
177229

178230
void I2C::lock_deep_sleep()

drivers/I2C.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define MBED_I2C_H
1818

1919
#include "platform/platform.h"
20+
#include "hal/gpio_api.h"
2021

2122
#if defined (DEVICE_I2C) || defined(DOXYGEN_ONLY)
2223

@@ -197,8 +198,24 @@ class I2C : private NonCopyable<I2C> {
197198

198199
i2c_t _i2c;
199200
static I2C *_owner;
200-
int _hz;
201+
int _hz;
201202
static SingletonPtr<PlatformMutex> _mutex;
203+
PinName _sda;
204+
PinName _scl;
205+
206+
private:
207+
/** Recover I2C bus, when stuck with SDA low
208+
* @note : Initialization of I2C bus is required after this API.
209+
*
210+
* @param sda I2C data line pin
211+
* @param scl I2C clock line pin
212+
*
213+
* @returns:
214+
* '0' - Successfully recovered
215+
* 'I2C_ERROR_BUS_BUSY' - In case of failure
216+
*
217+
*/
218+
int recover(PinName sda, PinName scl);
202219
};
203220

204221
} // namespace mbed

0 commit comments

Comments
 (0)