2 * This file is part of Betaflight.
4 * Betaflight is free software. You can redistribute this software
5 * and/or modify this software under the terms of the GNU General
6 * Public License as published by the Free Software Foundation,
7 * either version 3 of the License, or (at your option) any later
10 * Betaflight is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this software.
19 * If not, see <http://www.gnu.org/licenses/>.
26 #include "drivers/io.h"
27 #include "drivers/time.h"
29 #include "bus_i2c_utils.h"
31 // Clock period in us during unstick transfer
32 #define UNSTICK_CLK_US 10 // 100Khz
33 // Allow 500us for clock stretch to complete during unstick
34 #define UNSTICK_CLK_STRETCH (500 / UNSTICK_CLK_US)
36 // wait for SCL to return high (clock stretching)
37 static bool i2cUnstick_waitStretch(IO_t scl
, int timeout
)
40 while (!(sclVal
= IORead(scl
)) && timeout
) {
41 delayMicroseconds(UNSTICK_CLK_US
);
47 // generate clock pulses + STOP on I2C bus
48 // this should get all devices into idle state
49 // return true if bus seems to be idle (both SCL and SDA are high)
50 bool i2cUnstick(IO_t scl
, IO_t sda
)
52 // output value first to prevent glitch after switching direction
56 // bus was probably in I2C (alternate function) mode
57 IOConfigGPIO(scl
, IOCFG_OUT_OD
);
58 IOConfigGPIO(sda
, IOCFG_OUT_OD
);
60 // Clock out, with SDA high:
61 // 7 data bits, 1 READ bit, 1 cycle for the ACK
62 for (int i
= 0; i
< (7 + 1 + 1); i
++) {
63 // Wait for any clock stretching to finish
64 i2cUnstick_waitStretch(scl
, UNSTICK_CLK_STRETCH
);
66 IOLo(scl
); // Set bus low
67 delayMicroseconds(UNSTICK_CLK_US
/ 2);
68 IOHi(scl
); // Set bus high
69 delayMicroseconds(UNSTICK_CLK_US
/ 2);
71 // slave may be still stretching after last pulse
72 i2cUnstick_waitStretch(scl
, UNSTICK_CLK_STRETCH
);
74 // Generate a stop condition in case there was none
75 // SCL low pulse to switch SDA low
77 delayMicroseconds(UNSTICK_CLK_US
/ 2);
79 delayMicroseconds(UNSTICK_CLK_US
/ 2);
81 delayMicroseconds(UNSTICK_CLK_US
/ 2);
82 // SDA rising edge = STOP
84 // check that both SCL and SDA are high
85 delayMicroseconds(UNSTICK_CLK_US
/ 2); // time for SDA to return high
86 bool ok
= IORead(scl
) && IORead(sda
);
87 // I2C ping are left in GPIO mode