FIX: Invalid references when neither DSHOT nor PWM_OUTPUT is defined. (#14135)
[betaflight.git] / src / main / drivers / bus_i2c_utils.c
blobace10dab1f1e730b89d90bf858e4a1ab7475d9e5
1 /*
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
8 * version.
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/>.
22 #include <stdbool.h>
24 #include "platform.h"
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)
39 bool sclVal;
40 while (!(sclVal = IORead(scl)) && timeout) {
41 delayMicroseconds(UNSTICK_CLK_US);
42 timeout--;
44 return sclVal;
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
53 IOHi(scl);
54 IOHi(sda);
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);
65 // Pull low
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
76 IOLo(scl);
77 delayMicroseconds(UNSTICK_CLK_US / 2);
78 IOLo(sda);
79 delayMicroseconds(UNSTICK_CLK_US / 2);
80 IOHi(scl);
81 delayMicroseconds(UNSTICK_CLK_US / 2);
82 // SDA rising edge = STOP
83 IOHi(sda);
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
88 return ok;