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/>.
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)
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
) {
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))
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