From 5e1ba4064104c64d383f083dd233de858a47aae8 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Thu, 23 Mar 2017 23:37:25 +0000 Subject: i2c-master: add 400k speed support on v1/v2 --- tests/i2c-master/i2c-master.c | 59 ++++++++++++++++++++++----------- tests/i2c-master/main-stm32f072-disco.c | 5 ++- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/tests/i2c-master/i2c-master.c b/tests/i2c-master/i2c-master.c index 7eb2f6f..bcaa1db 100644 --- a/tests/i2c-master/i2c-master.c +++ b/tests/i2c-master/i2c-master.c @@ -27,6 +27,9 @@ enum sht21_cmd_e { // ------------------ section proposed to go up to libopencm3 +/** + * I2C speed modes. + */ enum i2c_speeds { i2c_speed_sm_100k, i2c_speed_fm_400k, @@ -35,18 +38,24 @@ enum i2c_speeds { }; /* to go to i2c-v1 impl file, with common name.... */ +/** + * Set the i2c communicaton speed. + * @param p 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 + */ static void i2c_set_speed_v1(uint32_t p, enum i2c_speeds speed, uint32_t clock_megahz) { -#if defined(I2C_SR2) + i2c_set_clock_frequency(p, clock_megahz); switch(speed) { case i2c_speed_fm_400k: - // FIXME - printf("oops, haven't gotten 400k yet!, grab chucks code from pr470!"); + i2c_set_fast_mode(p); + i2c_set_ccr(p, clock_megahz * 5 / 6); + i2c_set_trise(p, clock_megahz + 1); break; default: /* fall back to standard mode */ case i2c_speed_sm_100k: - i2c_set_clock_frequency(p, clock_megahz); i2c_set_standard_mode(p); /* x Mhz / (100kHz * 2) */ i2c_set_ccr(p, clock_megahz * 5); @@ -54,37 +63,45 @@ static void i2c_set_speed_v1(uint32_t p, enum i2c_speeds speed, uint32_t clock_m i2c_set_trise(p, clock_megahz + 1); break; } -#else - (void)p; - (void)speed; - (void)clock_megahz; -#endif } /* to go to i2c-v2 impl file, with common name.... */ +/** + * Set the i2c communicaton speed. + * NOTE: 1MHz mode not yet implemented! + * Min clock speed: 8MHz for FM, 2Mhz for SM, + * @param p 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 + */ static void i2c_set_speed_v2(uint32_t p, enum i2c_speeds speed, uint32_t clock_megahz) { -#if !defined(I2C_SR2) int prescaler; switch(speed) { case i2c_speed_fmp_1m: + /* FIXME - add support for this mode! */ + break; case i2c_speed_fm_400k: - // FIXME - printf("oops, haven't gotten to those speeds yet!"); + /* target 8Mhz input, so tpresc = 125ns */ + prescaler = clock_megahz / 8 - 1; + i2c_set_prescaler(p, prescaler); + i2c_set_scl_low_period(p, 0x9); // 1250ns + i2c_set_scl_high_period(p, 3); // 500ns + i2c_set_data_hold_time(p, 2); // 250ns + i2c_set_data_setup_time(p, 2); // 375ns break; default: /* fall back to standard mode */ case i2c_speed_sm_100k: /* target 2Mhz input, so tpresc = 500ns */ - prescaler = clock_megahz / 2 - 1; + prescaler = clock_megahz / 4 - 1; i2c_set_prescaler(p, prescaler); - i2c_set_scl_low_period(p, 9); // 5usecs - i2c_set_scl_high_period(p, 7); // 4usecs - i2c_set_data_hold_time(p, 1); // 0.5usecs - i2c_set_data_setup_time(p, 2); // 1.25usecs + i2c_set_scl_low_period(p, 0x13); // 5usecs + i2c_set_scl_high_period(p, 0xf); // 4usecs + i2c_set_data_hold_time(p, 2); // 0.5usecs + i2c_set_data_setup_time(p, 4); // 1.25usecs break; } -#endif } @@ -108,6 +125,7 @@ static void i2c_set_speed(uint32_t p, enum i2c_speeds speed, uint32_t clock_mega static void i2c_write7_v1(uint32_t i2c, int addr, uint8_t *data, size_t n) { +#if defined(I2C_SR1) while ((I2C_SR2(i2c) & I2C_SR2_BUSY)) { } @@ -131,10 +149,12 @@ static void i2c_write7_v1(uint32_t i2c, int addr, uint8_t *data, size_t n) i2c_send_data(i2c, data[i]); while (!(I2C_SR1(i2c) & (I2C_SR1_BTF))); } +#endif } static void i2c_read7_v1(uint32_t i2c, int addr, uint8_t *res, int n) { +#if defined(I2C_SR1) i2c_send_start(i2c); i2c_enable_ack(i2c); @@ -161,6 +181,7 @@ static void i2c_read7_v1(uint32_t i2c, int addr, uint8_t *res, int n) i2c_send_stop(i2c); return; +#endif } /* v1 isn't handling stop/start vs repeated start very well yet */ @@ -247,9 +268,9 @@ void i2cm_init(void) { rcc_periph_clock_enable(hw_details.periph_rcc); rcc_periph_reset_pulse(hw_details.periph_rst); - // i2c_enable_ack(hw_details.periph); /* NO ACK FOR SHT21! */ i2c_set_speed(hw_details.periph, i2c_speed_sm_100k, hw_details.i2c_clock_megahz); + //i2c_set_speed(hw_details.periph, i2c_speed_fm_400k, hw_details.i2c_clock_megahz); i2c_peripheral_enable(hw_details.periph); } diff --git a/tests/i2c-master/main-stm32f072-disco.c b/tests/i2c-master/main-stm32f072-disco.c index 8818665..b156e3c 100644 --- a/tests/i2c-master/main-stm32f072-disco.c +++ b/tests/i2c-master/main-stm32f072-disco.c @@ -28,7 +28,7 @@ struct hw_detail hw_details = { .trigger_rcc = RCC_GPIOB, .trigger_port = GPIOB, .trigger_pin = GPIO12, - .i2c_clock_megahz = 48, // FIXME + .i2c_clock_megahz = 48, }; @@ -67,6 +67,9 @@ static void i2cm_hw_init(void) gpio_mode_setup(hw_details.port, GPIO_MODE_AF, GPIO_PUPD_NONE, hw_details.pins); gpio_set_output_options(hw_details.port, GPIO_OTYPE_OD, GPIO_OSPEED_HIGH, hw_details.pins); gpio_set_af(hw_details.port, GPIO_AF1, hw_details.pins); + + /* select sysclk as i2c clock! */ + RCC_CFGR3 |= RCC_CFGR3_I2C1SW; } -- cgit