2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
27 #if defined(USE_I2C) && !defined(SOFT_I2C)
29 #include "drivers/io.h"
30 #include "drivers/io_impl.h"
31 #include "drivers/nvic.h"
32 #include "drivers/time.h"
33 #include "drivers/rcc.h"
35 #include "drivers/bus_i2c.h"
36 #include "drivers/bus_i2c_impl.h"
37 #include "drivers/bus_i2c_timing.h"
39 // Number of bits in I2C protocol phase
44 // Clock period in us during unstick transfer
45 #define UNSTICK_CLK_US 10
47 // Allow 500us for clock strech to complete during unstick
48 #define UNSTICK_CLK_STRETCH (500/UNSTICK_CLK_US)
50 static void i2cUnstick(IO_t scl
, IO_t sda
);
52 #define IOCFG_I2C_PU IO_CONFIG(GPIO_MODE_AF_OD, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLUP)
53 #define IOCFG_I2C IO_CONFIG(GPIO_MODE_AF_OD, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_NOPULL)
55 #define GPIO_AF4_I2C GPIO_AF4_I2C1
57 const i2cHardware_t i2cHardware
[I2CDEV_COUNT
] = {
59 #ifdef USE_I2C_DEVICE_1
63 .sclPins
= { I2CPINDEF(PB6
), I2CPINDEF(PB8
) },
64 .sdaPins
= { I2CPINDEF(PB7
), I2CPINDEF(PB9
) },
65 .rcc
= RCC_APB1(I2C1
),
66 .ev_irq
= I2C1_EV_IRQn
,
67 .er_irq
= I2C1_ER_IRQn
,
70 #ifdef USE_I2C_DEVICE_2
74 .sclPins
= { I2CPINDEF(PB10
), I2CPINDEF(PF1
) },
75 .sdaPins
= { I2CPINDEF(PB11
), I2CPINDEF(PF0
) },
76 .rcc
= RCC_APB1(I2C2
),
77 .ev_irq
= I2C2_EV_IRQn
,
78 .er_irq
= I2C2_ER_IRQn
,
81 #ifdef USE_I2C_DEVICE_3
85 .sclPins
= { I2CPINDEF(PA8
) },
86 .sdaPins
= { I2CPINDEF(PC9
) },
87 .rcc
= RCC_APB1(I2C3
),
88 .ev_irq
= I2C3_EV_IRQn
,
89 .er_irq
= I2C3_ER_IRQn
,
92 #ifdef USE_I2C_DEVICE_4
96 .sclPins
= { I2CPINDEF(PD12
), I2CPINDEF(PF14
) },
97 .sdaPins
= { I2CPINDEF(PD13
), I2CPINDEF(PF15
) },
98 .rcc
= RCC_APB1(I2C4
),
99 .ev_irq
= I2C4_EV_IRQn
,
100 .er_irq
= I2C4_ER_IRQn
,
103 #elif defined(STM32H7)
104 #ifdef USE_I2C_DEVICE_1
108 .sclPins
= { I2CPINDEF(PB6
, GPIO_AF4_I2C1
), I2CPINDEF(PB8
, GPIO_AF4_I2C1
) },
109 .sdaPins
= { I2CPINDEF(PB7
, GPIO_AF4_I2C1
), I2CPINDEF(PB9
, GPIO_AF4_I2C1
) },
110 .rcc
= RCC_APB1L(I2C1
),
111 .ev_irq
= I2C1_EV_IRQn
,
112 .er_irq
= I2C1_ER_IRQn
,
115 #ifdef USE_I2C_DEVICE_2
119 .sclPins
= { I2CPINDEF(PB10
, GPIO_AF4_I2C2
), I2CPINDEF(PF1
, GPIO_AF4_I2C2
) },
120 .sdaPins
= { I2CPINDEF(PB11
, GPIO_AF4_I2C2
), I2CPINDEF(PF0
, GPIO_AF4_I2C2
) },
121 .rcc
= RCC_APB1L(I2C2
),
122 .ev_irq
= I2C2_EV_IRQn
,
123 .er_irq
= I2C2_ER_IRQn
,
126 #ifdef USE_I2C_DEVICE_3
130 .sclPins
= { I2CPINDEF(PA8
, GPIO_AF4_I2C3
) },
131 .sdaPins
= { I2CPINDEF(PC9
, GPIO_AF4_I2C3
) },
132 .rcc
= RCC_APB1L(I2C3
),
133 .ev_irq
= I2C3_EV_IRQn
,
134 .er_irq
= I2C3_ER_IRQn
,
137 #ifdef USE_I2C_DEVICE_4
141 .sclPins
= { I2CPINDEF(PD12
, GPIO_AF4_I2C4
), I2CPINDEF(PF14
, GPIO_AF4_I2C4
), I2CPINDEF(PB6
, GPIO_AF6_I2C4
), I2CPINDEF(PB8
, GPIO_AF6_I2C4
) },
142 .sdaPins
= { I2CPINDEF(PD13
, GPIO_AF4_I2C4
), I2CPINDEF(PF15
, GPIO_AF4_I2C4
), I2CPINDEF(PB7
, GPIO_AF6_I2C4
), I2CPINDEF(PB9
, GPIO_AF6_I2C4
) },
143 .rcc
= RCC_APB4(I2C4
),
144 .ev_irq
= I2C4_EV_IRQn
,
145 .er_irq
= I2C4_ER_IRQn
,
148 #elif defined(STM32G4)
149 #ifdef USE_I2C_DEVICE_1
154 // Some boards are overloading SWD pins with I2C1 for maximum pin utilization on 48-pin CE(U) packages.
155 // Be carefull when using SWD on these boards if I2C1 pins are defined by default.
157 .sclPins
= { I2CPINDEF(PA13
, GPIO_AF4_I2C1
), I2CPINDEF(PA15
, GPIO_AF4_I2C1
), I2CPINDEF(PB6
, GPIO_AF4_I2C1
), I2CPINDEF(PB8
, GPIO_AF4_I2C1
), },
158 .sdaPins
= { I2CPINDEF(PA14
, GPIO_AF4_I2C1
), I2CPINDEF(PB7
, GPIO_AF4_I2C1
), I2CPINDEF(PB9
, GPIO_AF4_I2C1
), },
159 .rcc
= RCC_APB11(I2C1
),
160 .ev_irq
= I2C1_EV_IRQn
,
161 .er_irq
= I2C1_ER_IRQn
,
164 #ifdef USE_I2C_DEVICE_2
168 .sclPins
= { I2CPINDEF(PA9
, GPIO_AF4_I2C2
), },
169 .sdaPins
= { I2CPINDEF(PA10
, GPIO_AF4_I2C2
), },
170 .rcc
= RCC_APB11(I2C2
),
171 .ev_irq
= I2C2_EV_IRQn
,
172 .er_irq
= I2C2_ER_IRQn
,
175 #ifdef USE_I2C_DEVICE_3
179 .sclPins
= { I2CPINDEF(PA10
, GPIO_AF2_I2C3
), I2CPINDEF(PC8
, GPIO_AF8_I2C3
), },
180 .sdaPins
= { I2CPINDEF(PB5
, GPIO_AF8_I2C3
), I2CPINDEF(PC9
, GPIO_AF8_I2C3
), I2CPINDEF(PC11
, GPIO_AF8_I2C3
), },
181 .rcc
= RCC_APB11(I2C3
),
182 .ev_irq
= I2C3_EV_IRQn
,
183 .er_irq
= I2C3_ER_IRQn
,
186 #ifdef USE_I2C_DEVICE_4
191 // Here, SWDIO(PA13) is overloaded with I2C4_SCL, too.
192 // See comment in the I2C1 section above.
194 .sclPins
= { I2CPINDEF(PA13
, GPIO_AF3_I2C4
), I2CPINDEF(PB6
, GPIO_AF3_I2C4
), I2CPINDEF(PC6
, GPIO_AF8_I2C4
), },
195 .sdaPins
= { I2CPINDEF(PB7
, GPIO_AF4_I2C4
), I2CPINDEF(PC7
, GPIO_AF8_I2C4
), },
196 .rcc
= RCC_APB12(I2C4
),
197 .ev_irq
= I2C4_EV_IRQn
,
198 .er_irq
= I2C4_ER_IRQn
,
204 i2cDevice_t i2cDevice
[I2CDEV_COUNT
];
206 void i2cInit(I2CDevice device
)
208 if (device
== I2CINVALID
) {
212 i2cDevice_t
*pDev
= &i2cDevice
[device
];
214 const i2cHardware_t
*hardware
= pDev
->hardware
;
215 const IO_t scl
= pDev
->scl
;
216 const IO_t sda
= pDev
->sda
;
218 if (!hardware
|| IOGetOwner(scl
) || IOGetOwner(sda
)) {
222 IOInit(scl
, OWNER_I2C_SCL
, RESOURCE_INDEX(device
));
223 IOInit(sda
, OWNER_I2C_SDA
, RESOURCE_INDEX(device
));
226 RCC_ClockCmd(hardware
->rcc
, ENABLE
);
228 i2cUnstick(scl
, sda
);
232 IOConfigGPIOAF(scl
, pDev
->pullUp
? IOCFG_I2C_PU
: IOCFG_I2C
, GPIO_AF4_I2C
);
233 IOConfigGPIOAF(sda
, pDev
->pullUp
? IOCFG_I2C_PU
: IOCFG_I2C
, GPIO_AF4_I2C
);
234 #elif defined(STM32H7) || defined(STM32G4)
235 IOConfigGPIOAF(scl
, pDev
->pullUp
? IOCFG_I2C_PU
: IOCFG_I2C
, pDev
->sclAF
);
236 IOConfigGPIOAF(sda
, pDev
->pullUp
? IOCFG_I2C_PU
: IOCFG_I2C
, pDev
->sdaAF
);
238 IOConfigGPIO(scl
, IOCFG_AF_OD
);
239 IOConfigGPIO(sda
, IOCFG_AF_OD
);
242 // Init I2C peripheral
244 I2C_HandleTypeDef
*pHandle
= &pDev
->handle
;
246 memset(pHandle
, 0, sizeof(*pHandle
));
248 pHandle
->Instance
= pDev
->hardware
->reg
;
250 // Compute TIMINGR value based on peripheral clock for this device instance
254 #if defined(STM32F7) || defined(STM32G4)
255 // F7 Clock source configured in startup/system_stm32f7xx.c as:
257 // G4 Clock source configured in startup/system_stm32g4xx.c as:
259 i2cPclk
= HAL_RCC_GetPCLK1Freq();
260 #elif defined(STM32H7)
261 // Clock sources configured in startup/system_stm32h7xx.c as:
262 // I2C123 : D2PCLK1 (rcc_pclk1 for APB1)
263 // I2C4 : D3PCLK1 (rcc_pclk4 for APB4)
264 i2cPclk
= (pHandle
->Instance
== I2C4
) ? HAL_RCCEx_GetD3PCLK1Freq() : HAL_RCC_GetPCLK1Freq();
266 #error Unknown MCU type
269 pHandle
->Init
.Timing
= i2cClockTIMINGR(i2cPclk
, pDev
->clockSpeed
, 0);
271 pHandle
->Init
.OwnAddress1
= 0x0;
272 pHandle
->Init
.AddressingMode
= I2C_ADDRESSINGMODE_7BIT
;
273 pHandle
->Init
.DualAddressMode
= I2C_DUALADDRESS_DISABLE
;
274 pHandle
->Init
.OwnAddress2
= 0x0;
275 pHandle
->Init
.GeneralCallMode
= I2C_GENERALCALL_DISABLE
;
276 pHandle
->Init
.NoStretchMode
= I2C_NOSTRETCH_DISABLE
;
278 HAL_I2C_Init(pHandle
);
280 // Enable the Analog I2C Filter
281 HAL_I2CEx_ConfigAnalogFilter(pHandle
, I2C_ANALOGFILTER_ENABLE
);
283 // Setup interrupt handlers
284 HAL_NVIC_SetPriority(hardware
->er_irq
, NVIC_PRIORITY_BASE(NVIC_PRIO_I2C_ER
), NVIC_PRIORITY_SUB(NVIC_PRIO_I2C_ER
));
285 HAL_NVIC_EnableIRQ(hardware
->er_irq
);
286 HAL_NVIC_SetPriority(hardware
->ev_irq
, NVIC_PRIORITY_BASE(NVIC_PRIO_I2C_EV
), NVIC_PRIORITY_SUB(NVIC_PRIO_I2C_EV
));
287 HAL_NVIC_EnableIRQ(hardware
->ev_irq
);
290 static void i2cUnstick(IO_t scl
, IO_t sda
)
297 IOConfigGPIO(scl
, IOCFG_OUT_OD
);
298 IOConfigGPIO(sda
, IOCFG_OUT_OD
);
300 // Clock out, with SDA high:
303 // 1 cycle for the ACK
304 for (i
= 0; i
< (LEN_ADDR
+ LEN_RW
+ LEN_ACK
); i
++) {
305 // Wait for any clock stretching to finish
306 int timeout
= UNSTICK_CLK_STRETCH
;
307 while (!IORead(scl
) && timeout
) {
308 delayMicroseconds(UNSTICK_CLK_US
);
313 IOLo(scl
); // Set bus low
314 delayMicroseconds(UNSTICK_CLK_US
/2);
315 IOHi(scl
); // Set bus high
316 delayMicroseconds(UNSTICK_CLK_US
/2);
319 // Generate a stop condition in case there was none
321 delayMicroseconds(UNSTICK_CLK_US
/2);
323 delayMicroseconds(UNSTICK_CLK_US
/2);
325 IOHi(scl
); // Set bus scl high
326 delayMicroseconds(UNSTICK_CLK_US
/2);
327 IOHi(sda
); // Set bus sda high