Improve I2C_TIMINGR register calculation
[betaflight.git] / src / main / drivers / bus_i2c_hal_init.c
blob4b66b571416770d4f0e9db720c83d62dce5a82af
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"
38 // Number of bits in I2C protocol phase
39 #define LEN_ADDR 7
40 #define LEN_RW 1
41 #define LEN_ACK 1
43 // Clock period in us during unstick transfer
44 #define UNSTICK_CLK_US 10
46 // Allow 500us for clock strech to complete during unstick
47 #define UNSTICK_CLK_STRETCH (500/UNSTICK_CLK_US)
49 static void i2cUnstick(IO_t scl, IO_t sda);
51 #define IOCFG_I2C_PU IO_CONFIG(GPIO_MODE_AF_OD, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLUP)
52 #define IOCFG_I2C IO_CONFIG(GPIO_MODE_AF_OD, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_NOPULL)
54 #define GPIO_AF4_I2C GPIO_AF4_I2C1
56 const i2cHardware_t i2cHardware[I2CDEV_COUNT] = {
57 #if defined(STM32F7)
58 #ifdef USE_I2C_DEVICE_1
60 .device = I2CDEV_1,
61 .reg = I2C1,
62 .sclPins = { I2CPINDEF(PB6), I2CPINDEF(PB8) },
63 .sdaPins = { I2CPINDEF(PB7), I2CPINDEF(PB9) },
64 .rcc = RCC_APB1(I2C1),
65 .ev_irq = I2C1_EV_IRQn,
66 .er_irq = I2C1_ER_IRQn,
68 #endif
69 #ifdef USE_I2C_DEVICE_2
71 .device = I2CDEV_2,
72 .reg = I2C2,
73 .sclPins = { I2CPINDEF(PB10), I2CPINDEF(PF1) },
74 .sdaPins = { I2CPINDEF(PB11), I2CPINDEF(PF0) },
75 .rcc = RCC_APB1(I2C2),
76 .ev_irq = I2C2_EV_IRQn,
77 .er_irq = I2C2_ER_IRQn,
79 #endif
80 #ifdef USE_I2C_DEVICE_3
82 .device = I2CDEV_3,
83 .reg = I2C3,
84 .sclPins = { I2CPINDEF(PA8) },
85 .sdaPins = { I2CPINDEF(PC9) },
86 .rcc = RCC_APB1(I2C3),
87 .ev_irq = I2C3_EV_IRQn,
88 .er_irq = I2C3_ER_IRQn,
90 #endif
91 #ifdef USE_I2C_DEVICE_4
93 .device = I2CDEV_4,
94 .reg = I2C4,
95 .sclPins = { I2CPINDEF(PD12), I2CPINDEF(PF14) },
96 .sdaPins = { I2CPINDEF(PD13), I2CPINDEF(PF15) },
97 .rcc = RCC_APB1(I2C4),
98 .ev_irq = I2C4_EV_IRQn,
99 .er_irq = I2C4_ER_IRQn,
101 #endif
102 #elif defined(STM32H7)
103 #ifdef USE_I2C_DEVICE_1
105 .device = I2CDEV_1,
106 .reg = I2C1,
107 .sclPins = { I2CPINDEF(PB6, GPIO_AF4_I2C1), I2CPINDEF(PB8, GPIO_AF4_I2C1) },
108 .sdaPins = { I2CPINDEF(PB7, GPIO_AF4_I2C1), I2CPINDEF(PB9, GPIO_AF4_I2C1) },
109 .rcc = RCC_APB1L(I2C1),
110 .ev_irq = I2C1_EV_IRQn,
111 .er_irq = I2C1_ER_IRQn,
113 #endif
114 #ifdef USE_I2C_DEVICE_2
116 .device = I2CDEV_2,
117 .reg = I2C2,
118 .sclPins = { I2CPINDEF(PB10, GPIO_AF4_I2C2), I2CPINDEF(PF1, GPIO_AF4_I2C2) },
119 .sdaPins = { I2CPINDEF(PB11, GPIO_AF4_I2C2), I2CPINDEF(PF0, GPIO_AF4_I2C2) },
120 .rcc = RCC_APB1L(I2C2),
121 .ev_irq = I2C2_EV_IRQn,
122 .er_irq = I2C2_ER_IRQn,
124 #endif
125 #ifdef USE_I2C_DEVICE_3
127 .device = I2CDEV_3,
128 .reg = I2C3,
129 .sclPins = { I2CPINDEF(PA8, GPIO_AF4_I2C3) },
130 .sdaPins = { I2CPINDEF(PC9, GPIO_AF4_I2C3) },
131 .rcc = RCC_APB1L(I2C3),
132 .ev_irq = I2C3_EV_IRQn,
133 .er_irq = I2C3_ER_IRQn,
135 #endif
136 #ifdef USE_I2C_DEVICE_4
138 .device = I2CDEV_4,
139 .reg = I2C4,
140 .sclPins = { I2CPINDEF(PD12, GPIO_AF4_I2C4), I2CPINDEF(PF14, GPIO_AF4_I2C4), I2CPINDEF(PB6, GPIO_AF6_I2C4), I2CPINDEF(PB8, GPIO_AF6_I2C4) },
141 .sdaPins = { I2CPINDEF(PD13, GPIO_AF4_I2C4), I2CPINDEF(PF15, GPIO_AF4_I2C4), I2CPINDEF(PB7, GPIO_AF6_I2C4), I2CPINDEF(PB9, GPIO_AF6_I2C4) },
142 .rcc = RCC_APB4(I2C4),
143 .ev_irq = I2C4_EV_IRQn,
144 .er_irq = I2C4_ER_IRQn,
146 #endif
147 #elif defined(STM32G4)
148 #ifdef USE_I2C_DEVICE_1
150 .device = I2CDEV_1,
151 .reg = I2C1,
153 // Some boards are overloading SWD pins with I2C1 for maximum pin utilization on 48-pin CE(U) packages.
154 // Be carefull when using SWD on these boards if I2C1 pins are defined by default.
156 .sclPins = { I2CPINDEF(PA13, GPIO_AF4_I2C1), I2CPINDEF(PA15, GPIO_AF4_I2C1), I2CPINDEF(PB6, GPIO_AF4_I2C1), I2CPINDEF(PB8, GPIO_AF4_I2C1), },
157 .sdaPins = { I2CPINDEF(PA14, GPIO_AF4_I2C1), I2CPINDEF(PB7, GPIO_AF4_I2C1), I2CPINDEF(PB9, GPIO_AF4_I2C1), },
158 .rcc = RCC_APB11(I2C1),
159 .ev_irq = I2C1_EV_IRQn,
160 .er_irq = I2C1_ER_IRQn,
162 #endif
163 #ifdef USE_I2C_DEVICE_2
165 .device = I2CDEV_2,
166 .reg = I2C2,
167 .sclPins = { I2CPINDEF(PA9, GPIO_AF4_I2C2), },
168 .sdaPins = { I2CPINDEF(PA10, GPIO_AF4_I2C2), },
169 .rcc = RCC_APB11(I2C2),
170 .ev_irq = I2C2_EV_IRQn,
171 .er_irq = I2C2_ER_IRQn,
173 #endif
174 #ifdef USE_I2C_DEVICE_3
176 .device = I2CDEV_3,
177 .reg = I2C3,
178 .sclPins = { I2CPINDEF(PA10, GPIO_AF2_I2C3), I2CPINDEF(PC8, GPIO_AF8_I2C3), },
179 .sdaPins = { I2CPINDEF(PB5, GPIO_AF8_I2C3), I2CPINDEF(PC9, GPIO_AF8_I2C3), I2CPINDEF(PC11, GPIO_AF8_I2C3), },
180 .rcc = RCC_APB11(I2C3),
181 .ev_irq = I2C3_EV_IRQn,
182 .er_irq = I2C3_ER_IRQn,
184 #endif
185 #ifdef USE_I2C_DEVICE_4
187 .device = I2CDEV_4,
188 .reg = I2C4,
190 // Here, SWDIO(PA13) is overloaded with I2C4_SCL, too.
191 // See comment in the I2C1 section above.
193 .sclPins = { I2CPINDEF(PA13, GPIO_AF3_I2C4), I2CPINDEF(PB6, GPIO_AF3_I2C4), I2CPINDEF(PC6, GPIO_AF8_I2C4), },
194 .sdaPins = { I2CPINDEF(PB7, GPIO_AF4_I2C4), I2CPINDEF(PC7, GPIO_AF8_I2C4), },
195 .rcc = RCC_APB12(I2C4),
196 .ev_irq = I2C4_EV_IRQn,
197 .er_irq = I2C4_ER_IRQn,
199 #endif
200 #endif
203 i2cDevice_t i2cDevice[I2CDEV_COUNT];
205 // Values from I2C-SMBus specification
206 static uint16_t trmax; // Rise time (max)
207 static uint16_t tfmax; // Fall time (max)
208 static uint8_t tsuDATmin; // SDA setup time (min)
209 static uint8_t thdDATmin; // SDA hold time (min)
210 static uint16_t tHIGHmin; // High period of SCL clock (min)
211 static uint16_t tLOWmin; // Low period of SCL clock (min)
213 // Silicon specific values, from datasheet
214 static uint8_t tAFmin; // Analog filter delay (min)
215 static uint16_t tAFmax; // Analog filter delay (max)
217 // Actual (estimated) values
218 static uint16_t tr = 100; // Rise time
219 static uint16_t tf = 10; // Fall time
222 * Compute SCLDEL, SDADEL, SCLH and SCLL for TIMINGR register according to reference manuals.
224 static void i2cClockComputeRaw(uint32_t pclkFreq, int i2cFreqKhz, int presc, int dfcoeff,
225 uint8_t *scldel, uint8_t *sdadel, uint16_t *sclh, uint16_t *scll)
227 if (i2cFreqKhz > 400) {
228 // Fm+ (Fast mode plus)
229 trmax = 120;
230 tfmax = 120;
231 tsuDATmin = 50;
232 thdDATmin = 0;
233 tHIGHmin = 260;
234 tLOWmin = 500;
235 } else {
236 // Fm (Fast mode)
237 trmax = 300;
238 tfmax = 300;
239 tsuDATmin = 100;
240 thdDATmin = 0;
241 tHIGHmin = 600;
242 tLOWmin = 1300;
244 tAFmin = 50;
245 tAFmax = 90;
247 // Convert pclkFreq into nsec
248 float tI2cclk = 1000000000.0f / pclkFreq;
250 // Convert target i2cFreq into cycle time (nsec)
251 float tSCL = 1000000.0f / i2cFreqKhz;
253 uint32_t SCLDELmin = (trmax + tsuDATmin)/((presc + 1) * tI2cclk) - 1;
255 uint32_t SDADELmin = (tfmax + thdDATmin - tAFmin - ((dfcoeff + 3) * tI2cclk)) / ((presc + 1) * tI2cclk);
257 float tsync1 = tf + tAFmin + dfcoeff * tI2cclk + 2 * tI2cclk;
258 float tsync2 = tr + tAFmin + dfcoeff * tI2cclk + 2 * tI2cclk;
260 float tSCLH = tHIGHmin * tSCL / (tHIGHmin + tLOWmin) - tsync2;
261 float tSCLL = tSCL - tSCLH - tsync1 - tsync2;
263 uint32_t SCLH = tSCLH / ((presc + 1) * tI2cclk) - 1;
264 uint32_t SCLL = tSCLL / ((presc + 1) * tI2cclk) - 1;
266 while (tsync1 + tsync2 + ((SCLH + 1) + (SCLL + 1)) * ((presc + 1) * tI2cclk) < tSCL) {
267 SCLH++;
270 *scldel = SCLDELmin;
271 *sdadel = SDADELmin;
272 *sclh = SCLH;
273 *scll = SCLL;
276 static uint32_t i2cClockTIMINGR(uint32_t pclkFreq, int i2cFreqKhz, int dfcoeff)
278 #define TIMINGR(presc, scldel, sdadel, sclh, scll) \
279 ((presc << 28)|(scldel << 20)|(sdadel << 16)|(sclh << 8)|(scll << 0))
281 uint8_t scldel;
282 uint8_t sdadel;
283 uint16_t sclh;
284 uint16_t scll;
286 for (int presc = 0; presc < 15; presc++) {
287 i2cClockComputeRaw(pclkFreq, i2cFreqKhz, presc, dfcoeff, &scldel, &sdadel, &sclh, &scll);
289 // If all fields are not overflowing, return TIMINGR.
290 // Otherwise, increase prescaler and try again.
291 if ((scldel < 16) && (sdadel < 16) && (sclh < 256) && (scll < 256)) {
292 return TIMINGR(presc, scldel, sdadel, sclh, scll);
295 return 0; // Shouldn't reach here
298 void i2cInit(I2CDevice device)
300 if (device == I2CINVALID) {
301 return;
304 i2cDevice_t *pDev = &i2cDevice[device];
306 const i2cHardware_t *hardware = pDev->hardware;
307 const IO_t scl = pDev->scl;
308 const IO_t sda = pDev->sda;
310 if (!hardware || IOGetOwner(scl) || IOGetOwner(sda)) {
311 return;
314 IOInit(scl, OWNER_I2C_SCL, RESOURCE_INDEX(device));
315 IOInit(sda, OWNER_I2C_SDA, RESOURCE_INDEX(device));
317 // Enable RCC
318 RCC_ClockCmd(hardware->rcc, ENABLE);
320 i2cUnstick(scl, sda);
322 // Init pins
323 #if defined(STM32F7)
324 IOConfigGPIOAF(scl, pDev->pullUp ? IOCFG_I2C_PU : IOCFG_I2C, GPIO_AF4_I2C);
325 IOConfigGPIOAF(sda, pDev->pullUp ? IOCFG_I2C_PU : IOCFG_I2C, GPIO_AF4_I2C);
326 #elif defined(STM32H7) || defined(STM32G4)
327 IOConfigGPIOAF(scl, pDev->pullUp ? IOCFG_I2C_PU : IOCFG_I2C, pDev->sclAF);
328 IOConfigGPIOAF(sda, pDev->pullUp ? IOCFG_I2C_PU : IOCFG_I2C, pDev->sdaAF);
329 #else
330 IOConfigGPIO(scl, IOCFG_AF_OD);
331 IOConfigGPIO(sda, IOCFG_AF_OD);
332 #endif
334 // Init I2C peripheral
336 I2C_HandleTypeDef *pHandle = &pDev->handle;
338 memset(pHandle, 0, sizeof(*pHandle));
340 pHandle->Instance = pDev->hardware->reg;
342 // Compute TIMINGR value based on peripheral clock for this device instance
344 uint32_t i2cPclk;
346 #if defined(STM32F7) || defined(STM32G4)
347 // F7 Clock source configured in startup/system_stm32f7xx.c as:
348 // I2C1234 : PCLK1
349 // G4 Clock source configured in startup/system_stm32g4xx.c as:
350 // I2C1234 : PCLK1
351 i2cPclk = HAL_RCC_GetPCLK1Freq();
352 #elif defined(STM32H7)
353 // Clock sources configured in startup/system_stm32h7xx.c as:
354 // I2C123 : D2PCLK1 (rcc_pclk1 for APB1)
355 // I2C4 : D3PCLK1 (rcc_pclk4 for APB4)
356 i2cPclk = (pHandle->Instance == I2C4) ? HAL_RCCEx_GetD3PCLK1Freq() : HAL_RCC_GetPCLK1Freq();
357 #else
358 #error Unknown MCU type
359 #endif
361 pHandle->Init.Timing = i2cClockTIMINGR(i2cPclk, pDev->overClock ? 800 : 400, 0);
363 pHandle->Init.OwnAddress1 = 0x0;
364 pHandle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
365 pHandle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
366 pHandle->Init.OwnAddress2 = 0x0;
367 pHandle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
368 pHandle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
370 HAL_I2C_Init(pHandle);
372 // Enable the Analog I2C Filter
373 HAL_I2CEx_ConfigAnalogFilter(pHandle, I2C_ANALOGFILTER_ENABLE);
375 // Setup interrupt handlers
376 HAL_NVIC_SetPriority(hardware->er_irq, NVIC_PRIORITY_BASE(NVIC_PRIO_I2C_ER), NVIC_PRIORITY_SUB(NVIC_PRIO_I2C_ER));
377 HAL_NVIC_EnableIRQ(hardware->er_irq);
378 HAL_NVIC_SetPriority(hardware->ev_irq, NVIC_PRIORITY_BASE(NVIC_PRIO_I2C_EV), NVIC_PRIORITY_SUB(NVIC_PRIO_I2C_EV));
379 HAL_NVIC_EnableIRQ(hardware->ev_irq);
382 static void i2cUnstick(IO_t scl, IO_t sda)
384 int i;
386 IOHi(scl);
387 IOHi(sda);
389 IOConfigGPIO(scl, IOCFG_OUT_OD);
390 IOConfigGPIO(sda, IOCFG_OUT_OD);
392 // Clock out, with SDA high:
393 // 7 data bits
394 // 1 READ bit
395 // 1 cycle for the ACK
396 for (i = 0; i < (LEN_ADDR + LEN_RW + LEN_ACK); i++) {
397 // Wait for any clock stretching to finish
398 int timeout = UNSTICK_CLK_STRETCH;
399 while (!IORead(scl) && timeout) {
400 delayMicroseconds(UNSTICK_CLK_US);
401 timeout--;
404 // Pull low
405 IOLo(scl); // Set bus low
406 delayMicroseconds(UNSTICK_CLK_US/2);
407 IOHi(scl); // Set bus high
408 delayMicroseconds(UNSTICK_CLK_US/2);
411 // Generate a stop condition in case there was none
412 IOLo(scl);
413 delayMicroseconds(UNSTICK_CLK_US/2);
414 IOLo(sda);
415 delayMicroseconds(UNSTICK_CLK_US/2);
417 IOHi(scl); // Set bus scl high
418 delayMicroseconds(UNSTICK_CLK_US/2);
419 IOHi(sda); // Set bus sda high
422 #endif