Skip to content

Commit c801bb6

Browse files
committed
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 <[email protected]>
1 parent 5d679e6 commit c801bb6

File tree

9 files changed

+81
-1
lines changed

9 files changed

+81
-1
lines changed

hw/mcu/stm/stm32_common/src/hal_i2c.c

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,73 @@ i2c_reset(I2C_HandleTypeDef *hi2c)
9898
}
9999
#endif
100100

101+
#if !MYNEWT_VAL(STM32_HAL_I2C_HAS_CLOCKSPEED)
102+
#ifndef __LL_I2C_CONVERT_TIMINGS
103+
/* This is copy of macro from STM HAL for HALs that don't have it */
104+
#define __LL_I2C_CONVERT_TIMINGS(__PRESCALER__, __SETUP_TIME__, __HOLD_TIME__, __SCLH_PERIOD__, __SCLL_PERIOD__) \
105+
((((uint32_t)(__PRESCALER__) << I2C_TIMINGR_PRESC_Pos) & I2C_TIMINGR_PRESC) | \
106+
(((uint32_t)(__SETUP_TIME__) << I2C_TIMINGR_SCLDEL_Pos) & I2C_TIMINGR_SCLDEL) | \
107+
(((uint32_t)(__HOLD_TIME__) << I2C_TIMINGR_SDADEL_Pos) & I2C_TIMINGR_SDADEL) | \
108+
(((uint32_t)(__SCLH_PERIOD__) << I2C_TIMINGR_SCLH_Pos) & I2C_TIMINGR_SCLH) | \
109+
(((uint32_t)(__SCLL_PERIOD__) << I2C_TIMINGR_SCLL_Pos) & I2C_TIMINGR_SCLL))
110+
#endif
111+
112+
static uint32_t
113+
hal_i2c_timing(uint32_t i2c_speed, uint32_t clock)
114+
{
115+
uint32_t i2c_hold_time_min, i2c_setup_time_min;
116+
uint32_t i2c_h_min_time, i2c_l_min_time;
117+
uint32_t presc;
118+
uint32_t timing = 0U;
119+
120+
/* Timings from I2S specification for standard/fast/fast+ */
121+
if (i2c_speed < 400000) {
122+
i2c_h_min_time = 4000U;
123+
i2c_l_min_time = 4700U;
124+
i2c_hold_time_min = 500U;
125+
i2c_setup_time_min = 1250U;
126+
} else if (i2c_speed < 1000000) {
127+
i2c_h_min_time = 600U;
128+
i2c_l_min_time = 1300U;
129+
i2c_hold_time_min = 375U;
130+
i2c_setup_time_min = 500U;
131+
} else {
132+
i2c_h_min_time = 260U;
133+
i2c_l_min_time = 500U;
134+
i2c_hold_time_min = 130U;
135+
i2c_setup_time_min = 50U;
136+
}
137+
uint32_t clock_khz = clock / 1000;
138+
presc = ((i2c_h_min_time * clock_khz / 1000) + 255999) / 256000;
139+
uint32_t presc_max = ((i2c_l_min_time * clock_khz / 1000) + 255999) / 256000;
140+
presc = max(presc, presc_max);
141+
presc_max = ((i2c_hold_time_min * clock_khz / 1000) + 14999) / 15000;
142+
presc = max(presc, presc_max);
143+
presc_max = ((i2c_setup_time_min * clock_khz / 1000) + 15999) / 16000;
144+
presc = max(presc, presc_max);
145+
146+
if (presc <= 16) {
147+
uint32_t t_presc = clock / presc;
148+
uint32_t ns_presc = 1000000000 / t_presc;
149+
uint32_t sclh = (i2c_h_min_time + ns_presc - 1) / ns_presc;
150+
uint32_t scll = (i2c_l_min_time + ns_presc - 1) / ns_presc;
151+
uint32_t sdadel = (i2c_hold_time_min + ns_presc - 1) / ns_presc;
152+
uint32_t scldel = (i2c_setup_time_min + ns_presc - 1) / ns_presc;
153+
154+
uint32_t scl_h_l = (t_presc / i2c_speed) - 5;
155+
if (scl_h_l > sclh + scll) {
156+
uint32_t scl_h_l_fill = scl_h_l - (sclh + scll);
157+
scll += scl_h_l_fill / 2;
158+
sclh += (scl_h_l_fill + 1) / 2;
159+
}
160+
timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
161+
scldel - 1, sdadel, sclh - 1, scll - 1);
162+
}
163+
164+
return timing;
165+
}
166+
#endif
167+
101168
int
102169
hal_i2c_init(uint8_t i2c_num, void *usercfg)
103170
{
@@ -116,7 +183,11 @@ hal_i2c_init(uint8_t i2c_num, void *usercfg)
116183
init = &dev->hid_handle.Init;
117184
dev->hid_handle.Instance = cfg->hic_i2c;
118185
#if !MYNEWT_VAL(STM32_HAL_I2C_HAS_CLOCKSPEED)
119-
init->Timing = cfg->hic_timingr;
186+
if (cfg->hic_timingr) {
187+
init->Timing = cfg->hic_timingr;
188+
} else {
189+
init->Timing = hal_i2c_timing(cfg->hic_speed, HAL_RCC_GetPCLK1Freq());
190+
}
120191
#else
121192
init->ClockSpeed = cfg->hic_speed;
122193
#endif
@@ -258,3 +329,4 @@ hal_i2c_master_probe(uint8_t i2c_num, uint8_t address, uint32_t timo)
258329

259330
return rc;
260331
}
332+

