Skip to content

Commit a74e4fa

Browse files
yn386dpgeorge
authored andcommitted
stm32/i2c: Fix I2C frequency calc so it doesn't exceed requested rate.
Prior to this commit, the actual I2C frequency can be faster than specified one and it may exceed the I2C's specification for Fast Mode. The frequency of SCL should be less than or equal to 400KHz in Fast Mode. This commit fixes this issue for F4 MCUs by rounding up the division in the frequency calculation.
1 parent 65d8206 commit a74e4fa

File tree

3 files changed

+11
-2
lines changed

3 files changed

+11
-2
lines changed

docs/library/machine.I2C.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ General Methods
9191
- *sda* is a pin object for the SDA line
9292
- *freq* is the SCL clock rate
9393

94+
In the case of hardware I2C the actual clock frequency may be lower than the
95+
requested frequency. This is dependant on the platform hardware. The actual
96+
rate may be determined by printing the I2C object.
97+
9498
.. method:: I2C.deinit()
9599

96100
Turn off the I2C bus.

docs/library/pyb.I2C.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ Methods
9696
that DMA transfers have more precise timing but currently do not handle bus
9797
errors properly)
9898

99+
The actual clock frequency may be lower than the requested frequency.
100+
This is dependant on the platform hardware. The actual rate may be determined
101+
by printing the I2C object.
102+
99103
.. method:: I2C.is_ready(addr)
100104

101105
Check if an I2C device responds to the given address. Only valid when in controller mode.

ports/stm32/i2c.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,11 @@ int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t fr
7070

7171
// SM: MAX(4, PCLK1 / (F * 2))
7272
// FM, 16:9 duty: 0xc000 | MAX(1, (PCLK1 / (F * (16 + 9))))
73+
// (the PCLK1-1 and +1 at the end is to round the division up)
7374
if (freq <= 100000) {
74-
i2c->CCR = MAX(4, PCLK1 / (freq * 2));
75+
i2c->CCR = MAX(4, ((PCLK1 - 1) / (freq * 2) + 1));
7576
} else {
76-
i2c->CCR = 0xc000 | MAX(1, PCLK1 / (freq * 25));
77+
i2c->CCR = 0xc000 | MAX(1, ((PCLK1 - 1) / (freq * 25) + 1));
7778
}
7879

7980
// SM: 1000ns / (1/PCLK1) + 1 = PCLK1 * 1e-6 + 1

0 commit comments

Comments
 (0)