diff --git a/include/libopencm3/stm32/common/i2c_common_v1.h b/include/libopencm3/stm32/common/i2c_common_v1.h index b13bffc5..e4998c61 100644 --- a/include/libopencm3/stm32/common/i2c_common_v1.h +++ b/include/libopencm3/stm32/common/i2c_common_v1.h @@ -362,6 +362,16 @@ specific memorymap.h header before including this header file.*/ /* --- I2C function prototypes---------------------------------------------- */ +/** + * I2C speed modes. + */ +enum i2c_speeds { + i2c_speed_sm_100k, + i2c_speed_fm_400k, + i2c_speed_fmp_1m, + i2c_speed_unknown +}; + BEGIN_DECLS void i2c_reset(uint32_t i2c); @@ -395,6 +405,7 @@ void i2c_disable_dma(uint32_t i2c); void i2c_set_dma_last_transfer(uint32_t i2c); void i2c_clear_dma_last_transfer(uint32_t i2c); void i2c_transfer7(uint32_t i2c, uint8_t addr, uint8_t *w, size_t wn, uint8_t *r, size_t rn); +void i2c_set_speed(uint32_t i2c, enum i2c_speeds speed, uint32_t clock_megahz); END_DECLS diff --git a/include/libopencm3/stm32/common/i2c_common_v2.h b/include/libopencm3/stm32/common/i2c_common_v2.h index 3012fd7f..1a9df080 100644 --- a/include/libopencm3/stm32/common/i2c_common_v2.h +++ b/include/libopencm3/stm32/common/i2c_common_v2.h @@ -386,6 +386,16 @@ specific memorymap.h header before including this header file.*/ /* --- I2C function prototypes---------------------------------------------- */ +/** + * I2C speed modes. + */ +enum i2c_speeds { + i2c_speed_sm_100k, + i2c_speed_fm_400k, + i2c_speed_fmp_1m, + i2c_speed_unknown +}; + BEGIN_DECLS void i2c_reset(uint32_t i2c); @@ -431,6 +441,7 @@ void i2c_disable_rxdma(uint32_t i2c); void i2c_enable_txdma(uint32_t i2c); void i2c_disable_txdma(uint32_t i2c); void i2c_transfer7(uint32_t i2c, uint8_t addr, uint8_t *w, size_t wn, uint8_t *r, size_t rn); +void i2c_set_speed(uint32_t i2c, enum i2c_speeds speed, uint32_t clock_megahz); END_DECLS diff --git a/lib/stm32/common/i2c_common_v1.c b/lib/stm32/common/i2c_common_v1.c index dff41272..2cd5785a 100644 --- a/lib/stm32/common/i2c_common_v1.c +++ b/lib/stm32/common/i2c_common_v1.c @@ -539,5 +539,32 @@ void i2c_transfer7(uint32_t i2c, uint8_t addr, uint8_t *w, size_t wn, uint8_t *r } } +/** + * Set the i2c communication speed. + * @param i2c peripheral, eg I2C1 + * @param speed one of the listed speed modes @ref i2c_speeds + * @param clock_megahz i2c peripheral clock speed in MHz. Usually, rcc_apb1_frequency / 1e6 + */ +void i2c_set_speed(uint32_t i2c, enum i2c_speeds speed, uint32_t clock_megahz) +{ + i2c_set_clock_frequency(i2c, clock_megahz); + switch(speed) { + case i2c_speed_fm_400k: + i2c_set_fast_mode(i2c); + i2c_set_ccr(i2c, clock_megahz * 5 / 6); + i2c_set_trise(i2c, clock_megahz + 1); + break; + default: + /* fall back to standard mode */ + case i2c_speed_sm_100k: + i2c_set_standard_mode(i2c); + /* x Mhz / (100kHz * 2) */ + i2c_set_ccr(i2c, clock_megahz * 5); + /* Sm mode, (100kHz) freqMhz + 1 */ + i2c_set_trise(i2c, clock_megahz + 1); + break; + } +} + /**@}*/ diff --git a/lib/stm32/common/i2c_common_v2.c b/lib/stm32/common/i2c_common_v2.c index 2dd5db8e..2116064f 100644 --- a/lib/stm32/common/i2c_common_v2.c +++ b/lib/stm32/common/i2c_common_v2.c @@ -436,4 +436,42 @@ void i2c_transfer7(uint32_t i2c, uint8_t addr, uint8_t *w, size_t wn, uint8_t *r } +/** + * Set the i2c communication speed. + * NOTE: 1MHz mode not yet implemented! + * Min clock speed: 8MHz for FM, 2Mhz for SM, + * @param i2c peripheral, eg I2C1 + * @param speed one of the listed speed modes @ref i2c_speeds + * @param clock_megahz i2c peripheral clock speed in MHz. Usually, rcc_apb1_frequency / 1e6 + */ +void i2c_set_speed(uint32_t i2c, enum i2c_speeds speed, uint32_t clock_megahz) +{ + int prescaler; + switch(speed) { + case i2c_speed_fmp_1m: + /* FIXME - add support for this mode! */ + break; + case i2c_speed_fm_400k: + /* target 8Mhz input, so tpresc = 125ns */ + prescaler = clock_megahz / 8 - 1; + i2c_set_prescaler(i2c, prescaler); + i2c_set_scl_low_period(i2c, 10-1); // 1250ns + i2c_set_scl_high_period(i2c, 4-1); // 500ns + i2c_set_data_hold_time(i2c, 3); // 375ns + i2c_set_data_setup_time(i2c, 4-1); // 500ns + break; + default: + /* fall back to standard mode */ + case i2c_speed_sm_100k: + /* target 4Mhz input, so tpresc = 250ns */ + prescaler = (clock_megahz / 4) - 1; + i2c_set_prescaler(i2c, prescaler); + i2c_set_scl_low_period(i2c, 20-1); // 5usecs + i2c_set_scl_high_period(i2c, 16-1); // 4usecs + i2c_set_data_hold_time(i2c, 2); // 0.5usecs + i2c_set_data_setup_time(i2c, 5-1); // 1.25usecs + break; + } +} + /**@}*/