Refactor missing prototypes 2 (#14170)
[betaflight.git] / src / main / drivers / bus_i2c_timing.c
blobf196fd385f7e675c53d0e5b88a4dc9c32349b06d
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 <stdint.h>
23 #include "platform.h"
25 #include "bus_i2c_timing.h"
28 * Compute SCLDEL, SDADEL, SCLH and SCLL for TIMINGR register according to reference manuals.
30 static void i2cClockComputeRaw(uint32_t pclkFreq, int i2cFreqKhz, int presc, int dfcoeff,
31 uint8_t *scldel, uint8_t *sdadel, uint16_t *sclh, uint16_t *scll)
33 // Values from I2C-SMBus specification
34 uint16_t trmax; // Rise time (max)
35 uint16_t tfmax; // Fall time (max)
36 uint8_t tsuDATmin; // SDA setup time (min)
37 uint8_t thdDATmin; // SDA hold time (min)
38 uint16_t tHIGHmin; // High period of SCL clock (min)
39 uint16_t tLOWmin; // Low period of SCL clock (min)
41 // Silicon specific values, from datasheet
42 uint8_t tAFmin = 50; // Analog filter delay (min)
44 // Actual (estimated) values
45 uint8_t tr = 100; // Rise time
46 uint8_t tf = 10; // Fall time
48 if (i2cFreqKhz > 400) {
49 // Fm+ (Fast mode plus)
50 trmax = 120;
51 tfmax = 120;
52 tsuDATmin = 50;
53 thdDATmin = 0;
54 tHIGHmin = 260;
55 tLOWmin = 500;
56 } else {
57 // Fm (Fast mode)
58 trmax = 300;
59 tfmax = 300;
60 tsuDATmin = 100;
61 thdDATmin = 0;
62 tHIGHmin = 600;
63 tLOWmin = 1300;
66 // Convert pclkFreq into nsec
67 float tI2cclk = 1000000000.0f / pclkFreq;
69 // Convert target i2cFreq into cycle time (nsec)
70 float tSCL = 1000000.0f / i2cFreqKhz;
72 uint32_t SCLDELmin = (trmax + tsuDATmin) / ((presc + 1) * tI2cclk) - 1;
73 uint32_t SDADELmin = (tfmax + thdDATmin - tAFmin - ((dfcoeff + 3) * tI2cclk)) / ((presc + 1) * tI2cclk);
75 float tsync1 = tf + tAFmin + dfcoeff * tI2cclk + 2 * tI2cclk;
76 float tsync2 = tr + tAFmin + dfcoeff * tI2cclk + 2 * tI2cclk;
78 float tSCLH = tHIGHmin * tSCL / (tHIGHmin + tLOWmin) - tsync2;
79 float tSCLL = tSCL - tSCLH - tsync1 - tsync2;
81 uint32_t SCLH = tSCLH / ((presc + 1) * tI2cclk) - 1;
82 uint32_t SCLL = tSCLL / ((presc + 1) * tI2cclk) - 1;
84 while (tsync1 + tsync2 + ((SCLH + 1) + (SCLL + 1)) * ((presc + 1) * tI2cclk) < tSCL) {
85 SCLH++;
88 *scldel = SCLDELmin;
89 *sdadel = SDADELmin;
90 *sclh = SCLH;
91 *scll = SCLL;
94 uint32_t i2cClockTIMINGR(uint32_t pclkFreq, int i2cFreqKhz, int dfcoeff)
96 #define TIMINGR(presc, scldel, sdadel, sclh, scll) \
97 ((presc << 28)|(scldel << 20)|(sdadel << 16)|(sclh << 8)|(scll << 0))
99 uint8_t scldel;
100 uint8_t sdadel;
101 uint16_t sclh;
102 uint16_t scll;
104 for (int presc = 0; presc < 15; presc++) {
105 i2cClockComputeRaw(pclkFreq, i2cFreqKhz, presc, dfcoeff, &scldel, &sdadel, &sclh, &scll);
107 // If all fields are not overflowing, return TIMINGR.
108 // Otherwise, increase prescaler and try again.
109 if ((scldel < 16) && (sdadel < 16) && (sclh < 256) && (scll < 256)) {
110 return TIMINGR(presc, scldel, sdadel, sclh, scll);
113 return 0; // Shouldn't reach here