From c801bb6038620205ef9d933e875b54a146126254 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Wed, 22 Nov 2023 14:34:45 +0100 Subject: [PATCH] mcu/stm32: Calculate I2C timing register STM32 F1,F4,L1 do have ClockSpeed filed in I2C initialization API, so it easy to specify requested clock speed for I2C. For all other devices ST HAL does not provide such field and expect that TIMINGR register value is precomputed. This value is specified in each BSP and is likely incorrect for some of them. This change introduces hic_speed to MCUs that has timing register and function that computes timing register base on requested speed and system clock. If timing register is specified in settings it is still being used to to configure I2C. If timing register setting is 0 hic_speed is used. Signed-off-by: Jerzy Kasenberg --- hw/mcu/stm/stm32_common/src/hal_i2c.c | 74 ++++++++++++++++++- .../include/mcu/stm32f0xx_mynewt_hal.h | 1 + .../include/mcu/stm32f3xx_mynewt_hal.h | 1 + .../include/mcu/stm32f7xx_mynewt_hal.h | 1 + .../include/mcu/stm32h7xx_mynewt_hal.h | 1 + .../include/mcu/stm32l0xx_mynewt_hal.h | 1 + .../include/mcu/stm32l4xx_mynewt_hal.h | 1 + .../include/mcu/stm32u5xx_mynewt_hal.h | 1 + .../include/mcu/stm32wbxx_mynewt_hal.h | 1 + 9 files changed, 81 insertions(+), 1 deletion(-) diff --git a/hw/mcu/stm/stm32_common/src/hal_i2c.c b/hw/mcu/stm/stm32_common/src/hal_i2c.c index cacf29c395..59d1bf1d14 100644 --- a/hw/mcu/stm/stm32_common/src/hal_i2c.c +++ b/hw/mcu/stm/stm32_common/src/hal_i2c.c @@ -98,6 +98,73 @@ i2c_reset(I2C_HandleTypeDef *hi2c) } #endif +#if !MYNEWT_VAL(STM32_HAL_I2C_HAS_CLOCKSPEED) +#ifndef __LL_I2C_CONVERT_TIMINGS +/* This is copy of macro from STM HAL for HALs that don't have it */ +#define __LL_I2C_CONVERT_TIMINGS(__PRESCALER__, __SETUP_TIME__, __HOLD_TIME__, __SCLH_PERIOD__, __SCLL_PERIOD__) \ + ((((uint32_t)(__PRESCALER__) << I2C_TIMINGR_PRESC_Pos) & I2C_TIMINGR_PRESC) | \ + (((uint32_t)(__SETUP_TIME__) << I2C_TIMINGR_SCLDEL_Pos) & I2C_TIMINGR_SCLDEL) | \ + (((uint32_t)(__HOLD_TIME__) << I2C_TIMINGR_SDADEL_Pos) & I2C_TIMINGR_SDADEL) | \ + (((uint32_t)(__SCLH_PERIOD__) << I2C_TIMINGR_SCLH_Pos) & I2C_TIMINGR_SCLH) | \ + (((uint32_t)(__SCLL_PERIOD__) << I2C_TIMINGR_SCLL_Pos) & I2C_TIMINGR_SCLL)) +#endif + +static uint32_t +hal_i2c_timing(uint32_t i2c_speed, uint32_t clock) +{ + uint32_t i2c_hold_time_min, i2c_setup_time_min; + uint32_t i2c_h_min_time, i2c_l_min_time; + uint32_t presc; + uint32_t timing = 0U; + + /* Timings from I2S specification for standard/fast/fast+ */ + if (i2c_speed < 400000) { + i2c_h_min_time = 4000U; + i2c_l_min_time = 4700U; + i2c_hold_time_min = 500U; + i2c_setup_time_min = 1250U; + } else if (i2c_speed < 1000000) { + i2c_h_min_time = 600U; + i2c_l_min_time = 1300U; + i2c_hold_time_min = 375U; + i2c_setup_time_min = 500U; + } else { + i2c_h_min_time = 260U; + i2c_l_min_time = 500U; + i2c_hold_time_min = 130U; + i2c_setup_time_min = 50U; + } + uint32_t clock_khz = clock / 1000; + presc = ((i2c_h_min_time * clock_khz / 1000) + 255999) / 256000; + uint32_t presc_max = ((i2c_l_min_time * clock_khz / 1000) + 255999) / 256000; + presc = max(presc, presc_max); + presc_max = ((i2c_hold_time_min * clock_khz / 1000) + 14999) / 15000; + presc = max(presc, presc_max); + presc_max = ((i2c_setup_time_min * clock_khz / 1000) + 15999) / 16000; + presc = max(presc, presc_max); + + if (presc <= 16) { + uint32_t t_presc = clock / presc; + uint32_t ns_presc = 1000000000 / t_presc; + uint32_t sclh = (i2c_h_min_time + ns_presc - 1) / ns_presc; + uint32_t scll = (i2c_l_min_time + ns_presc - 1) / ns_presc; + uint32_t sdadel = (i2c_hold_time_min + ns_presc - 1) / ns_presc; + uint32_t scldel = (i2c_setup_time_min + ns_presc - 1) / ns_presc; + + uint32_t scl_h_l = (t_presc / i2c_speed) - 5; + if (scl_h_l > sclh + scll) { + uint32_t scl_h_l_fill = scl_h_l - (sclh + scll); + scll += scl_h_l_fill / 2; + sclh += (scl_h_l_fill + 1) / 2; + } + timing = __LL_I2C_CONVERT_TIMINGS(presc - 1, + scldel - 1, sdadel, sclh - 1, scll - 1); + } + + return timing; +} +#endif + int hal_i2c_init(uint8_t i2c_num, void *usercfg) { @@ -116,7 +183,11 @@ hal_i2c_init(uint8_t i2c_num, void *usercfg) init = &dev->hid_handle.Init; dev->hid_handle.Instance = cfg->hic_i2c; #if !MYNEWT_VAL(STM32_HAL_I2C_HAS_CLOCKSPEED) - init->Timing = cfg->hic_timingr; + if (cfg->hic_timingr) { + init->Timing = cfg->hic_timingr; + } else { + init->Timing = hal_i2c_timing(cfg->hic_speed, HAL_RCC_GetPCLK1Freq()); + } #else init->ClockSpeed = cfg->hic_speed; #endif @@ -258,3 +329,4 @@ hal_i2c_master_probe(uint8_t i2c_num, uint8_t address, uint32_t timo) return rc; } + diff --git a/hw/mcu/stm/stm32f0xx/include/mcu/stm32f0xx_mynewt_hal.h b/hw/mcu/stm/stm32f0xx/include/mcu/stm32f0xx_mynewt_hal.h index b120b67c59..de8931cdec 100644 --- a/hw/mcu/stm/stm32f0xx/include/mcu/stm32f0xx_mynewt_hal.h +++ b/hw/mcu/stm/stm32f0xx/include/mcu/stm32f0xx_mynewt_hal.h @@ -56,6 +56,7 @@ struct stm32_hal_i2c_cfg { uint8_t hic_pin_af; uint8_t hic_10bit; uint32_t hic_timingr; /* TIMINGR register */ + uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */ }; #ifdef __cplusplus diff --git a/hw/mcu/stm/stm32f3xx/include/mcu/stm32f3xx_mynewt_hal.h b/hw/mcu/stm/stm32f3xx/include/mcu/stm32f3xx_mynewt_hal.h index 104b3c31d9..868efca6fc 100644 --- a/hw/mcu/stm/stm32f3xx/include/mcu/stm32f3xx_mynewt_hal.h +++ b/hw/mcu/stm/stm32f3xx/include/mcu/stm32f3xx_mynewt_hal.h @@ -56,6 +56,7 @@ struct stm32_hal_i2c_cfg { uint8_t hic_pin_af; uint8_t hic_10bit; uint32_t hic_timingr; /* TIMINGR register */ + uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */ }; #ifdef __cplusplus diff --git a/hw/mcu/stm/stm32f7xx/include/mcu/stm32f7xx_mynewt_hal.h b/hw/mcu/stm/stm32f7xx/include/mcu/stm32f7xx_mynewt_hal.h index 0cd7721516..a9f2321ea7 100644 --- a/hw/mcu/stm/stm32f7xx/include/mcu/stm32f7xx_mynewt_hal.h +++ b/hw/mcu/stm/stm32f7xx/include/mcu/stm32f7xx_mynewt_hal.h @@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg { uint8_t hic_pin_af; uint8_t hic_10bit; uint32_t hic_timingr; /* TIMINGR register */ + uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */ }; #ifdef __cplusplus diff --git a/hw/mcu/stm/stm32h7xx/include/mcu/stm32h7xx_mynewt_hal.h b/hw/mcu/stm/stm32h7xx/include/mcu/stm32h7xx_mynewt_hal.h index dc17d6fe11..fd6f5ea1c5 100644 --- a/hw/mcu/stm/stm32h7xx/include/mcu/stm32h7xx_mynewt_hal.h +++ b/hw/mcu/stm/stm32h7xx/include/mcu/stm32h7xx_mynewt_hal.h @@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg { uint8_t hic_pin_af; uint8_t hic_10bit; uint32_t hic_timingr; /* TIMINGR register */ + uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */ }; #ifdef __cplusplus diff --git a/hw/mcu/stm/stm32l0xx/include/mcu/stm32l0xx_mynewt_hal.h b/hw/mcu/stm/stm32l0xx/include/mcu/stm32l0xx_mynewt_hal.h index 75a7bef2d2..50f18b7d00 100644 --- a/hw/mcu/stm/stm32l0xx/include/mcu/stm32l0xx_mynewt_hal.h +++ b/hw/mcu/stm/stm32l0xx/include/mcu/stm32l0xx_mynewt_hal.h @@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg { uint8_t hic_pin_af; uint8_t hic_10bit; uint32_t hic_timingr; /* TIMINGR register */ + uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */ }; #ifdef __cplusplus diff --git a/hw/mcu/stm/stm32l4xx/include/mcu/stm32l4xx_mynewt_hal.h b/hw/mcu/stm/stm32l4xx/include/mcu/stm32l4xx_mynewt_hal.h index 292dade41e..6cec1fdc6d 100644 --- a/hw/mcu/stm/stm32l4xx/include/mcu/stm32l4xx_mynewt_hal.h +++ b/hw/mcu/stm/stm32l4xx/include/mcu/stm32l4xx_mynewt_hal.h @@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg { uint8_t hic_pin_af; uint8_t hic_10bit; uint32_t hic_timingr; /* TIMINGR register */ + uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */ }; #ifdef __cplusplus diff --git a/hw/mcu/stm/stm32u5xx/include/mcu/stm32u5xx_mynewt_hal.h b/hw/mcu/stm/stm32u5xx/include/mcu/stm32u5xx_mynewt_hal.h index 1709bf9fe2..c403d44c4f 100644 --- a/hw/mcu/stm/stm32u5xx/include/mcu/stm32u5xx_mynewt_hal.h +++ b/hw/mcu/stm/stm32u5xx/include/mcu/stm32u5xx_mynewt_hal.h @@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg { uint8_t hic_pin_af; uint8_t hic_10bit; uint32_t hic_timingr; /* TIMINGR register */ + uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */ }; #ifdef __cplusplus diff --git a/hw/mcu/stm/stm32wbxx/include/mcu/stm32wbxx_mynewt_hal.h b/hw/mcu/stm/stm32wbxx/include/mcu/stm32wbxx_mynewt_hal.h index 71313f377d..7522657685 100644 --- a/hw/mcu/stm/stm32wbxx/include/mcu/stm32wbxx_mynewt_hal.h +++ b/hw/mcu/stm/stm32wbxx/include/mcu/stm32wbxx_mynewt_hal.h @@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg { uint8_t hic_pin_af; uint8_t hic_10bit; uint32_t hic_timingr; /* TIMINGR register */ + uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */ }; #ifdef __cplusplus