Skip to content

STM32: driver/Added I2C timing calculation algorithm #14557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions targets/TARGET_STM/TARGET_STM32F0/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ target_sources(mbed-stm32f0
cmsis_nvic.c
flash_api.c
gpio_irq_device.c
i2c_device.c
pwmout_device.c
serial_device.c
spi_api.c
Expand Down
90 changes: 90 additions & 0 deletions targets/TARGET_STM/TARGET_STM32F0/i2c_device.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/* mbed Microcontroller Library
* SPDX-License-Identifier: BSD-3-Clause
******************************************************************************
*
* Copyright (c) 2021 STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/

#include "i2c_device.h"
#include "mbed_assert.h"
#include "mbed_error.h"
#include "stm32f0xx_ll_rcc.h"

/* Define I2C Device */
#if DEVICE_I2C

/**
* @brief Get I2C clock source frequency according I2C instance used.
* @param i2c I2C instance name.
* @retval I2C clock source frequency in Hz.
*/
uint32_t i2c_get_pclk(I2CName i2c)
{
uint32_t clocksource;
uint32_t pclk = 0;
if (i2c == I2C_1) {
clocksource = __HAL_RCC_GET_I2C1_SOURCE();
switch (clocksource) {
case RCC_I2C1CLKSOURCE_SYSCLK:
pclk = HAL_RCC_GetSysClockFreq();
break;

case RCC_I2C1CLKSOURCE_HSI:
pclk = HSI_VALUE;
break;
}
} else {
// should not happend
error("I2C: unknown instance");
}
return pclk;
}

/**
* @brief Provide the suitable timing depending on requested frequency
* @param hz Required I2C clock in Hz.
* @retval I2C timing or 0 in case of error.
*/
uint32_t i2c_get_timing(I2CName i2c, int hz)
{
uint32_t tim;
uint32_t pclk;

pclk = i2c_get_pclk(i2c);

if (pclk == I2C_PCLK_DEF) {
switch (hz) {
case 100000:
tim = TIMING_VAL_DEFAULT_CLK_100KHZ;
break;
case 400000:
tim = TIMING_VAL_DEFAULT_CLK_400KHZ;
break;
case 1000000:
tim = TIMING_VAL_DEFAULT_CLK_1MHZ;
break;
default:
MBED_ASSERT((hz == 100000) || (hz == 400000) || (hz == 1000000));
break;
}
}

else {
tim = i2c_compute_timing(pclk, hz);
}
return tim;
}

/**
* @}
*/

#endif // DEVICE_I2C
46 changes: 17 additions & 29 deletions targets/TARGET_STM/TARGET_STM32F0/i2c_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* SPDX-License-Identifier: BSD-3-Clause
******************************************************************************
*
* Copyright (c) 2015-2020 STMicroelectronics.
* Copyright (c) 2015-2021 STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under BSD 3-Clause license,
Expand All @@ -16,12 +16,13 @@
#ifndef MBED_I2C_DEVICE_H
#define MBED_I2C_DEVICE_H

#include "cmsis.h"
#include "PeripheralNames.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Define I2C Device */
#if DEVICE_I2C

