Skip to content

Commit dc0c23e

Browse files
committed
STM32: Compute I2C timing according current I2C clock source and required I2C clock
1 parent ef0eb44 commit dc0c23e

File tree

2 files changed

+375
-33
lines changed

2 files changed

+375
-33
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,369 @@
1+
/* mbed Microcontroller Library
2+
* SPDX-License-Identifier: BSD-3-Clause
3+
******************************************************************************
4+
*
5+
* Copyright (c) 2015-2020 STMicroelectronics.
6+
* Copyright (c) 2020, Arduino SA.
7+
* All rights reserved.
8+
*
9+
* This software component is licensed by ST under BSD 3-Clause license,
10+
* the "License"; You may not use this file except in compliance with the
11+
* License. You may obtain a copy of the License at:
12+
* opensource.org/licenses/BSD-3-Clause
13+
*
14+
******************************************************************************
15+
*/
16+
17+
#include "i2c_device.h"
18+
#include "mbed_assert.h"
19+
#include "stm32h7xx_ll_rcc.h"
20+
21+
#if DEVICE_I2C
22+
23+
/** @defgroup I2C_DEVICE_Private_Constants I2C_DEVICE Private Constants
24+
* @{
25+
*/
26+
#ifndef I2C_VALID_TIMING_NBR
27+
#define I2C_VALID_TIMING_NBR 128U
28+
#endif
29+
#define I2C_SPEED_FREQ_STANDARD 0U /* 100 kHz */
30+
#define I2C_SPEED_FREQ_FAST 1U /* 400 kHz */
31+
#define I2C_SPEED_FREQ_FAST_PLUS 2U /* 1 MHz */
32+
#define I2C_ANALOG_FILTER_DELAY_MIN 50U /* ns */
33+
#define I2C_ANALOG_FILTER_DELAY_MAX 260U /* ns */
34+
#define I2C_USE_ANALOG_FILTER 1U
35+
#define I2C_DIGITAL_FILTER_COEF 0U
36+
#define I2C_PRESC_MAX 16U
37+
#define I2C_SCLDEL_MAX 16U
38+
#define I2C_SDADEL_MAX 16U
39+
#define I2C_SCLH_MAX 256U
40+
#define I2C_SCLL_MAX 256U
41+
#define SEC2NSEC 1000000000UL
42+
/**
43+
* @}
44+
*/
45+
46+
/** @defgroup I2C_DEVICE_Private_Types I2C_DEVICE Private Types
47+
* @{
48+
*/
49+
typedef struct
50+
{
51+
uint32_t freq; /* Frequency in Hz */
52+
uint32_t freq_min; /* Minimum frequency in Hz */
53+
uint32_t freq_max; /* Maximum frequency in Hz */
54+
uint32_t hddat_min; /* Minimum data hold time in ns */
55+
uint32_t vddat_max; /* Maximum data valid time in ns */
56+
uint32_t sudat_min; /* Minimum data setup time in ns */
57+
uint32_t lscl_min; /* Minimum low period of the SCL clock in ns */
58+
uint32_t hscl_min; /* Minimum high period of SCL clock in ns */
59+
uint32_t trise; /* Rise time in ns */
60+
uint32_t tfall; /* Fall time in ns */
61+
uint32_t dnf; /* Digital noise filter coefficient */
62+
} I2C_Charac_t;
63+
64+
typedef struct
65+
{
66+
uint32_t presc; /* Timing prescaler */
67+
uint32_t tscldel; /* SCL delay */
68+
uint32_t tsdadel; /* SDA delay */
69+
uint32_t sclh; /* SCL high period */
70+
uint32_t scll; /* SCL low period */
71+
} I2C_Timings_t;
72+
/**
73+
* @}
74+
*/
75+
76+
/** @defgroup I2C_DEVICE_Private_Constants I2C_DEVICE Private Constants
77+
* @{
78+
*/
79+
static const I2C_Charac_t I2C_Charac[] =
80+
{
81+
[I2C_SPEED_FREQ_STANDARD] =
82+
{
83+
.freq = 100000,
84+
.freq_min = 80000,
85+
.freq_max = 120000,
86+
.hddat_min = 0,
87+
.vddat_max = 3450,
88+
.sudat_min = 250,
89+
.lscl_min = 4700,
90+
.hscl_min = 4000,
91+
.trise = 640,
92+
.tfall = 20,
93+
.dnf = I2C_DIGITAL_FILTER_COEF,
94+
},
95+
[I2C_SPEED_FREQ_FAST] =
96+
{
97+
.freq = 400000,
98+
.freq_min = 320000,
99+
.freq_max = 480000,
100+
.hddat_min = 0,
101+
.vddat_max = 900,
102+
.sudat_min = 100,
103+
.lscl_min = 1300,
104+
.hscl_min = 600,
105+
.trise = 250,
106+
.tfall = 100,
107+
.dnf = I2C_DIGITAL_FILTER_COEF,
108+
},
109+
[I2C_SPEED_FREQ_FAST_PLUS] =
110+
{
111+
.freq = 1000000,
112+
.freq_min = 800000,
113+
.freq_max = 1200000,
114+
.hddat_min = 0,
115+
.vddat_max = 450,
116+
.sudat_min = 50,
117+
.lscl_min = 500,
118+
.hscl_min = 260,
119+
.trise = 60,
120+
.tfall = 100,
121+
.dnf = I2C_DIGITAL_FILTER_COEF,
122+
},
123+
};
124+
/**
125+
* @}
126+
*/
127+
128+
/** @defgroup I2C_DEVICE_Private_Variables I2C_DEVICE Private Variables
129+
* @{
130+
*/
131+
static I2C_Timings_t I2c_valid_timing[I2C_VALID_TIMING_NBR];
132+
static uint32_t I2c_valid_timing_nbr = 0;
133+
/**
134+
* @}
135+
*/
136+
137+
/** @defgroup I2C_DEVICE_Private_Functions I2C_DEVICE Private Functions
138+
* @{
139+
*/
140+
/**
141+
* @brief Compute PRESC, SCLDEL and SDADEL.
142+
* @param clock_src_freq I2C source clock in HZ.
143+
* @param I2C_speed I2C frequency (index).
144+
* @retval None.
145+
*/
146+
static void I2C_Compute_PRESC_SCLDEL_SDADEL(uint32_t clock_src_freq, uint32_t I2C_speed)
147+
{
148+
uint32_t prev_presc = I2C_PRESC_MAX;
149+
uint32_t ti2cclk;
150+
int32_t tsdadel_min, tsdadel_max;
151+
int32_t tscldel_min;
152+
uint32_t presc, scldel, sdadel;
153+
uint32_t tafdel_min, tafdel_max;
154+
155+
ti2cclk = (SEC2NSEC + (clock_src_freq / 2U))/ clock_src_freq;
156+
157+
tafdel_min = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MIN : 0U;
158+
tafdel_max = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MAX : 0U;
159+
160+
/* tDNF = DNF x tI2CCLK
161+
tPRESC = (PRESC+1) x tI2CCLK
162+
SDADEL >= {tf +tHD;DAT(min) - tAF(min) - tDNF - [3 x tI2CCLK]} / {tPRESC}
163+
SDADEL <= {tVD;DAT(max) - tr - tAF(max) - tDNF- [4 x tI2CCLK]} / {tPRESC} */
164+
165+
tsdadel_min = (int32_t)I2C_Charac[I2C_speed].tfall + (int32_t)I2C_Charac[I2C_speed].hddat_min -
166+
(int32_t)tafdel_min - (int32_t)(((int32_t)I2C_Charac[I2C_speed].dnf + 3) * (int32_t)ti2cclk);
167+
168+
tsdadel_max = (int32_t)I2C_Charac[I2C_speed].vddat_max - (int32_t)I2C_Charac[I2C_speed].trise -
169+
(int32_t)tafdel_max - (int32_t)(((int32_t)I2C_Charac[I2C_speed].dnf + 4) * (int32_t)ti2cclk);
170+
171+
172+
/* {[tr+ tSU;DAT(min)] / [tPRESC]} - 1 <= SCLDEL */
173+
tscldel_min = (int32_t)I2C_Charac[I2C_speed].trise + (int32_t)I2C_Charac[I2C_speed].sudat_min;
174+
175+
if (tsdadel_min <= 0)
176+
{
177+
tsdadel_min = 0;
178+
}
179+
180+
if (tsdadel_max <= 0)
181+
{
182+
tsdadel_max = 0;
183+
}
184+
185+
for (presc = 0; presc < I2C_PRESC_MAX; presc++)
186+
{
187+
for (scldel = 0; scldel < I2C_SCLDEL_MAX; scldel++)
188+
{
189+
/* TSCLDEL = (SCLDEL+1) * (PRESC+1) * TI2CCLK */
190+
uint32_t tscldel = (scldel + 1U) * (presc + 1U) * ti2cclk;
191+
192+
if (tscldel >= (uint32_t)tscldel_min)
193+
{
194+
for (sdadel = 0; sdadel < I2C_SDADEL_MAX; sdadel++)
195+
{
196+
/* TSDADEL = SDADEL * (PRESC+1) * TI2CCLK */
197+
uint32_t tsdadel = (sdadel * (presc + 1U)) * ti2cclk;
198+
199+
if ((tsdadel >= (uint32_t)tsdadel_min) && (tsdadel <= (uint32_t)tsdadel_max))
200+
{
201+
if(presc != prev_presc)
202+
{
203+
I2c_valid_timing[I2c_valid_timing_nbr].presc = presc;
204+
I2c_valid_timing[I2c_valid_timing_nbr].tscldel = scldel;
205+
I2c_valid_timing[I2c_valid_timing_nbr].tsdadel = sdadel;
206+
prev_presc = presc;
207+
I2c_valid_timing_nbr ++;
208+
209+
if(I2c_valid_timing_nbr >= I2C_VALID_TIMING_NBR)
210+
{
211+
return;
212+
}
213+
}
214+
}
215+
}
216+
}
217+
}
218+
}
219+
}
220+
221+
/**
222+
* @brief Calculate SCLL and SCLH and find best configuration.
223+
* @param clock_src_freq I2C source clock in HZ.
224+
* @param I2C_speed I2C frequency (index).
225+
* @retval config index (0 to I2C_VALID_TIMING_NBR], 0xFFFFFFFF for no valid config.
226+
*/
227+
static uint32_t I2C_Compute_SCLL_SCLH (uint32_t clock_src_freq, uint32_t I2C_speed)
228+
{
229+
uint32_t ret = 0xFFFFFFFFU;
230+
uint32_t ti2cclk;
231+
uint32_t ti2cspeed;
232+
uint32_t prev_error;
233+
uint32_t dnf_delay;
234+
uint32_t clk_min, clk_max;
235+
uint32_t scll, sclh;
236+
uint32_t tafdel_min;
237+
238+
ti2cclk = (SEC2NSEC + (clock_src_freq / 2U))/ clock_src_freq;
239+
ti2cspeed = (SEC2NSEC + (I2C_Charac[I2C_speed].freq / 2U))/ I2C_Charac[I2C_speed].freq;
240+
241+
tafdel_min = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MIN : 0U;
242+
243+
/* tDNF = DNF x tI2CCLK */
244+
dnf_delay = I2C_Charac[I2C_speed].dnf * ti2cclk;
245+
246+
clk_max = SEC2NSEC / I2C_Charac[I2C_speed].freq_min;
247+
clk_min = SEC2NSEC / I2C_Charac[I2C_speed].freq_max;
248+
249+
prev_error = ti2cspeed;
250+
251+
for (uint32_t count = 0; count < I2c_valid_timing_nbr; count++)
252+
{
253+
/* tPRESC = (PRESC+1) x tI2CCLK*/
254+
uint32_t tpresc = (I2c_valid_timing[count].presc + 1U) * ti2cclk;
255+
256+
for (scll = 0; scll < I2C_SCLL_MAX; scll++)
257+
{
258+
/* tLOW(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLL+1) x tPRESC ] */
259+
uint32_t tscl_l = tafdel_min + dnf_delay + (2U * ti2cclk) + ((scll + 1U) * tpresc);
260+
261+
262+
/* The I2CCLK period tI2CCLK must respect the following conditions:
263+
tI2CCLK < (tLOW - tfilters) / 4 and tI2CCLK < tHIGH */
264+
if ((tscl_l > I2C_Charac[I2C_speed].lscl_min) && (ti2cclk < ((tscl_l - tafdel_min - dnf_delay) / 4U)))
265+
{
266+
for (sclh = 0; sclh < I2C_SCLH_MAX; sclh++)
267+
{
268+
/* tHIGH(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLH+1) x tPRESC] */
269+
uint32_t tscl_h = tafdel_min + dnf_delay + (2U * ti2cclk) + ((sclh + 1U) * tpresc);
270+
271+
/* tSCL = tf + tLOW + tr + tHIGH */
272+
uint32_t tscl = tscl_l + tscl_h + I2C_Charac[I2C_speed].trise + I2C_Charac[I2C_speed].tfall;
273+
274+
if ((tscl >= clk_min) && (tscl <= clk_max) && (tscl_h >= I2C_Charac[I2C_speed].hscl_min) && (ti2cclk < tscl_h))
275+
{
276+
int32_t error = (int32_t)tscl - (int32_t)ti2cspeed;
277+
278+
if (error < 0)
279+
{
280+
error = -error;
281+
}
282+
283+
/* look for the timings with the lowest clock error */
284+
if ((uint32_t)error < prev_error)
285+
{
286+
prev_error = (uint32_t)error;
287+
I2c_valid_timing[count].scll = scll;
288+
I2c_valid_timing[count].sclh = sclh;
289+
ret = count;
290+
}
291+
}
292+
}
293+
}
294+
}
295+
}
296+
297+
return ret;
298+
}
299+
300+
/**
301+
* @brief Compute I2C timing according current I2C clock source and required I2C clock.
302+
* @param clock_src_freq I2C clock source in Hz.
303+
* @param i2c_freq Required I2C clock in Hz.
304+
* @retval I2C timing or 0 in case of error.
305+
*/
306+
static uint32_t I2C_ComputeTiming(uint32_t clock_src_freq, uint32_t i2c_freq)
307+
{
308+
uint32_t ret = 0;
309+
uint32_t speed;
310+
uint32_t idx;
311+
312+
313+
if((clock_src_freq != 0U) && (i2c_freq != 0U))
314+
{
315+
for ( speed = 0 ; speed <= (uint32_t)I2C_SPEED_FREQ_FAST_PLUS ; speed++)
316+
{
317+
if ((i2c_freq >= I2C_Charac[speed].freq_min) &&
318+
(i2c_freq <= I2C_Charac[speed].freq_max))
319+
{
320+
I2C_Compute_PRESC_SCLDEL_SDADEL(clock_src_freq, speed);
321+
idx = I2C_Compute_SCLL_SCLH(clock_src_freq, speed);
322+
323+
if (idx < I2C_VALID_TIMING_NBR)
324+
{
325+
ret = ((I2c_valid_timing[idx].presc & 0x0FU) << 28) |\
326+
((I2c_valid_timing[idx].tscldel & 0x0FU) << 20) |\
327+
((I2c_valid_timing[idx].tsdadel & 0x0FU) << 16) |\
328+
((I2c_valid_timing[idx].sclh & 0xFFU) << 8) |\
329+
((I2c_valid_timing[idx].scll & 0xFFU) << 0);
330+
}
331+
break;
332+
}
333+
}
334+
}
335+
336+
return ret;
337+
}
338+
/**
339+
* @}
340+
*/
341+
342+
/** @defgroup I2C_DEVICE_Exported_Functions I2C_DEVICE Exported Functions
343+
* @{
344+
*/
345+
/**
346+
* @brief Provide the suitable timing depending on requested frequency
347+
* @param hz Required I2C clock in Hz.
348+
* @retval I2C timing or 0 in case of error.
349+
*/
350+
uint32_t get_i2c_timing(int hz)
351+
{
352+
uint32_t clock_src_freq;
353+
uint32_t tim;
354+
355+
/* we will use D2PCLK1 to calculate I2C timings */
356+
MBED_ASSERT(RCC_I2C1CLKSOURCE_D2PCLK1 ==__HAL_RCC_GET_I2C1_SOURCE());
357+
358+
LL_RCC_ClocksTypeDef rcc_clocks;
359+
LL_RCC_GetSystemClocksFreq(&rcc_clocks);
360+
361+
tim = I2C_ComputeTiming(rcc_clocks.PCLK1_Frequency, hz);
362+
363+
return tim;
364+
}
365+
/**
366+
* @}
367+
*/
368+
369+
#endif // DEVICE_I2C

0 commit comments

Comments
 (0)