2022-12-02 02:21 AM
HI Team,
We are using the STM32WB controller for our project, in that we are using the I2C1 for to communicate with Eeprom Module.
Can anyone explain how to configure/Calculate the Exact Timing Register value. If we have any sample calculator for different I2C Speeds along with other register settings it is very helpful to us.
Currently My Register value: hi2c1.hi2c1.Init. Timing = 0x00000E14, for which I2C speed it is calculated we are not understanding.
Regards,
Srinivas.V
2022-12-08 07:34 AM
Could you please share with me your inputs.
Foued
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2022-12-08 09:33 AM
Hi Khalsi,
Thanks for your reply. Here with I am sharing my inputs.
Please suggest me the correct settings.
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x00000E14; //100Khz //
hi2c1.Init.OwnAddress1 = I2C_ADDRESS;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE);
HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0x0)
HAL_I2CEx_EnableFastModePlus(I2C_FASTMODEPLUS_I2C1);
/*##-1- Configure the I2C clock source. The clock is derived from the SYSCLK #*/
RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
RCC_PeriphCLKInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_SYSCLK;
//GPIO Configuration
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//GPIO_SPEED_FREQ_LOW,GPIO_SPEED_FREQ_HIGH,GPIO_SPEED_FREQ_MEDIUM,GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
I have added source file also for your reference in attachments.
Please let me know if any more inputs are required from my side.
2022-12-09 12:50 AM
Hello,
The "Excel spreadsheet I2C_Timing_Configuration_V1.0.1" is only for the STM32F3 and STM32F0
(I2C timing configuration tool for STM32F3xx and STM32F0xx microcontrollers)
I recommend you to use the STM32CubeMX for getting Higher speeds like 400Khz and 1 MHz, it helps you to configure/Calculate the Exact Timing Register value.
Foued.
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2022-12-09 01:16 AM
Hi Khalsi,
Once again thanks for your reply and support. In STM32CubeMX Some of the fields are not able to calculate like Rise & Fall times, and what is the impact of these two variables also we do not know and currently we keep it as zero's only.
If you have any other I2C example code integrated with specific application is useful to us.
Regards,
Srinivas.V
2022-12-09 01:17 AM
Hi Khalsi,
Once again thanks for your reply and support. I have shared my code files in last message, could you find out any changes are required in that, please let us know, it is very helpful to us to relook into that one.
2022-12-09 01:46 AM
Hello,
You can check the I2C examples from :
\Repository\STM32Cube_FW_WB_V1.15.0RC2\Projects\P-NUCLEO-WB55.Nucleo\Examples\I2C
Download the STM32Cube MCU Package for STM32WB series :
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2022-12-09 02:11 AM
Example description:
-I2C pins
-I2C Clock Source Frequency : 32 MHz
-I2C Speed Frequency : 1MHz
-Rise Time : 0 ns
-Fall Time : 0 ns
Code:
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 8;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK4|RCC_CLOCKTYPE_HCLK2
|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.AHBCLK2Divider = RCC_SYSCLK_DIV2;
RCC_ClkInitStruct.AHBCLK4Divider = RCC_SYSCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief Peripherals Common Clock Configuration
* @retval None
*/
void PeriphCommonClock_Config(void)
{
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SMPS;
PeriphClkInitStruct.SmpsClockSelection = RCC_SMPSCLKSOURCE_HSI;
PeriphClkInitStruct.SmpsDivSelection = RCC_SMPSCLKDIV_RANGE1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN Smps */
/* USER CODE END Smps */
}
/**
* @brief I2C1 Initialization Function
* @param None
* @retval None
*/
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x00100413;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
/** I2C Enable Fast Mode Plus
*/
HAL_I2CEx_EnableFastModePlus(I2C_FASTMODEPLUS_I2C1);
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
Foued
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2022-12-09 03:09 AM
Hi Khalsi,
Once again thanks for your support and sharing the source code to us.
Almost code is the same except the Clock Source settings, in your code RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK.
our code,
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE.
but the Input Clock to I2C1 is 32 MHz Only, Mx settings also same. We will use Same Timing Reg value for our as well.
Similar way can you have any code base for Flash operations initializations and Read, Write and Erase as well. We will use the same for our purpose.
Regards,
Srinivas.V
2024-11-04 11:11 AM - edited 2024-11-04 12:42 PM
I know it's a bit late, but I use the following algorithm for stm32g030.
It might be useful to someone
/* ======================================================================
* The function calculates optimal timing of the I2C bus
*
* @PAram pclk1_hz - PCLK frequency (Hz)
* @PAram i2c_freq_hz - target I2C clock frequency (Hz)
* @retvalue - timing register value
* ======================================================================*/
uint32_t I2C_calculate_timing(const uint32_t pclk1_hz, const uint32_t i2c_freq_hz)
{
const uint32_t clock_period_ns = 1000000000 / pclk1_hz;
const uint32_t i2c_period_ns = 1000000000 / i2c_freq_hz;
const uint32_t af_delay_ns = 50; // Analog filter delay (ns)
// Determine speed mode limits & digital filter delay (ns)
uint32_t tlow_min, thigh_min, tsudat_min, dfn;
if (i2c_freq_hz <= 100000) {
tlow_min = i2c_period_ns * 470 >> 10;
thigh_min = i2c_period_ns * 400 >> 10;
tsudat_min = 250;
dfn = 4;
} else if (i2c_freq_hz <= 400000) {
tlow_min = i2c_period_ns * 540 >> 10;
thigh_min = i2c_period_ns * 250 >> 10;
tsudat_min = 100;
dfn = 2;
} else if (i2c_freq_hz <= 1000000) {
tlow_min = i2c_period_ns * 520 >> 10;
thigh_min = i2c_period_ns * 270 >> 10;
tsudat_min = 50;
dfn = 0;
} else {
return 0;
}
const uint32_t filter_delay_ns = af_delay_ns + (dfn * clock_period_ns);
const uint32_t sdadel_min_ns = filter_delay_ns;
const uint32_t sdadel_max_ns = i2c_period_ns >> 2;
const uint32_t scldel_min_ns = tsudat_min + filter_delay_ns;
// Target period with 20% margin
const uint32_t period_max = i2c_period_ns + (i2c_period_ns / 5);
const uint32_t period_min = i2c_period_ns - (i2c_period_ns / 5);
uint32_t tmp_presc = 0;
uint32_t tmp_scldel = 0;
uint32_t tmp_sdadel = 0;
uint32_t tmp_sclh = 0;
uint32_t tmp_scll = 0;
uint32_t tmp_error = UINT32_MAX;
// Binary search helper function for SCLH and SCLL
for (uint32_t presc = 0; presc < 16; presc++) {
const uint32_t ti2cclk = clock_period_ns * (presc + 1);
for (uint32_t scldel = 0; scldel < 16; scldel++) {
const uint32_t tscldel = (scldel + 1) * ti2cclk;
if (tscldel < scldel_min_ns) continue;
for (uint32_t sdadel = 0; sdadel < 16; sdadel++) {
const uint32_t tsdadel = sdadel * ti2cclk;
if (tsdadel < sdadel_min_ns || tsdadel > sdadel_max_ns) continue;
const uint32_t tsync = filter_delay_ns + 2 * ti2cclk;
// Binary search for SCLH
uint32_t sclh_min = (thigh_min - filter_delay_ns + ti2cclk - 1) / ti2cclk - 1;
if (sclh_min >= 256) continue;
uint32_t sclh_max = 255;
while (sclh_min <= sclh_max) {
const uint32_t sclh = (sclh_min + sclh_max) >> 1;
const uint32_t tsclh = (sclh + 1) * ti2cclk;
const uint32_t thigh = tsclh + filter_delay_ns;
if (thigh < thigh_min) {
sclh_min = sclh + 1;
continue;
}
if (ti2cclk >= thigh) {
sclh_min = sclh + 1;
continue;
}
// Binary search for SCLL
uint32_t scll_min = (tlow_min - filter_delay_ns + ti2cclk - 1) / ti2cclk - 1;
if (scll_min >= 256) {
sclh_min = sclh + 1;
continue;
}
uint32_t scll_max = 255;
while (scll_min <= scll_max) {
const uint32_t scll = (scll_min + scll_max) >> 1;
const uint32_t tscll = (scll + 1) * ti2cclk;
const uint32_t tlow = tscll + filter_delay_ns;
if (tlow < tlow_min) {
scll_min = scll + 1;
continue;
}
if (ti2cclk >= (tlow - filter_delay_ns) / 4) {
scll_min = scll + 1;
continue;
}
const uint32_t ttotal = tscll + tsclh + 2 * tsync;
if (ttotal < period_min) {
scll_min = scll + 1;
continue;
}
if (ttotal > period_max) {
scll_max = scll - 1;
continue;
}
// Calculate error
const uint32_t error = (ttotal > i2c_period_ns)
? ttotal - i2c_period_ns
: i2c_period_ns - ttotal;
// Update if better timing found
if (error < tmp_error) {
tmp_error = error;
tmp_presc = presc;
tmp_scldel = scldel;
tmp_sdadel = sdadel;
tmp_sclh = sclh;
tmp_scll = scll;
}
// Try to find better error by decreasing SCLL
scll_max = scll - 1;
}
// Try to find better error by decreasing SCLH
sclh_max = sclh - 1;
}
}
}
}
if (tmp_error == UINT32_MAX) {
return 0;
}
return (tmp_presc << 28) | (tmp_scldel << 20) | (tmp_sdadel << 16) | (tmp_sclh << 8) | tmp_scll;
}