hw/mcu/stm/stm32f0xx/include/mcu/stm32f0xx_mynewt_hal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct stm32_hal_i2c_cfg {
5656
uint8_t hic_pin_af;
5757
uint8_t hic_10bit;
5858
uint32_t hic_timingr; /* TIMINGR register */
59+
uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */
5960
};
6061

6162
#ifdef __cplusplus

hw/mcu/stm/stm32f3xx/include/mcu/stm32f3xx_mynewt_hal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct stm32_hal_i2c_cfg {
5656
uint8_t hic_pin_af;
5757
uint8_t hic_10bit;
5858
uint32_t hic_timingr; /* TIMINGR register */
59+
uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */
5960
};
6061

6162
#ifdef __cplusplus

hw/mcu/stm/stm32f7xx/include/mcu/stm32f7xx_mynewt_hal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg {
5757
uint8_t hic_pin_af;
5858
uint8_t hic_10bit;
5959
uint32_t hic_timingr; /* TIMINGR register */
60+
uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */
6061
};
6162

6263
#ifdef __cplusplus

hw/mcu/stm/stm32h7xx/include/mcu/stm32h7xx_mynewt_hal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg {
5757
uint8_t hic_pin_af;
5858
uint8_t hic_10bit;
5959
uint32_t hic_timingr; /* TIMINGR register */
60+
uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */
6061
};
6162

6263
#ifdef __cplusplus

hw/mcu/stm/stm32l0xx/include/mcu/stm32l0xx_mynewt_hal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg {
5757
uint8_t hic_pin_af;
5858
uint8_t hic_10bit;
5959
uint32_t hic_timingr; /* TIMINGR register */
60+
uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */
6061
};
6162

6263
#ifdef __cplusplus

hw/mcu/stm/stm32l4xx/include/mcu/stm32l4xx_mynewt_hal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg {
5757
uint8_t hic_pin_af;
5858
uint8_t hic_10bit;
5959
uint32_t hic_timingr; /* TIMINGR register */
60+
uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */
6061
};
6162

6263
#ifdef __cplusplus

hw/mcu/stm/stm32u5xx/include/mcu/stm32u5xx_mynewt_hal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg {
5757
uint8_t hic_pin_af;
5858
uint8_t hic_10bit;
5959
uint32_t hic_timingr; /* TIMINGR register */
60+
uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */
6061
};
6162

6263
#ifdef __cplusplus

hw/mcu/stm/stm32wbxx/include/mcu/stm32wbxx_mynewt_hal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct stm32_hal_i2c_cfg {
5757
uint8_t hic_pin_af;
5858
uint8_t hic_10bit;
5959
uint32_t hic_timingr; /* TIMINGR register */
60+
uint32_t hic_speed; /* Requested speed (used when hic_timingr is 0) */
6061
};
6162

6263
#ifdef __cplusplus

0 commit comments

Comments
 (0)