stm32: i2c: Support auto speed configuration
For both v1 and v2, support automatic calculation of timing registers for 100khz and 400khz i2c modes. Based on work by Chuck in https://github.com/libopencm3/libopencm3/pull/470 for v1
This commit is contained in:
parent
f3df01f14e
commit
6678da39bd
@ -362,6 +362,16 @@ specific memorymap.h header before including this header file.*/
|
|||||||
|
|
||||||
/* --- I2C function prototypes---------------------------------------------- */
|
/* --- 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
|
BEGIN_DECLS
|
||||||
|
|
||||||
void i2c_reset(uint32_t i2c);
|
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_set_dma_last_transfer(uint32_t i2c);
|
||||||
void i2c_clear_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_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
|
END_DECLS
|
||||||
|
|
||||||
|
@ -386,6 +386,16 @@ specific memorymap.h header before including this header file.*/
|
|||||||
|
|
||||||
/* --- I2C function prototypes---------------------------------------------- */
|
/* --- 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
|
BEGIN_DECLS
|
||||||
|
|
||||||
void i2c_reset(uint32_t i2c);
|
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_enable_txdma(uint32_t i2c);
|
||||||
void i2c_disable_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_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
|
END_DECLS
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user