#if defined I2C1_BASE
Expand All @@ -32,41 +33,28 @@ extern "C" {
#define I2C2_EV_IRQn I2C2_IRQn
#define I2C2_ER_IRQn I2C2_IRQn
#endif
#if defined I2C3_BASE
#define I2C3_EV_IRQn I2C3_IRQn
#define I2C3_ER_IRQn I2C3_IRQn
#endif

#define I2C_IT_ALL (I2C_IT_ERRI|I2C_IT_TCI|I2C_IT_STOPI|I2C_IT_NACKI|I2C_IT_ADDRI|I2C_IT_RXI|I2C_IT_TXI)


/* Define IP version */
#define I2C_IP_VERSION_V2

#define TIMING_VAL_DEFAULT_CLK_100KHZ 0x10805E89 // Standard mode with Rise Time = 400ns and Fall Time = 100ns
#define TIMING_VAL_DEFAULT_CLK_400KHZ 0x00901850 // Fast mode with Rise Time = 250ns and Fall Time = 100ns
#define TIMING_VAL_DEFAULT_CLK_1MHZ 0x00700818 // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns
#define I2C_PCLK_DEF 48000000 // 48 MHz

#define I2C_IT_ALL (I2C_IT_ERRI|I2C_IT_TCI|I2C_IT_STOPI|I2C_IT_NACKI|I2C_IT_ADDRI|I2C_IT_RXI|I2C_IT_TXI)

/* Family specifc settings for clock source */
#define I2CAPI_I2C1_CLKSRC RCC_I2C1CLKSOURCE_SYSCLK

/* Provide the suitable timing depending on requested frequencie */
static inline uint32_t get_i2c_timing(int hz)
{
uint32_t tim = 0;
uint32_t i2c_get_pclk(I2CName i2c);
uint32_t i2c_compute_timing(uint32_t clock_src_freq, uint32_t i2c_freq);
uint32_t i2c_get_timing(I2CName i2c, int hz);
void i2c_compute_presc_scldel_sdadel(uint32_t clock_src_freq, uint32_t I2C_speed);
uint32_t i2c_compute_scll_sclh(uint32_t clock_src_freq, uint32_t I2C_speed);

switch (hz) {
case 100000:
tim = 0x10805E89; // Standard mode with Rise Time = 400ns and Fall Time = 100ns
break;
case 400000:
tim = 0x00901850; // Fast mode with Rise Time = 250ns and Fall Time = 100ns
break;
case 1000000:
tim = 0x00700818; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns
break;
default:
break;
}
return tim;
#ifdef __cplusplus
}

#endif
#endif // DEVICE_I2C

#endif
1 change: 1 addition & 0 deletions targets/TARGET_STM/TARGET_STM32F3/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ target_sources(mbed-stm32f3
analogout_device.c
flash_api.c
gpio_irq_device.c
i2c_device.c
pwmout_device.c
serial_device.c
spi_api.c
Expand Down
134 changes: 134 additions & 0 deletions targets/TARGET_STM/TARGET_STM32F3/i2c_device.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/* mbed Microcontroller Library
* SPDX-License-Identifier: BSD-3-Clause
******************************************************************************
*
* Copyright (c) 2021 STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/

#include "i2c_device.h"
#include "mbed_assert.h"
#include "mbed_error.h"
#include "stm32f3xx_ll_rcc.h"

/* Define I2C Device */
#if DEVICE_I2C

/**
* @brief Get I2C clock source frequency according I2C instance used.
* @param i2c I2C instance name.
* @retval I2C clock source frequency in Hz.
*/
uint32_t i2c_get_pclk(I2CName i2c)
{
uint32_t clocksource;
uint32_t pclk = 0;
if (i2c == I2C_1) {
clocksource = __HAL_RCC_GET_I2C1_SOURCE();
switch (clocksource) {
case RCC_I2C1CLKSOURCE_SYSCLK:
pclk = HAL_RCC_GetSysClockFreq();
break;

case RCC_I2C1CLKSOURCE_HSI:
pclk = HSI_VALUE;
break;
}
}
#if defined I2C2_BASE
else if (i2c == I2C_2) {
clocksource = __HAL_RCC_GET_I2C2_SOURCE();
switch (clocksource) {
case RCC_I2C2CLKSOURCE_SYSCLK:
pclk = HAL_RCC_GetSysClockFreq();
break;

case RCC_I2C2CLKSOURCE_HSI:
pclk = HSI_VALUE;
break;
}
}
#endif
#if defined I2C3_BASE
else if (i2c == I2C_3) {
clocksource = __HAL_RCC_GET_I2C3_SOURCE();
switch (clocksource) {
case RCC_I2C3CLKSOURCE_SYSCLK:
pclk = HAL_RCC_GetSysClockFreq();
break;

case RCC_I2C3CLKSOURCE_HSI:
pclk = HSI_VALUE;
break;
}
}
#endif
else {
// should not happend
error("I2C: unknown instance");
}
return pclk;
}

/**
* @brief Provide the suitable timing depending on requested frequency
* @param hz Required I2C clock in Hz.
* @retval I2C timing or 0 in case of error.
*/
uint32_t i2c_get_timing(I2CName i2c, int hz)
{
uint32_t tim;
uint32_t pclk;

pclk = i2c_get_pclk(i2c);

if (pclk == I2C_PCLK_HSI) {
switch (hz) {
case 100000:
tim = TIMING_VAL_64M_CLK_100KHZ;
break;
case 400000:
tim = TIMING_VAL_64M_CLK_400KHZ;
break;
case 1000000:
tim = TIMING_VAL_64M_CLK_1MHZ;
break;
default:
MBED_ASSERT((hz == 100000) || (hz == 400000) || (hz == 1000000));
break;
}
} else if (pclk == I2C_PCLK_HSE) {
switch (hz) {
case 100000:
tim = TIMING_VAL_72M_CLK_100KHZ;
break;
case 400000:
tim = TIMING_VAL_72M_CLK_400KHZ;
break;
case 1000000:
tim = TIMING_VAL_72M_CLK_1MHZ;
break;
default:
MBED_ASSERT((hz == 100000) || (hz == 400000) || (hz == 1000000));
break;
}
}

else {
tim = i2c_compute_timing(pclk, hz);
}
return tim;
}

/**
* @}
*/

#endif // DEVICE_I2C
Loading