Merge pull request #11198 from SteveCEvans/sce_rc2
[betaflight.git] / src / main / drivers / bus_i2c_hal_init.c
blob3f00b9b5f3bca3ab9df89ca458e8033b7bc003e4
1 /*
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)
8 * any later version.
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/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
25 #include "platform.h"
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
40 #define LEN_ADDR 7
41 #define LEN_RW 1
42 #define LEN_ACK 1
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] = {
58 #if defined(STM32F7)
59 #ifdef USE_I2C_DEVICE_1
61 .device = I2CDEV_1,
62 .reg = I2C1,
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,
69 #endif
70 #ifdef USE_I2C_DEVICE_2
72 .device = I2CDEV_2,
73 .reg = I2C2,
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,
80 #endif
81 #ifdef USE_I2C_DEVICE_3
83 .device = I2CDEV_3,
84 .reg = I2C3,
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,
91 #endif
92 #ifdef USE_I2C_DEVICE_4
94 .device = I2CDEV_4,
95 .reg = I2C4,
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,
102 #endif
103 #elif defined(STM32H7)
104 #ifdef USE_I2C_DEVICE_1
106 .device = I2CDEV_1,
107 .reg = I2C1,
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,
114 #endif
115 #ifdef USE_I2C_DEVICE_2
117 .device = I2CDEV_2,
118 .reg = I2C2,
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,
125 #endif
126 #ifdef USE_I2C_DEVICE_3
128 .device = I2CDEV_3,
129 .reg = I2C3,
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,
136 #endif
137 #ifdef USE_I2C_DEVICE_4
139 .device = I2CDEV_4,
140 .reg = I2C4,
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,
147 #endif
148 #elif defined(STM32G4)
149 #ifdef USE_I2C_DEVICE_1
151 .device = I2CDEV_1,
152 .reg = I2C1,
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,
163 #endif
164 #ifdef USE_I2C_DEVICE_2
166 .device = I2CDEV_2,
167 .reg = I2C2,
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,
174 #endif
175 #ifdef USE_I2C_DEVICE_3
177 .device = I2CDEV_3,
178 .reg = I2C3,
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,
185 #endif
186 #ifdef USE_I2C_DEVICE_4
188 .device = I2CDEV_4,
189 .reg = I2C4,
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,
200 #endif
201 #endif
204 i2cDevice_t i2cDevice[I2CDEV_COUNT];
206 void i2cInit(I2CDevice device)
208 if (device == I2CINVALID) {
209 return;
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)) {
219 return;
222 IOInit(scl, OWNER_I2C_SCL, RESOURCE_INDEX(device));
223 IOInit(sda, OWNER_I2C_SDA, RESOURCE_INDEX(device));
225 // Enable RCC
226 RCC_ClockCmd(hardware->rcc, ENABLE);
228 i2cUnstick(scl, sda);
230 // Init pins
231 #if defined(STM32F7)
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);
237 #else
238 IOConfigGPIO(scl, IOCFG_AF_OD);
239 IOConfigGPIO(sda, IOCFG_AF_OD);
240 #endif
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
252 uint32_t i2cPclk;
254 #if defined(STM32F7) || defined(STM32G4)
255 // F7 Clock source configured in startup/system_stm32f7xx.c as:
256 // I2C1234 : PCLK1
257 // G4 Clock source configured in startup/system_stm32g4xx.c as:
258 // I2C1234 : PCLK1
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();
265 #else
266 #error Unknown MCU type
267 #endif
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)
292 int i;
294 IOHi(scl);
295 IOHi(sda);
297 IOConfigGPIO(scl, IOCFG_OUT_OD);
298 IOConfigGPIO(sda, IOCFG_OUT_OD);
300 // Clock out, with SDA high:
301 // 7 data bits
302 // 1 READ bit
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);
309 timeout--;
312 // Pull low
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
320 IOLo(scl);
321 delayMicroseconds(UNSTICK_CLK_US/2);
322 IOLo(sda);
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
330 #endif