Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i2c: set hold time of SDA during transmit to an appropriate value #273

Merged
merged 7 commits into from
Apr 6, 2021
10 changes: 10 additions & 0 deletions src/rp2_common/hardware_i2c/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ uint i2c_set_baudrate(i2c_inst_t *i2c, uint baudrate) {
invalid_params_if(I2C, hcnt < 8);
invalid_params_if(I2C, lcnt < 8);

// The SDA hold time should be at least 300 ns, per the I2C standard.
// sda_hold_count [cycles] = freq_in [cycles/s] * 300ns * (1s / 1e9ns)
// Reduce 300/1e9 to 3/1e7 to avoid numbers that don't fit in uint.
// Add 1 to avoid division truncation.
uint sda_hold_count = ((freq_in * 3) / 10000000) + 1;
fivdi marked this conversation as resolved.
Show resolved Hide resolved
invalid_params_if(I2C, sda_hold_count > lcnt - 2);
fivdi marked this conversation as resolved.
Show resolved Hide resolved

i2c->hw->enable = 0;
// Always use "fast" mode (<= 400 kHz, works fine for standard mode too)
hw_write_masked(&i2c->hw->con,
Expand All @@ -84,6 +91,9 @@ uint i2c_set_baudrate(i2c_inst_t *i2c, uint baudrate) {
i2c->hw->fs_scl_hcnt = hcnt;
i2c->hw->fs_scl_lcnt = lcnt;
i2c->hw->fs_spklen = lcnt < 16 ? 1 : lcnt / 16;
hw_write_masked(&i2c->hw->sda_hold,
sda_hold_count,
I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD_BITS);

i2c->hw->enable = 1;
return freq_in / period;
Expand Down