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/>.
26 * Compute SCLDEL, SDADEL, SCLH and SCLL for TIMINGR register according to reference manuals.
28 static void i2cClockComputeRaw(uint32_t pclkFreq
, int i2cFreqKhz
, int presc
, int dfcoeff
,
29 uint8_t *scldel
, uint8_t *sdadel
, uint16_t *sclh
, uint16_t *scll
)
31 // Values from I2C-SMBus specification
32 uint16_t trmax
; // Rise time (max)
33 uint16_t tfmax
; // Fall time (max)
34 uint8_t tsuDATmin
; // SDA setup time (min)
35 uint8_t thdDATmin
; // SDA hold time (min)
36 uint16_t tHIGHmin
; // High period of SCL clock (min)
37 uint16_t tLOWmin
; // Low period of SCL clock (min)
39 // Silicon specific values, from datasheet
40 uint8_t tAFmin
= 50; // Analog filter delay (min)
42 // Actual (estimated) values
43 uint8_t tr
= 100; // Rise time
44 uint8_t tf
= 10; // Fall time
46 if (i2cFreqKhz
> 400) {
47 // Fm+ (Fast mode plus)
64 // Convert pclkFreq into nsec
65 float tI2cclk
= 1000000000.0f
/ pclkFreq
;
67 // Convert target i2cFreq into cycle time (nsec)
68 float tSCL
= 1000000.0f
/ i2cFreqKhz
;
70 uint32_t SCLDELmin
= (trmax
+ tsuDATmin
) / ((presc
+ 1) * tI2cclk
) - 1;
71 uint32_t SDADELmin
= (tfmax
+ thdDATmin
- tAFmin
- ((dfcoeff
+ 3) * tI2cclk
)) / ((presc
+ 1) * tI2cclk
);
73 float tsync1
= tf
+ tAFmin
+ dfcoeff
* tI2cclk
+ 2 * tI2cclk
;
74 float tsync2
= tr
+ tAFmin
+ dfcoeff
* tI2cclk
+ 2 * tI2cclk
;
76 float tSCLH
= tHIGHmin
* tSCL
/ (tHIGHmin
+ tLOWmin
) - tsync2
;
77 float tSCLL
= tSCL
- tSCLH
- tsync1
- tsync2
;
79 uint32_t SCLH
= tSCLH
/ ((presc
+ 1) * tI2cclk
) - 1;
80 uint32_t SCLL
= tSCLL
/ ((presc
+ 1) * tI2cclk
) - 1;
82 while (tsync1
+ tsync2
+ ((SCLH
+ 1) + (SCLL
+ 1)) * ((presc
+ 1) * tI2cclk
) < tSCL
) {
92 uint32_t i2cClockTIMINGR(uint32_t pclkFreq
, int i2cFreqKhz
, int dfcoeff
)
94 #define TIMINGR(presc, scldel, sdadel, sclh, scll) \
95 ((presc << 28)|(scldel << 20)|(sdadel << 16)|(sclh << 8)|(scll << 0))
102 for (int presc
= 0; presc
< 15; presc
++) {
103 i2cClockComputeRaw(pclkFreq
, i2cFreqKhz
, presc
, dfcoeff
, &scldel
, &sdadel
, &sclh
, &scll
);
105 // If all fields are not overflowing, return TIMINGR.
106 // Otherwise, increase prescaler and try again.
107 if ((scldel
< 16) && (sdadel
< 16) && (sclh
< 256) && (scll
< 256)) {
108 return TIMINGR(presc
, scldel
, sdadel
, sclh
, scll
);
111 return 0; // Shouldn't reach here