diff --git a/targets/TARGET_STM/TARGET_STM32F0/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32F0/CMakeLists.txt index fb1ef56291..cf33302d07 100644 --- a/targets/TARGET_STM/TARGET_STM32F0/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32F0/CMakeLists.txt @@ -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 diff --git a/targets/TARGET_STM/TARGET_STM32F0/i2c_device.c b/targets/TARGET_STM/TARGET_STM32F0/i2c_device.c new file mode 100755 index 0000000000..a14f653d46 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32F0/i2c_device.c @@ -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 diff --git a/targets/TARGET_STM/TARGET_STM32F0/i2c_device.h b/targets/TARGET_STM/TARGET_STM32F0/i2c_device.h index bda4eb7adb..1fb9f83404 100644 --- a/targets/TARGET_STM/TARGET_STM32F0/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32F0/i2c_device.h @@ -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, @@ -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 @@ -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 // DEVICE_I2C - +#endif +#endif // DEVICE_I2C #endif diff --git a/targets/TARGET_STM/TARGET_STM32F3/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32F3/CMakeLists.txt index b13377e017..f1684b7fc6 100644 --- a/targets/TARGET_STM/TARGET_STM32F3/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32F3/CMakeLists.txt @@ -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 diff --git a/targets/TARGET_STM/TARGET_STM32F3/i2c_device.c b/targets/TARGET_STM/TARGET_STM32F3/i2c_device.c new file mode 100755 index 0000000000..3ac6dc1b18 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32F3/i2c_device.c @@ -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 diff --git a/targets/TARGET_STM/TARGET_STM32F3/i2c_device.h b/targets/TARGET_STM/TARGET_STM32F3/i2c_device.h index 7ef29226aa..7e19708eb3 100644 --- a/targets/TARGET_STM/TARGET_STM32F3/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32F3/i2c_device.h @@ -1,6 +1,6 @@ /* mbed Microcontroller Library ******************************************************************************* - * Copyright (c) 2015, STMicroelectronics + * Copyright (c) 2015-2021, STMicroelectronics * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,76 +27,48 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************* */ + #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 -#define I2C_IP_VERSION_V2 +#define TIMING_VAL_64M_CLK_100KHZ 0x10B17DB4 // Standard mode with Rise time = 120ns, Fall time = 120ns +#define TIMING_VAL_64M_CLK_400KHZ 0x00E22163 // Fast Mode with Rise time = 120ns, Fall time = 120ns +#define TIMING_VAL_64M_CLK_1MHZ 0x00A00D1E // Fast Mode Plus with Rise time = 120ns, Fall time = 10ns +#define I2C_PCLK_HSI 64000000 // 64 MHz + +#define TIMING_VAL_72M_CLK_100KHZ 0x10D28DCB // Standard mode with Rise time = 120ns, Fall time = 120ns +#define TIMING_VAL_72M_CLK_400KHZ 0x00F32571 // Fast Mode with Rise time = 120ns, Fall time = 120ns +#define TIMING_VAL_72M_CLK_1MHZ 0x00C00D24 // Fast Mode Plus with Rise time = 120ns, Fall time = 10ns +#define I2C_PCLK_HSE 72000000 // 72 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) +/* Define IP version */ +#define I2C_IP_VERSION_V2 + /* Family specifc settings for clock source */ #define I2CAPI_I2C1_CLKSRC RCC_I2C1CLKSOURCE_SYSCLK #define I2CAPI_I2C2_CLKSRC RCC_I2C2CLKSOURCE_SYSCLK #define I2CAPI_I2C3_CLKSRC RCC_I2C3CLKSOURCE_SYSCLK -/* Provide the suitable timing depending on requested frequencie */ -static inline uint32_t get_i2c_timing(int hz) -{ - uint32_t tim = 0; - /* - Values calculated with I2C_Timing_Configuration_V1.0.1.xls file (see AN4235) - * Standard mode (up to 100 kHz) - * Fast Mode (up to 400 kHz) - * Fast Mode Plus (up to 1 MHz) - Below values obtained with: - - I2C clock source = 64 MHz (System Clock w/ HSI) or 72 (System Clock w/ HSE) - - Analog filter delay = ON - - Digital filter coefficient = 0 - */ - if (SystemCoreClock == 64000000) { - switch (hz) { - case 100000: - tim = 0x10B17DB4; // Standard mode with Rise time = 120ns, Fall time = 120ns - break; - case 400000: - tim = 0x00E22163; // Fast Mode with Rise time = 120ns, Fall time = 120ns - break; - case 1000000: - tim = 0x00A00D1E; // Fast Mode Plus with Rise time = 120ns, Fall time = 10ns - break; - default: - break; - } - } else if (SystemCoreClock == 72000000) { - switch (hz) { - case 100000: - tim = 0x10D28DCB; // Standard mode with Rise time = 120ns, Fall time = 120ns - break; - case 400000: - tim = 0x00F32571; // Fast Mode with Rise time = 120ns, Fall time = 120ns - break; - case 1000000: - tim = 0x00C00D24; // Fast Mode Plus with Rise time = 120ns, Fall time = 10ns - break; - default: - break; - } - } - return tim; -} +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); #ifdef __cplusplus } #endif - #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/TARGET_STM32F7/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32F7/CMakeLists.txt index a7e0becfd3..9cada3e83c 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32F7/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources(mbed-stm32f7 analogout_device.c flash_api.c gpio_irq_device.c + i2c_device.c pwmout_device.c serial_device.c spi_api.c diff --git a/targets/TARGET_STM/TARGET_STM32F7/i2c_device.c b/targets/TARGET_STM/TARGET_STM32F7/i2c_device.c new file mode 100755 index 0000000000..01d39d0a72 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32F7/i2c_device.c @@ -0,0 +1,144 @@ +/* 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 "stm32f7xx_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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + case RCC_I2C3CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C3CLKSOURCE_HSI: + pclk = HSI_VALUE; + break; + } + } +#endif +#if defined I2C4_BASE + else if (i2c == I2C_4) { + clocksource = __HAL_RCC_GET_I2C4_SOURCE(); + switch (clocksource) { + case RCC_I2C4CLKSOURCE_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + case RCC_I2C4CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C4CLKSOURCE_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_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 diff --git a/targets/TARGET_STM/TARGET_STM32F7/i2c_device.h b/targets/TARGET_STM/TARGET_STM32F7/i2c_device.h index 3bfbc23c86..66f9717bed 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32F7/i2c_device.h @@ -1,6 +1,6 @@ /* mbed Microcontroller Library ******************************************************************************* - * Copyright (c) 2015, STMicroelectronics + * Copyright (c) 2015-2021, STMicroelectronics * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,17 +27,25 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************* */ + #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 +#define TIMING_VAL_DEFAULT_CLK_100KHZ 0x10916998 // Standard mode with Rise time = 120ns, Fall time = 120ns +#define TIMING_VAL_DEFAULT_CLK_400KHZ 0x00B11B54 // Fast Mode with Rise time = 120ns, Fall time = 120ns +#define TIMING_VAL_DEFAULT_CLK_1MHZ 0x0090091B // Fast Mode Plus with Rise time = 120ns, Fall time = 10ns +#define I2C_PCLK_DEF 54000000 // 54 MHz + +/* Define IP version */ #define I2C_IP_VERSION_V2 #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) @@ -48,40 +56,14 @@ extern "C" { #define I2CAPI_I2C3_CLKSRC RCC_I2C3CLKSOURCE_PCLK1 #define I2CAPI_I2C4_CLKSRC RCC_I2C4CLKSOURCE_PCLK1 -/* Provide the suitable timing depending on requested frequencie */ -static inline uint32_t get_i2c_timing(int hz) -{ - uint32_t tim = 0; - /* - Values calculated with I2C_Timing_Configuration tool (excel file) - * Standard mode (up to 100 kHz) - * Fast Mode (up to 400 kHz) - * Fast Mode Plus (up to 1 MHz) - Below values obtained with: - - I2Cx clock source = APB1CLK = 54 MHz - - Analog filter delay = ON - - Digital filter coefficient = 0 - */ - switch (hz) { - case 100000: - tim = 0x10916998; // Standard mode with Rise time = 120ns, Fall time = 120ns - break; - case 400000: - tim = 0x00B11B54; // Fast Mode with Rise time = 120ns, Fall time = 120ns - break; - case 1000000: - tim = 0x0090091B; // Fast Mode Plus with Rise time = 120ns, Fall time = 10ns - break; - default: - break; - } - return tim; -} +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); #ifdef __cplusplus } #endif - #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/TARGET_STM32G0/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32G0/CMakeLists.txt index 697a933c3e..6fabba85b5 100644 --- a/targets/TARGET_STM/TARGET_STM32G0/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32G0/CMakeLists.txt @@ -17,6 +17,7 @@ target_sources(mbed-stm32g0 analogout_device.c flash_api.c gpio_irq_device.c + i2c_device.c pwmout_device.c serial_device.c spi_api.c diff --git a/targets/TARGET_STM/TARGET_STM32G0/i2c_device.c b/targets/TARGET_STM/TARGET_STM32G0/i2c_device.c new file mode 100755 index 0000000000..f20aae22f8 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32G0/i2c_device.c @@ -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 "stm32g0xx_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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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 diff --git a/targets/TARGET_STM/TARGET_STM32G0/i2c_device.h b/targets/TARGET_STM/TARGET_STM32G0/i2c_device.h index 21d527549c..4b189f7abc 100644 --- a/targets/TARGET_STM/TARGET_STM32G0/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32G0/i2c_device.h @@ -2,7 +2,7 @@ * SPDX-License-Identifier: BSD-3-Clause ****************************************************************************** * - * Copyright (c) 2015 STMicroelectronics. + * Copyright (c) 2015-2021 STMicroelectronics. * All rights reserved. * * This software component is licensed by ST under BSD 3-Clause license, @@ -12,19 +12,27 @@ * ****************************************************************************** */ + #ifndef MBED_I2C_DEVICE_H #define MBED_I2C_DEVICE_H -#include "cmsis.h" +#include "PeripheralNames.h" #ifdef __cplusplus extern "C" { #endif +/* Define IP version */ #if DEVICE_I2C -#define I2C_IP_VERSION_V2 +// Common settings: I2C clock = 64 MHz, Analog filter = ON, Digital filter coefficient = 0 +#define TIMING_VAL_DEFAULT_CLK_100KHZ 0xC0311319 // Standard mode with Rise Time = 400ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_400KHZ 0x10B1102E // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_1MHZ 0x00710B1E // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns +#define I2C_PCLK_DEF 64000000 // 64 MHz +/* Define IP version */ +#define I2C_IP_VERSION_V2 #define I2C1_EV_IRQn I2C1_IRQn #define I2C1_ER_IRQn I2C1_IRQn @@ -32,39 +40,20 @@ extern "C" { #define I2C2_EV_IRQn I2C2_IRQn #define I2C2_ER_IRQn I2C2_IRQn - - #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 #define I2CAPI_I2C2_CLKSRC RCC_I2C2CLKSOURCE_SYSCLK -/* Provide the suitable timing depending on requested frequencie */ -static inline uint32_t get_i2c_timing(int hz) -{ - uint32_t tim = 0; - // Common settings: I2C clock = 64 MHz, Analog filter = ON, Digital filter coefficient = 0 - switch (hz) { - case 100000: - tim = 0xC0311319; // Standard mode with Rise Time = 400ns and Fall Time = 100ns - break; - case 400000: - tim = 0x10B1102E; // Fast mode with Rise Time = 250ns and Fall Time = 100ns - break; - case 1000000: - tim = 0x00710B1E; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns - break; - default: - break; - } - return tim; -} +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); #ifdef __cplusplus } #endif - #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/TARGET_STM32G4/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32G4/CMakeLists.txt index 298030962a..a670385d2d 100644 --- a/targets/TARGET_STM/TARGET_STM32G4/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32G4/CMakeLists.txt @@ -18,6 +18,7 @@ target_sources(mbed-stm32g4 analogout_device.c flash_api.c gpio_irq_device.c + i2c_device.c pwmout_device.c serial_device.c spi_api.c diff --git a/targets/TARGET_STM/TARGET_STM32G4/i2c_device.c b/targets/TARGET_STM/TARGET_STM32G4/i2c_device.c new file mode 100755 index 0000000000..dfd06765f9 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32G4/i2c_device.c @@ -0,0 +1,143 @@ +/* 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 "stm32g4xx_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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + case RCC_I2C3CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C3CLKSOURCE_HSI: + pclk = HSI_VALUE; + break; + } + } +#endif +#if defined I2C4_BASE + else if (i2c == I2C_4) { + clocksource = __HAL_RCC_GET_I2C4_SOURCE(); + switch (clocksource) { + case RCC_I2C4CLKSOURCE_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + case RCC_I2C4CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C4CLKSOURCE_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_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 diff --git a/targets/TARGET_STM/TARGET_STM32G4/i2c_device.h b/targets/TARGET_STM/TARGET_STM32G4/i2c_device.h index 35f5c320e1..dada081833 100644 --- a/targets/TARGET_STM/TARGET_STM32G4/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32G4/i2c_device.h @@ -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, @@ -16,14 +16,22 @@ #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 +// Common settings: I2C clock = 64 MHz, Analog filter = ON, Digital filter coefficient = 0 +#define TIMING_VAL_DEFAULT_CLK_100KHZ 0xC0311319 // Standard mode with Rise Time = 400ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_400KHZ 0x10B1102E // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_1MHZ 0x00710B1E // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns +#define I2C_PCLK_DEF 170000000 // 170 MHz + +/* Define IP version */ #define I2C_IP_VERSION_V2 #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) @@ -34,31 +42,14 @@ extern "C" { #define I2CAPI_I2C3_CLKSRC RCC_I2C3CLKSOURCE_SYSCLK #define I2CAPI_I2C4_CLKSRC RCC_I2C4CLKSOURCE_SYSCLK -/* Provide the suitable timing depending on requested frequencie */ -static inline uint32_t get_i2c_timing(int hz) -{ - uint32_t tim = 0; - // Common settings: I2C clock = 64 MHz, Analog filter = ON, Digital filter coefficient = 0 - switch (hz) { - case 100000: - tim = 0xC0311319; // Standard mode with Rise Time = 400ns and Fall Time = 100ns - break; - case 400000: - tim = 0x10B1102E; // Fast mode with Rise Time = 250ns and Fall Time = 100ns - break; - case 1000000: - tim = 0x00710B1E; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns - break; - default: - break; - } - return tim; -} +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); #ifdef __cplusplus } #endif - #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/TARGET_STM32H7/i2c_device.c b/targets/TARGET_STM/TARGET_STM32H7/i2c_device.c old mode 100644 new mode 100755 index b1a9e8b182..889192c157 --- a/targets/TARGET_STM/TARGET_STM32H7/i2c_device.c +++ b/targets/TARGET_STM/TARGET_STM32H7/i2c_device.c @@ -2,8 +2,7 @@ * SPDX-License-Identifier: BSD-3-Clause ****************************************************************************** * - * Copyright (c) 2015-2020 STMicroelectronics. - * Copyright (c) 2020, Arduino SA. + * Copyright (c) 2021 STMicroelectronics. * All rights reserved. * * This software component is licensed by ST under BSD 3-Clause license, @@ -19,313 +18,20 @@ #include "mbed_error.h" #include "stm32h7xx_ll_rcc.h" +/* Define I2C Device */ #if DEVICE_I2C -/** @defgroup I2C_DEVICE_Private_Constants I2C_DEVICE Private Constants - * @{ - */ -#ifndef I2C_VALID_TIMING_NBR -#define I2C_VALID_TIMING_NBR 128U -#endif -#define I2C_SPEED_FREQ_STANDARD 0U /* 100 kHz */ -#define I2C_SPEED_FREQ_FAST 1U /* 400 kHz */ -#define I2C_SPEED_FREQ_FAST_PLUS 2U /* 1 MHz */ -#define I2C_ANALOG_FILTER_DELAY_MIN 50U /* ns */ -#define I2C_ANALOG_FILTER_DELAY_MAX 260U /* ns */ -#define I2C_USE_ANALOG_FILTER 1U -#define I2C_DIGITAL_FILTER_COEF 0U -#define I2C_PRESC_MAX 16U -#define I2C_SCLDEL_MAX 16U -#define I2C_SDADEL_MAX 16U -#define I2C_SCLH_MAX 256U -#define I2C_SCLL_MAX 256U -#define SEC2NSEC 1000000000UL -/** - * @} - */ - -/** @defgroup I2C_DEVICE_Private_Types I2C_DEVICE Private Types - * @{ - */ -typedef struct { - uint32_t freq; /* Frequency in Hz */ - uint32_t freq_min; /* Minimum frequency in Hz */ - uint32_t freq_max; /* Maximum frequency in Hz */ - uint32_t hddat_min; /* Minimum data hold time in ns */ - uint32_t vddat_max; /* Maximum data valid time in ns */ - uint32_t sudat_min; /* Minimum data setup time in ns */ - uint32_t lscl_min; /* Minimum low period of the SCL clock in ns */ - uint32_t hscl_min; /* Minimum high period of SCL clock in ns */ - uint32_t trise; /* Rise time in ns */ - uint32_t tfall; /* Fall time in ns */ - uint32_t dnf; /* Digital noise filter coefficient */ -} I2C_Charac_t; - -typedef struct { - uint32_t presc; /* Timing prescaler */ - uint32_t tscldel; /* SCL delay */ - uint32_t tsdadel; /* SDA delay */ - uint32_t sclh; /* SCL high period */ - uint32_t scll; /* SCL low period */ -} I2C_Timings_t; -/** - * @} - */ - -/** @defgroup I2C_DEVICE_Private_Constants I2C_DEVICE Private Constants - * @{ - */ -static const I2C_Charac_t I2C_Charac[] = { - [I2C_SPEED_FREQ_STANDARD] = - { - .freq = 100000, - .freq_min = 80000, - .freq_max = 120000, - .hddat_min = 0, - .vddat_max = 3450, - .sudat_min = 250, - .lscl_min = 4700, - .hscl_min = 4000, - .trise = 640, - .tfall = 20, - .dnf = I2C_DIGITAL_FILTER_COEF, - }, - [I2C_SPEED_FREQ_FAST] = - { - .freq = 400000, - .freq_min = 320000, - .freq_max = 480000, - .hddat_min = 0, - .vddat_max = 900, - .sudat_min = 100, - .lscl_min = 1300, - .hscl_min = 600, - .trise = 250, - .tfall = 100, - .dnf = I2C_DIGITAL_FILTER_COEF, - }, - [I2C_SPEED_FREQ_FAST_PLUS] = - { - .freq = 1000000, - .freq_min = 800000, - .freq_max = 1200000, - .hddat_min = 0, - .vddat_max = 450, - .sudat_min = 50, - .lscl_min = 500, - .hscl_min = 260, - .trise = 60, - .tfall = 100, - .dnf = I2C_DIGITAL_FILTER_COEF, - }, -}; -/** - * @} - */ - -/** @defgroup I2C_DEVICE_Private_Variables I2C_DEVICE Private Variables -* @{ -*/ -static I2C_Timings_t I2c_valid_timing[I2C_VALID_TIMING_NBR]; -static uint32_t I2c_valid_timing_nbr = 0; -/** - * @} - */ - -/** @defgroup I2C_DEVICE_Private_Functions I2C_DEVICE Private Functions - * @{ - */ -/** - * @brief Compute PRESC, SCLDEL and SDADEL. - * @param clock_src_freq I2C source clock in HZ. - * @param I2C_speed I2C frequency (index). - * @retval None. - */ -static void I2C_Compute_PRESC_SCLDEL_SDADEL(uint32_t clock_src_freq, uint32_t I2C_speed) -{ - uint32_t prev_presc = I2C_PRESC_MAX; - uint32_t ti2cclk; - int32_t tsdadel_min, tsdadel_max; - int32_t tscldel_min; - uint32_t presc, scldel, sdadel; - uint32_t tafdel_min, tafdel_max; - - ti2cclk = (SEC2NSEC + (clock_src_freq / 2U)) / clock_src_freq; - - tafdel_min = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MIN : 0U; - tafdel_max = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MAX : 0U; - - /* tDNF = DNF x tI2CCLK - tPRESC = (PRESC+1) x tI2CCLK - SDADEL >= {tf +tHD;DAT(min) - tAF(min) - tDNF - [3 x tI2CCLK]} / {tPRESC} - SDADEL <= {tVD;DAT(max) - tr - tAF(max) - tDNF- [4 x tI2CCLK]} / {tPRESC} */ - - tsdadel_min = (int32_t)I2C_Charac[I2C_speed].tfall + (int32_t)I2C_Charac[I2C_speed].hddat_min - - (int32_t)tafdel_min - (int32_t)(((int32_t)I2C_Charac[I2C_speed].dnf + 3) * (int32_t)ti2cclk); - - tsdadel_max = (int32_t)I2C_Charac[I2C_speed].vddat_max - (int32_t)I2C_Charac[I2C_speed].trise - - (int32_t)tafdel_max - (int32_t)(((int32_t)I2C_Charac[I2C_speed].dnf + 4) * (int32_t)ti2cclk); - - - /* {[tr+ tSU;DAT(min)] / [tPRESC]} - 1 <= SCLDEL */ - tscldel_min = (int32_t)I2C_Charac[I2C_speed].trise + (int32_t)I2C_Charac[I2C_speed].sudat_min; - - if (tsdadel_min <= 0) { - tsdadel_min = 0; - } - - if (tsdadel_max <= 0) { - tsdadel_max = 0; - } - - for (presc = 0; presc < I2C_PRESC_MAX; presc++) { - for (scldel = 0; scldel < I2C_SCLDEL_MAX; scldel++) { - /* TSCLDEL = (SCLDEL+1) * (PRESC+1) * TI2CCLK */ - uint32_t tscldel = (scldel + 1U) * (presc + 1U) * ti2cclk; - - if (tscldel >= (uint32_t)tscldel_min) { - for (sdadel = 0; sdadel < I2C_SDADEL_MAX; sdadel++) { - /* TSDADEL = SDADEL * (PRESC+1) * TI2CCLK */ - uint32_t tsdadel = (sdadel * (presc + 1U)) * ti2cclk; - - if ((tsdadel >= (uint32_t)tsdadel_min) && (tsdadel <= (uint32_t)tsdadel_max)) { - if (presc != prev_presc) { - I2c_valid_timing[I2c_valid_timing_nbr].presc = presc; - I2c_valid_timing[I2c_valid_timing_nbr].tscldel = scldel; - I2c_valid_timing[I2c_valid_timing_nbr].tsdadel = sdadel; - prev_presc = presc; - I2c_valid_timing_nbr ++; - - if (I2c_valid_timing_nbr >= I2C_VALID_TIMING_NBR) { - return; - } - } - } - } - } - } - } -} - -/** - * @brief Calculate SCLL and SCLH and find best configuration. - * @param clock_src_freq I2C source clock in HZ. - * @param I2C_speed I2C frequency (index). - * @retval config index (0 to I2C_VALID_TIMING_NBR], 0xFFFFFFFF for no valid config. - */ -static uint32_t I2C_Compute_SCLL_SCLH(uint32_t clock_src_freq, uint32_t I2C_speed) -{ - uint32_t ret = 0xFFFFFFFFU; - uint32_t ti2cclk; - uint32_t ti2cspeed; - uint32_t prev_error; - uint32_t dnf_delay; - uint32_t clk_min, clk_max; - uint32_t scll, sclh; - uint32_t tafdel_min; - - ti2cclk = (SEC2NSEC + (clock_src_freq / 2U)) / clock_src_freq; - ti2cspeed = (SEC2NSEC + (I2C_Charac[I2C_speed].freq / 2U)) / I2C_Charac[I2C_speed].freq; - - tafdel_min = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MIN : 0U; - - /* tDNF = DNF x tI2CCLK */ - dnf_delay = I2C_Charac[I2C_speed].dnf * ti2cclk; - - clk_max = SEC2NSEC / I2C_Charac[I2C_speed].freq_min; - clk_min = SEC2NSEC / I2C_Charac[I2C_speed].freq_max; - - prev_error = ti2cspeed; - - for (uint32_t count = 0; count < I2c_valid_timing_nbr; count++) { - /* tPRESC = (PRESC+1) x tI2CCLK*/ - uint32_t tpresc = (I2c_valid_timing[count].presc + 1U) * ti2cclk; - - for (scll = 0; scll < I2C_SCLL_MAX; scll++) { - /* tLOW(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLL+1) x tPRESC ] */ - uint32_t tscl_l = tafdel_min + dnf_delay + (2U * ti2cclk) + ((scll + 1U) * tpresc); - - - /* The I2CCLK period tI2CCLK must respect the following conditions: - tI2CCLK < (tLOW - tfilters) / 4 and tI2CCLK < tHIGH */ - if ((tscl_l > I2C_Charac[I2C_speed].lscl_min) && (ti2cclk < ((tscl_l - tafdel_min - dnf_delay) / 4U))) { - for (sclh = 0; sclh < I2C_SCLH_MAX; sclh++) { - /* tHIGH(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLH+1) x tPRESC] */ - uint32_t tscl_h = tafdel_min + dnf_delay + (2U * ti2cclk) + ((sclh + 1U) * tpresc); - - /* tSCL = tf + tLOW + tr + tHIGH */ - uint32_t tscl = tscl_l + tscl_h + I2C_Charac[I2C_speed].trise + I2C_Charac[I2C_speed].tfall; - - if ((tscl >= clk_min) && (tscl <= clk_max) && (tscl_h >= I2C_Charac[I2C_speed].hscl_min) && (ti2cclk < tscl_h)) { - int32_t error = (int32_t)tscl - (int32_t)ti2cspeed; - - if (error < 0) { - error = -error; - } - - /* look for the timings with the lowest clock error */ - if ((uint32_t)error < prev_error) { - prev_error = (uint32_t)error; - I2c_valid_timing[count].scll = scll; - I2c_valid_timing[count].sclh = sclh; - ret = count; - } - } - } - } - } - } - - return ret; -} - -/** - * @brief Compute I2C timing according current I2C clock source and required I2C clock. - * @param clock_src_freq I2C clock source in Hz. - * @param i2c_freq Required I2C clock in Hz. - * @retval I2C timing or 0 in case of error. - */ -static uint32_t I2C_ComputeTiming(uint32_t clock_src_freq, uint32_t i2c_freq) -{ - uint32_t ret = 0; - uint32_t speed; - uint32_t idx; - - - if ((clock_src_freq != 0U) && (i2c_freq != 0U)) { - for (speed = 0 ; speed <= (uint32_t)I2C_SPEED_FREQ_FAST_PLUS ; speed++) { - if ((i2c_freq >= I2C_Charac[speed].freq_min) && - (i2c_freq <= I2C_Charac[speed].freq_max)) { - I2C_Compute_PRESC_SCLDEL_SDADEL(clock_src_freq, speed); - idx = I2C_Compute_SCLL_SCLH(clock_src_freq, speed); - - if (idx < I2C_VALID_TIMING_NBR) { - ret = ((I2c_valid_timing[idx].presc & 0x0FU) << 28) | \ - ((I2c_valid_timing[idx].tscldel & 0x0FU) << 20) | \ - ((I2c_valid_timing[idx].tsdadel & 0x0FU) << 16) | \ - ((I2c_valid_timing[idx].sclh & 0xFFU) << 8) | \ - ((I2c_valid_timing[idx].scll & 0xFFU) << 0); - } - break; - } - } - } - - return ret; -} - /** * @brief Get I2C clock source frequency according I2C instance used. * @param i2c I2C instance name. * @retval I2C clock source frequency in Hz. */ -static uint32_t I2C_GetPclk(I2CName i2c) +uint32_t i2c_get_pclk(I2CName i2c) { uint32_t clocksource; uint32_t pclk = 0; PLL3_ClocksTypeDef pll3_clocks; - - if (i2c == I2C_1 || i2c == I2C_2 || i2c == I2C_3) { + if ((i2c == I2C_1) || (i2c == I2C_2) || (i2c == I2C_3)) { clocksource = __HAL_RCC_GET_I2C123_SOURCE(); switch (clocksource) { case RCC_I2C123CLKSOURCE_D2PCLK1: @@ -346,7 +52,9 @@ static uint32_t I2C_GetPclk(I2CName i2c) error("I2C123: Invalid clock source"); break; } - } else if (i2c == I2C_4) { + } +#if defined I2C4_BASE + else if (i2c == I2C_4) { clocksource = __HAL_RCC_GET_I2C4_SOURCE(); switch (clocksource) { case RCC_I2C4CLKSOURCE_D3PCLK1: @@ -367,11 +75,12 @@ static uint32_t I2C_GetPclk(I2CName i2c) error("I2C4: Invalid clock source"); break; } - } else { + } +#endif + else { // should not happend error("I2C: unknown instance"); } - return pclk; } /** @@ -386,17 +95,29 @@ static uint32_t I2C_GetPclk(I2CName i2c) * @param hz Required I2C clock in Hz. * @retval I2C timing or 0 in case of error. */ -uint32_t get_i2c_timing(I2CName i2c, int hz) +uint32_t i2c_get_timing(I2CName i2c, int hz) { uint32_t tim; uint32_t pclk; - - I2c_valid_timing_nbr = 0; - - pclk = I2C_GetPclk(i2c); - - tim = I2C_ComputeTiming(pclk, hz); - + 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; } /** diff --git a/targets/TARGET_STM/TARGET_STM32H7/i2c_device.h b/targets/TARGET_STM/TARGET_STM32H7/i2c_device.h index 829290d9c6..cc56874f26 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32H7/i2c_device.h @@ -2,7 +2,7 @@ * SPDX-License-Identifier: BSD-3-Clause ****************************************************************************** * - * Copyright (c) 2015-2020 STMicroelectronics. + * Copyright (c) 2015-2021 STMicroelectronics. * Copyright (c) 2020, Arduino SA. * All rights reserved. * @@ -23,10 +23,17 @@ extern "C" { #endif +/* Define I2C Device */ #if DEVICE_I2C +/* Define IP version */ #define I2C_IP_VERSION_V2 +#define TIMING_VAL_DEFAULT_CLK_100KHZ 0x40E15676 // Standard mode with Rise Time = 400ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_400KHZ 0x20C11434 // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_1MHZ 0x00C31536 // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns +#define I2C_PCLK_DEF 120000000 // 120 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 */ @@ -35,14 +42,14 @@ extern "C" { #define I2CAPI_I2C3_CLKSRC RCC_I2C3CLKSOURCE_D2PCLK1 #define I2CAPI_I2C4_CLKSRC RCC_I2C4CLKSOURCE_D3PCLK1 -/* Provide the suitable timing depending on requested frequency */ -extern uint32_t get_i2c_timing(I2CName i2c, int hz); - +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); #ifdef __cplusplus } #endif - #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/TARGET_STM32L0/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32L0/CMakeLists.txt index fbeb9c20d8..a9a2a6c5d3 100644 --- a/targets/TARGET_STM/TARGET_STM32L0/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32L0/CMakeLists.txt @@ -17,6 +17,7 @@ target_sources(mbed-stm32l0 analogout_device.c flash_api.c gpio_irq_device.c + i2c_device.c pwmout_device.c serial_device.c spi_api.c diff --git a/targets/TARGET_STM/TARGET_STM32L0/i2c_device.c b/targets/TARGET_STM/TARGET_STM32L0/i2c_device.c new file mode 100755 index 0000000000..21df6a93a6 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L0/i2c_device.c @@ -0,0 +1,114 @@ +/* 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 "stm32l0xx_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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + case RCC_I2C1CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C1CLKSOURCE_HSI: + pclk = HSI_VALUE; + break; + } + } +#if defined I2C3_BASE + else if (i2c == I2C_3) { + clocksource = __HAL_RCC_GET_I2C3_SOURCE(); + switch (clocksource) { + case RCC_I2C3CLKSOURCE_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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; +} +/** + * @} + */ + +/** @defgroup I2C_DEVICE_Exported_Functions I2C_DEVICE Exported Functions + * @{ + */ +/** + * @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 diff --git a/targets/TARGET_STM/TARGET_STM32L0/i2c_device.h b/targets/TARGET_STM/TARGET_STM32L0/i2c_device.h index 175bde9f2d..b5e50a17eb 100644 --- a/targets/TARGET_STM/TARGET_STM32L0/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32L0/i2c_device.h @@ -2,7 +2,7 @@ * SPDX-License-Identifier: BSD-3-Clause ****************************************************************************** * - * Copyright (c) 2016-2020 STMicroelectronics. + * Copyright (c) 2016-2021 STMicroelectronics. * All rights reserved. * * This software component is licensed by ST under BSD 3-Clause license, @@ -12,17 +12,20 @@ * ****************************************************************************** */ + #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 +/* Define IP version */ #define I2C_IP_VERSION_V2 #if defined I2C1_BASE @@ -38,6 +41,11 @@ extern "C" { #define I2C3_ER_IRQn I2C3_IRQn #endif +#define TIMING_VAL_DEFAULT_CLK_100KHZ 0x20602938 // Standard mode with Rise Time = 400ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_400KHZ 0x00B0122A // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_1MHZ 0x0030040E // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns +#define I2C_PCLK_DEF 32000000 // 32 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 */ @@ -45,31 +53,14 @@ extern "C" { #define I2CAPI_I2C3_CLKSRC RCC_I2C3CLKSOURCE_SYSCLK #define I2CAPI_I2C4_CLKSRC RCC_I2C4CLKSOURCE_SYSCLK -/* Provide the suitable timing depending on requested frequencie */ -static inline uint32_t get_i2c_timing(int hz) -{ - uint32_t tim = 0; - - switch (hz) { - case 100000: - tim = 0x20602938; // Standard mode with Rise Time = 400ns and Fall Time = 100ns - break; - case 400000: - tim = 0x00B0122A; // Fast mode with Rise Time = 250ns and Fall Time = 100ns - break; - case 1000000: - tim = 0x0030040E; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns - break; - default: - break; - } - return tim; -} +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); #ifdef __cplusplus } #endif - #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/TARGET_STM32L4/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32L4/CMakeLists.txt index 0642e934d0..6664473031 100644 --- a/targets/TARGET_STM/TARGET_STM32L4/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32L4/CMakeLists.txt @@ -23,6 +23,7 @@ target_sources(mbed-stm32l4 analogout_device.c flash_api.c gpio_irq_device.c + i2c_device.c pwmout_device.c serial_device.c spi_api.c diff --git a/targets/TARGET_STM/TARGET_STM32L4/i2c_device.c b/targets/TARGET_STM/TARGET_STM32L4/i2c_device.c new file mode 100755 index 0000000000..0db4d13000 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L4/i2c_device.c @@ -0,0 +1,179 @@ +/* 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 "stm32l4xx_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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + case RCC_I2C3CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C3CLKSOURCE_HSI: + pclk = HSI_VALUE; + break; + } + } +#endif +#if defined I2C4_BASE + else if (i2c == I2C_4) { + clocksource = __HAL_RCC_GET_I2C4_SOURCE(); + switch (clocksource) { + case RCC_I2C4CLKSOURCE_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + case RCC_I2C4CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C4CLKSOURCE_HSI: + pclk = HSI_VALUE; + break; + } + } +#endif + else { + // should not happend + error("I2C: unknown instance"); + } + return pclk; +} +/** + * @} + */ + +/** @defgroup I2C_DEVICE_Exported_Functions I2C_DEVICE Exported Functions + * @{ + */ +/** + * @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_80M) { + switch (hz) { + case 100000: + tim = TIMING_VAL_80M_CLK_100KHZ; + break; + case 400000: + tim = TIMING_VAL_80M_CLK_400KHZ; + break; + case 1000000: + tim = TIMING_VAL_80M_CLK_1MHZ; + break; + default: + MBED_ASSERT((hz == 100000) || (hz == 400000) || (hz == 1000000)); + break; + } + } else if (pclk == I2C_PCLK_48M) { + switch (hz) { + case 100000: + tim = TIMING_VAL_48M_CLK_100KHZ; + break; + case 400000: + tim = TIMING_VAL_48M_CLK_400KHZ; + break; + case 1000000: + tim = TIMING_VAL_48M_CLK_1MHZ; + break; + default: + MBED_ASSERT((hz == 100000) || (hz == 400000) || (hz == 1000000)); + break; + } + } else if (pclk == I2C_PCLK_120M) { + switch (hz) { + case 100000: + tim = TIMING_VAL_120M_CLK_100KHZ; + break; + case 400000: + tim = TIMING_VAL_120M_CLK_400KHZ; + break; + case 1000000: + tim = TIMING_VAL_120M_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 diff --git a/targets/TARGET_STM/TARGET_STM32L4/i2c_device.h b/targets/TARGET_STM/TARGET_STM32L4/i2c_device.h index 6368b4c53b..9cd5712954 100644 --- a/targets/TARGET_STM/TARGET_STM32L4/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32L4/i2c_device.h @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2016-2020 STMicroelectronics + * Copyright (c) 2016-2021 STMicroelectronics * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,17 +18,36 @@ #ifndef MBED_I2C_DEVICE_H #define MBED_I2C_DEVICE_H -#include "cmsis.h" -#include "mbed_error.h" +#include "PeripheralNames.h" #ifdef __cplusplus extern "C" { #endif +/* Define I2C Device */ #if DEVICE_I2C +/* Define IP version */ #define I2C_IP_VERSION_V2 +// Common settings: I2C clock = 80 MHz, Analog filter = ON, Digital filter coefficient = 0 +#define TIMING_VAL_80M_CLK_100KHZ 0x30C14E6B // Standard mode with Rise Time = 400ns and Fall Time = 100ns +#define TIMING_VAL_80M_CLK_400KHZ 0x10D1143A // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_80M_CLK_1MHZ 0x00810E27 // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns +#define I2C_PCLK_80M 80000000 // 80 MHz + +// Common settings: I2C clock = 48 MHz, Analog filter = ON, Digital filter coefficient = 0 +#define TIMING_VAL_48M_CLK_100KHZ 0x20A03E55 // Standard mode with Rise Time = 400ns and Fall Time = 100ns +#define TIMING_VAL_48M_CLK_400KHZ 0x10800C21 // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_48M_CLK_1MHZ 0x00500816 // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns +#define I2C_PCLK_48M 48000000 // 48 MHz + +// Common settings: I2C clock = 120 MHz, Analog filter = ON, Digital filter coefficient = 0 +#define TIMING_VAL_120M_CLK_100KHZ 0x107075B0 // Standard mode with Rise Time = 400ns and Fall Time = 100ns +#define TIMING_VAL_120M_CLK_400KHZ 0x00501E6C // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_120M_CLK_1MHZ 0x00200A26 // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns +#define I2C_PCLK_120M 120000000 // 120 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 */ @@ -37,65 +56,14 @@ extern "C" { #define I2CAPI_I2C3_CLKSRC RCC_I2C3CLKSOURCE_SYSCLK #define I2CAPI_I2C4_CLKSRC RCC_I2C4CLKSOURCE_SYSCLK -/* Provide the suitable timing depending on requested frequencie */ -static inline uint32_t get_i2c_timing(int hz) -{ - uint32_t tim = 0; - if (SystemCoreClock == 80000000) { - // Common settings: I2C clock = 80 MHz, Analog filter = ON, Digital filter coefficient = 0 - switch (hz) { - case 100000: - tim = 0x30C14E6B; // Standard mode with Rise Time = 400ns and Fall Time = 100ns - break; - case 400000: - tim = 0x10D1143A; // Fast mode with Rise Time = 250ns and Fall Time = 100ns - break; - case 1000000: - tim = 0x00810E27; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns - break; - default: - break; - } - } else if (SystemCoreClock == 48000000) { - // Common settings: I2C clock = 48 MHz, Analog filter = ON, Digital filter coefficient = 0 - switch (hz) { - case 100000: - tim = 0x20A03E55; // Standard mode with Rise Time = 400ns and Fall Time = 100ns - break; - case 400000: - tim = 0x10800C21; // Fast mode with Rise Time = 250ns and Fall Time = 100ns - break; - case 1000000: - tim = 0x00500816; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns - break; - default: - break; - } - } else if (SystemCoreClock == 120000000) { - // Common settings: I2C clock = 120 MHz, Analog filter = ON, Digital filter coefficient = 0 - switch (hz) { - case 100000: - tim = 0x107075B0; // Standard mode with Rise Time = 400ns and Fall Time = 100ns - break; - case 400000: - tim = 0x00501E6C; // Fast mode with Rise Time = 250ns and Fall Time = 100ns - break; - case 1000000: - tim = 0x00200A26; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns - break; - default: - break; - } - } else { - error("get_i2c_timing error\n"); - } - return tim; -} +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); #ifdef __cplusplus } #endif - #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/TARGET_STM32L5/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32L5/CMakeLists.txt index fe6e123def..54a213bb2b 100644 --- a/targets/TARGET_STM/TARGET_STM32L5/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32L5/CMakeLists.txt @@ -14,6 +14,7 @@ target_sources(mbed-stm32l5 analogout_device.c flash_api.c gpio_irq_device.c + i2c_device.c pwmout_device.c serial_device.c system_clock.c diff --git a/targets/TARGET_STM/TARGET_STM32L5/i2c_device.c b/targets/TARGET_STM/TARGET_STM32L5/i2c_device.c new file mode 100755 index 0000000000..84fe773c67 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L5/i2c_device.c @@ -0,0 +1,153 @@ +/* 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 "stm32l5xx_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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + case RCC_I2C3CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C3CLKSOURCE_HSI: + pclk = HSI_VALUE; + break; + } + } +#endif +#if defined I2C4_BASE + else if (i2c == I2C_4) { + clocksource = __HAL_RCC_GET_I2C4_SOURCE(); + switch (clocksource) { + case RCC_I2C4CLKSOURCE_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + case RCC_I2C4CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C4CLKSOURCE_HSI: + pclk = HSI_VALUE; + break; + } + } +#endif + else { + // should not happend + error("I2C: unknown instance"); + } + return pclk; +} +/** + * @} + */ + +/** @defgroup I2C_DEVICE_Exported_Functions I2C_DEVICE Exported Functions + * @{ + */ +/** + * @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 diff --git a/targets/TARGET_STM/TARGET_STM32L5/i2c_device.h b/targets/TARGET_STM/TARGET_STM32L5/i2c_device.h index 90ee70c22f..c3d1a2797a 100644 --- a/targets/TARGET_STM/TARGET_STM32L5/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32L5/i2c_device.h @@ -2,7 +2,7 @@ * SPDX-License-Identifier: BSD-3-Clause ****************************************************************************** * - * Copyright (c) 2015 STMicroelectronics. + * Copyright (c) 2015-2021 STMicroelectronics. * All rights reserved. * * This software component is licensed by ST under BSD 3-Clause license, @@ -16,17 +16,24 @@ #ifndef MBED_I2C_DEVICE_H #define MBED_I2C_DEVICE_H -#include "cmsis.h" -#include "mbed_error.h" +#include "PeripheralNames.h" #ifdef __cplusplus extern "C" { #endif +/* Define I2C Device */ #if DEVICE_I2C +/* Define IP version */ #define I2C_IP_VERSION_V2 +// Common settings: I2C clock = 110 MHz, Analog filter = ON, Digital filter coefficient = 0 +#define TIMING_VAL_DEFAULT_CLK_100KHZ 0x40E15676 // Standard mode with Rise Time = 400ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_400KHZ 0x20C11434 // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_1MHZ 0x00C31536 // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns +#define I2C_PCLK_DEF 110000000 // 110 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 */ @@ -35,36 +42,14 @@ extern "C" { #define I2CAPI_I2C3_CLKSRC RCC_I2C3CLKSOURCE_SYSCLK #define I2CAPI_I2C4_CLKSRC RCC_I2C4CLKSOURCE_SYSCLK -/* Provide the suitable timing depending on requested frequencie */ -static inline uint32_t get_i2c_timing(int hz) -{ - uint32_t tim = 0; - if (SystemCoreClock == 110000000) { - // Common settings: I2C clock = 80 MHz, Analog filter = ON, Digital filter coefficient = 0 - switch (hz) { - case 100000: - tim = 0x40E15676; // Standard mode with Rise Time = 400ns and Fall Time = 100ns - break; - case 400000: - tim = 0x20C11434; // Fast mode with Rise Time = 250ns and Fall Time = 100ns - break; - case 1000000: - tim = 0x00C31536; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns - break; - default: - break; - } - } - else { - error("Value not provided for SystemCoreClock %u\n", SystemCoreClock); - } - return tim; -} +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); #ifdef __cplusplus } #endif - #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/TARGET_STM32WB/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32WB/CMakeLists.txt index c1a9d96996..7e54bfb73b 100644 --- a/targets/TARGET_STM/TARGET_STM32WB/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32WB/CMakeLists.txt @@ -12,6 +12,7 @@ target_sources(mbed-stm32wb analogin_device.c flash_api.c gpio_irq_device.c + i2c_device.c pwmout_device.c serial_device.c spi_api.c diff --git a/targets/TARGET_STM/TARGET_STM32WB/i2c_device.c b/targets/TARGET_STM/TARGET_STM32WB/i2c_device.c new file mode 100755 index 0000000000..0c234dcf6f --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32WB/i2c_device.c @@ -0,0 +1,151 @@ +/* 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 "stm32wbxx_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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + case RCC_I2C1CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C1CLKSOURCE_HSI: + pclk = HSI_VALUE; + break; + } + } +#if defined I2C2_BASE + if (i2c == I2C_2) { + clocksource = __HAL_RCC_GET_I2C2_SOURCE(); + switch (clocksource) { + case RCC_I2C2CLKSOURCE_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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; +} +/** + * @} + */ + +/** @defgroup I2C_DEVICE_Exported_Functions I2C_DEVICE Exported Functions + * @{ + */ +/** + * @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_64M) { + 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_32M) { + switch (hz) { + case 100000: + tim = TIMING_VAL_32M_CLK_100KHZ; + break; + case 400000: + tim = TIMING_VAL_32M_CLK_400KHZ; + break; + case 1000000: + tim = TIMING_VAL_32M_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 diff --git a/targets/TARGET_STM/TARGET_STM32WB/i2c_device.h b/targets/TARGET_STM/TARGET_STM32WB/i2c_device.h index 023f8ab9d5..53cdcff5ae 100644 --- a/targets/TARGET_STM/TARGET_STM32WB/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32WB/i2c_device.h @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2019 STMicroelectronics + * Copyright (c) 2019-2021 STMicroelectronics * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,16 +18,30 @@ #ifndef MBED_I2C_DEVICE_H #define MBED_I2C_DEVICE_H -#include "cmsis.h" +#include "PeripheralNames.h" #ifdef __cplusplus extern "C" { #endif -#ifdef DEVICE_I2C +/* Define I2C Device */ +#if DEVICE_I2C +/* Define IP version */ #define I2C_IP_VERSION_V2 +// Common settings: I2C clock = 64 MHz, Analog filter = ON, Digital filter coefficient = 0 +#define TIMING_VAL_64M_CLK_100KHZ 0x10707DBC // Standard mode with Rise Time = 400ns and Fall Time = 100ns +#define TIMING_VAL_64M_CLK_400KHZ 0x00602173 // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_64M_CLK_1MHZ 0x00300B29 // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns +#define I2C_PCLK_64M 64000000 // 64 MHz + +// Common settings: I2C clock = 32 MHz, Analog filter = ON, Digital filter coefficient = 0 +#define TIMING_VAL_32M_CLK_100KHZ 0x00707CBB // Standard mode with Rise Time = 400ns and Fall Time = 100ns +#define TIMING_VAL_32M_CLK_400KHZ 0x00300F38 // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_32M_CLK_1MHZ 0x00100413 // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns +#define I2C_PCLK_32M 32000000 // 32 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 specific settings for clock source */ @@ -35,48 +49,14 @@ extern "C" { #define I2CAPI_I2C2_CLKSRC RCC_I2C2CLKSOURCE_SYSCLK #define I2CAPI_I2C3_CLKSRC RCC_I2C3CLKSOURCE_SYSCLK -/* Provide the suitable timing depending on requested frequency */ -static inline uint32_t get_i2c_timing(int hz) -{ - uint32_t tim = 0; - if (SystemCoreClock == 64000000) { - // Common settings: I2C clock = 64 MHz, Analog filter = ON, Digital filter coefficient = 0 - switch (hz) { - case 100000: - tim = 0x10707DBC; // Standard mode with Rise Time = 400ns and Fall Time = 100ns - break; - case 400000: - tim = 0x00602173; // Fast mode with Rise Time = 250ns and Fall Time = 100ns - break; - case 1000000: - tim = 0x00300B29; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns - break; - default: - break; - } - } else if (SystemCoreClock == 32000000) { - // Common settings: I2C clock = 32 MHz, Analog filter = ON, Digital filter coefficient = 0 - switch (hz) { - case 100000: - tim = 0x00707CBB; // Standard mode with Rise Time = 400ns and Fall Time = 100ns - break; - case 400000: - tim = 0x00300F38; // Fast mode with Rise Time = 250ns and Fall Time = 100ns - break; - case 1000000: - tim = 0x00100413; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns - break; - default: - break; - } - } - return tim; -} +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); #ifdef __cplusplus } #endif - #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/TARGET_STM32WL/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32WL/CMakeLists.txt index 36c47064a1..1b8e784872 100644 --- a/targets/TARGET_STM/TARGET_STM32WL/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32WL/CMakeLists.txt @@ -12,6 +12,7 @@ target_sources(mbed-stm32wl analogout_device.c flash_api.c gpio_irq_device.c + i2c_device.c pwmout_device.c serial_device.c spi_api.c diff --git a/targets/TARGET_STM/TARGET_STM32WL/i2c_device.c b/targets/TARGET_STM/TARGET_STM32WL/i2c_device.c new file mode 100755 index 0000000000..bd18a50b6b --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32WL/i2c_device.c @@ -0,0 +1,136 @@ +/* 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 "stm32wlxx_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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + case RCC_I2C1CLKSOURCE_SYSCLK: + pclk = HAL_RCC_GetSysClockFreq(); + break; + + case RCC_I2C1CLKSOURCE_HSI: + pclk = HSI_VALUE; + break; + } + } +#if defined I2C2_BASE + if (i2c == I2C_2) { + clocksource = __HAL_RCC_GET_I2C2_SOURCE(); + switch (clocksource) { + case RCC_I2C2CLKSOURCE_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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_PCLK1: + pclk = HAL_RCC_GetPCLK1Freq(); + break; + + 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; +} +/** + * @} + */ + +/** @defgroup I2C_DEVICE_Exported_Functions I2C_DEVICE Exported Functions + * @{ + */ +/** + * @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 diff --git a/targets/TARGET_STM/TARGET_STM32WL/i2c_device.h b/targets/TARGET_STM/TARGET_STM32WL/i2c_device.h index eedf470733..ef7df02404 100644 --- a/targets/TARGET_STM/TARGET_STM32WL/i2c_device.h +++ b/targets/TARGET_STM/TARGET_STM32WL/i2c_device.h @@ -16,16 +16,24 @@ #ifndef MBED_I2C_DEVICE_H #define MBED_I2C_DEVICE_H -#include "cmsis.h" +#include "PeripheralNames.h" #ifdef __cplusplus extern "C" { #endif -#ifdef DEVICE_I2C +/* Define I2C Device */ +#if DEVICE_I2C +/* Define IP version */ #define I2C_IP_VERSION_V2 +// Common settings: I2C clock = 48 MHz, Analog filter = ON, Digital filter coefficient = 0 +#define TIMING_VAL_DEFAULT_CLK_100KHZ 0x20E03F53 // Standard mode with Rise Time = 640ns and Fall Time = 20ns +#define TIMING_VAL_DEFAULT_CLK_400KHZ 0x20500817 // Fast mode with Rise Time = 250ns and Fall Time = 100ns +#define TIMING_VAL_DEFAULT_CLK_1MHZ 0x00500A18 // 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 specific settings for clock source */ @@ -33,32 +41,14 @@ extern "C" { #define I2CAPI_I2C2_CLKSRC RCC_I2C2CLKSOURCE_SYSCLK #define I2CAPI_I2C3_CLKSRC RCC_I2C3CLKSOURCE_SYSCLK -/* Provide the suitable timing depending on requested frequency */ -static inline uint32_t get_i2c_timing(int hz) -{ - uint32_t tim = 0; - - // Common settings: I2C clock = 48 MHz, Analog filter = ON, Digital filter coefficient = 0 - switch (hz) { - case 100000: - tim = 0x20E03F53; // Standard mode with Rise Time = 640ns and Fall Time = 20ns - break; - case 400000: - tim = 0x20500817; // Fast mode with Rise Time = 250ns and Fall Time = 100ns - break; - case 1000000: - tim = 0x00500A18; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns - break; - default: - break; - } - return tim; -} +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); #ifdef __cplusplus } #endif - #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/i2c_api.c b/targets/TARGET_STM/i2c_api.c index 72c8c0bd96..824512c268 100644 --- a/targets/TARGET_STM/i2c_api.c +++ b/targets/TARGET_STM/i2c_api.c @@ -1,6 +1,6 @@ /* mbed Microcontroller Library ******************************************************************************* - * Copyright (c) 2015, STMicroelectronics + * Copyright (c) 2015-2021, STMicroelectronics * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,115 @@ #include "mbed_error.h" #include "platform/mbed_power_mgmt.h" +/** @defgroup I2C_DEVICE_Private_Constants I2C_DEVICE Private Constants + * @{ + */ +#ifndef I2C_VALID_TIMING_NBR +#define I2C_VALID_TIMING_NBR 128U +#endif +#define I2C_SPEED_FREQ_STANDARD 0U /* 100 kHz */ +#define I2C_SPEED_FREQ_FAST 1U /* 400 kHz */ +#define I2C_SPEED_FREQ_FAST_PLUS 2U /* 1 MHz */ +#define I2C_ANALOG_FILTER_DELAY_MIN 50U /* ns */ +#define I2C_ANALOG_FILTER_DELAY_MAX 260U /* ns */ +#define I2C_USE_ANALOG_FILTER 1U +#define I2C_DIGITAL_FILTER_COEF 0U +#define I2C_PRESC_MAX 16U +#define I2C_SCLDEL_MAX 16U +#define I2C_SDADEL_MAX 16U +#define I2C_SCLH_MAX 256U +#define I2C_SCLL_MAX 256U +#define SEC2NSEC 1000000000UL +/** + * @} + */ + + +/** @defgroup I2C_DEVICE_Private_Types I2C_DEVICE Private Types + * @{ + */ +typedef struct { + uint32_t freq; /* Frequency in Hz */ + uint32_t freq_min; /* Minimum frequency in Hz */ + uint32_t freq_max; /* Maximum frequency in Hz */ + uint32_t hddat_min; /* Minimum data hold time in ns */ + uint32_t vddat_max; /* Maximum data valid time in ns */ + uint32_t sudat_min; /* Minimum data setup time in ns */ + uint32_t lscl_min; /* Minimum low period of the SCL clock in ns */ + uint32_t hscl_min; /* Minimum high period of SCL clock in ns */ + uint32_t trise; /* Rise time in ns */ + uint32_t tfall; /* Fall time in ns */ + uint32_t dnf; /* Digital noise filter coefficient */ +} I2C_Charac_t; + +typedef struct { + uint32_t presc; /* Timing prescaler */ + uint32_t tscldel; /* SCL delay */ + uint32_t tsdadel; /* SDA delay */ + uint32_t sclh; /* SCL high period */ + uint32_t scll; /* SCL low period */ +} I2C_Timings_t; +/** + * @} + */ + +/** @defgroup I2C_DEVICE_Private_Constants I2C_DEVICE Private Constants + * @{ + */ +static const I2C_Charac_t I2C_Charac[] = { + [I2C_SPEED_FREQ_STANDARD] = + { + .freq = 100000, + .freq_min = 80000, + .freq_max = 120000, + .hddat_min = 0, + .vddat_max = 3450, + .sudat_min = 250, + .lscl_min = 4700, + .hscl_min = 4000, + .trise = 640, + .tfall = 20, + .dnf = I2C_DIGITAL_FILTER_COEF, + }, + [I2C_SPEED_FREQ_FAST] = + { + .freq = 400000, + .freq_min = 320000, + .freq_max = 480000, + .hddat_min = 0, + .vddat_max = 900, + .sudat_min = 100, + .lscl_min = 1300, + .hscl_min = 600, + .trise = 250, + .tfall = 100, + .dnf = I2C_DIGITAL_FILTER_COEF, + }, + [I2C_SPEED_FREQ_FAST_PLUS] = + { + .freq = 1000000, + .freq_min = 800000, + .freq_max = 1200000, + .hddat_min = 0, + .vddat_max = 450, + .sudat_min = 50, + .lscl_min = 500, + .hscl_min = 260, + .trise = 60, + .tfall = 100, + .dnf = I2C_DIGITAL_FILTER_COEF, + }, +}; +/** + * @} + */ + +/** @defgroup I2C_DEVICE_Private_Variables I2C_DEVICE Private Variables +* @{ +*/ +static I2C_Timings_t I2c_valid_timing[I2C_VALID_TIMING_NBR]; +static uint32_t I2c_valid_timing_nbr = 0; + #ifndef DEBUG_STDIO # define DEBUG_STDIO 0 #endif @@ -482,7 +591,8 @@ void i2c_frequency(i2c_t *obj, int hz) #ifdef I2C_IP_VERSION_V2 /* Only predefined timing for below frequencies are supported */ MBED_ASSERT((hz == 100000) || (hz == 400000) || (hz == 1000000)); - + /* Calculates I2C timing value with respect to I2C input clock and I2C bus frequency */ + handle->Init.Timing = i2c_get_timing(obj_s->i2c, hz); // Enable the Fast Mode Plus capability if (hz == 1000000) { #if defined(I2C1_BASE) && defined(I2C_FASTMODEPLUS_I2C1) // sometimes I2C_FASTMODEPLUS_I2Cx is define even if not supported by the chip @@ -550,14 +660,6 @@ void i2c_frequency(i2c_t *obj, int hz) HAL_I2CEx_ConfigAnalogFilter(handle, I2C_ANALOGFILTER_ENABLE); #endif -#ifdef I2C_IP_VERSION_V2 -#ifdef TARGET_STM32H7 - handle->Init.Timing = get_i2c_timing(obj_s->i2c, hz); -#else - handle->Init.Timing = get_i2c_timing(hz); -#endif -#endif - // I2C configuration handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; @@ -1399,6 +1501,184 @@ void i2c_abort_asynch(i2c_t *obj) HAL_I2C_Master_Abort_IT(handle, Dummy_DevAddress); } +/** + * @brief Calculate SCLL and SCLH and find best configuration. + * @param clock_src_freq I2C source clock in HZ. + * @param I2C_speed I2C frequency (index). + * @retval config index (0 to I2C_VALID_TIMING_NBR], 0xFFFFFFFF for no valid config. + */ +uint32_t i2c_compute_scll_sclh(uint32_t clock_src_freq, uint32_t I2C_speed) +{ + uint32_t ret = 0xFFFFFFFFU; + uint32_t ti2cclk; + uint32_t ti2cspeed; + uint32_t prev_error; + uint32_t dnf_delay; + uint32_t clk_min, clk_max; + uint32_t scll, sclh; + uint32_t tafdel_min; + + ti2cclk = (SEC2NSEC + (clock_src_freq / 2U)) / clock_src_freq; + ti2cspeed = (SEC2NSEC + (I2C_Charac[I2C_speed].freq / 2U)) / I2C_Charac[I2C_speed].freq; + + tafdel_min = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MIN : 0U; + + /* tDNF = DNF x tI2CCLK */ + dnf_delay = I2C_Charac[I2C_speed].dnf * ti2cclk; + + clk_max = SEC2NSEC / I2C_Charac[I2C_speed].freq_min; + clk_min = SEC2NSEC / I2C_Charac[I2C_speed].freq_max; + + prev_error = ti2cspeed; + + for (uint32_t count = 0; count < I2c_valid_timing_nbr; count++) { + /* tPRESC = (PRESC+1) x tI2CCLK*/ + uint32_t tpresc = (I2c_valid_timing[count].presc + 1U) * ti2cclk; + + for (scll = 0; scll < I2C_SCLL_MAX; scll++) { + /* tLOW(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLL+1) x tPRESC ] */ + uint32_t tscl_l = tafdel_min + dnf_delay + (2U * ti2cclk) + ((scll + 1U) * tpresc); + + + /* The I2CCLK period tI2CCLK must respect the following conditions: + tI2CCLK < (tLOW - tfilters) / 4 and tI2CCLK < tHIGH */ + if ((tscl_l > I2C_Charac[I2C_speed].lscl_min) && (ti2cclk < ((tscl_l - tafdel_min - dnf_delay) / 4U))) { + for (sclh = 0; sclh < I2C_SCLH_MAX; sclh++) { + /* tHIGH(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLH+1) x tPRESC] */ + uint32_t tscl_h = tafdel_min + dnf_delay + (2U * ti2cclk) + ((sclh + 1U) * tpresc); + + /* tSCL = tf + tLOW + tr + tHIGH */ + uint32_t tscl = tscl_l + tscl_h + I2C_Charac[I2C_speed].trise + I2C_Charac[I2C_speed].tfall; + + if ((tscl >= clk_min) && (tscl <= clk_max) && (tscl_h >= I2C_Charac[I2C_speed].hscl_min) && (ti2cclk < tscl_h)) { + int32_t error = (int32_t)tscl - (int32_t)ti2cspeed; + + if (error < 0) { + error = -error; + } + + /* look for the timings with the lowest clock error */ + if ((uint32_t)error < prev_error) { + prev_error = (uint32_t)error; + I2c_valid_timing[count].scll = scll; + I2c_valid_timing[count].sclh = sclh; + ret = count; + } + } + } + } + } + } + + return ret; +} + +/** + * @brief Compute PRESC, SCLDEL and SDADEL. + * @param clock_src_freq I2C source clock in HZ. + * @param I2C_speed I2C frequency (index). + * @retval None. + */ +void i2c_compute_presc_scldel_sdadel(uint32_t clock_src_freq, uint32_t I2C_speed) +{ + uint32_t prev_presc = I2C_PRESC_MAX; + uint32_t ti2cclk; + int32_t tsdadel_min, tsdadel_max; + int32_t tscldel_min; + uint32_t presc, scldel, sdadel; + uint32_t tafdel_min, tafdel_max; + + ti2cclk = (SEC2NSEC + (clock_src_freq / 2U)) / clock_src_freq; + + tafdel_min = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MIN : 0U; + tafdel_max = (I2C_USE_ANALOG_FILTER == 1U) ? I2C_ANALOG_FILTER_DELAY_MAX : 0U; + + /* tDNF = DNF x tI2CCLK + tPRESC = (PRESC+1) x tI2CCLK + SDADEL >= {tf +tHD;DAT(min) - tAF(min) - tDNF - [3 x tI2CCLK]} / {tPRESC} + SDADEL <= {tVD;DAT(max) - tr - tAF(max) - tDNF- [4 x tI2CCLK]} / {tPRESC} */ + + tsdadel_min = (int32_t)I2C_Charac[I2C_speed].tfall + (int32_t)I2C_Charac[I2C_speed].hddat_min - + (int32_t)tafdel_min - (int32_t)(((int32_t)I2C_Charac[I2C_speed].dnf + 3) * (int32_t)ti2cclk); + + tsdadel_max = (int32_t)I2C_Charac[I2C_speed].vddat_max - (int32_t)I2C_Charac[I2C_speed].trise - + (int32_t)tafdel_max - (int32_t)(((int32_t)I2C_Charac[I2C_speed].dnf + 4) * (int32_t)ti2cclk); + + + /* {[tr+ tSU;DAT(min)] / [tPRESC]} - 1 <= SCLDEL */ + tscldel_min = (int32_t)I2C_Charac[I2C_speed].trise + (int32_t)I2C_Charac[I2C_speed].sudat_min; + + if (tsdadel_min <= 0) { + tsdadel_min = 0; + } + + if (tsdadel_max <= 0) { + tsdadel_max = 0; + } + + for (presc = 0; presc < I2C_PRESC_MAX; presc++) { + for (scldel = 0; scldel < I2C_SCLDEL_MAX; scldel++) { + /* TSCLDEL = (SCLDEL+1) * (PRESC+1) * TI2CCLK */ + uint32_t tscldel = (scldel + 1U) * (presc + 1U) * ti2cclk; + + if (tscldel >= (uint32_t)tscldel_min) { + for (sdadel = 0; sdadel < I2C_SDADEL_MAX; sdadel++) { + /* TSDADEL = SDADEL * (PRESC+1) * TI2CCLK */ + uint32_t tsdadel = (sdadel * (presc + 1U)) * ti2cclk; + + if ((tsdadel >= (uint32_t)tsdadel_min) && (tsdadel <= (uint32_t)tsdadel_max)) { + if (presc != prev_presc) { + I2c_valid_timing[I2c_valid_timing_nbr].presc = presc; + I2c_valid_timing[I2c_valid_timing_nbr].tscldel = scldel; + I2c_valid_timing[I2c_valid_timing_nbr].tsdadel = sdadel; + prev_presc = presc; + I2c_valid_timing_nbr ++; + + if (I2c_valid_timing_nbr >= I2C_VALID_TIMING_NBR) { + return; + } + } + } + } + } + } + } +} + +/** + * @brief Compute I2C timing according current I2C clock source and required I2C clock. + * @param clock_src_freq I2C clock source in Hz. + * @param i2c_freq Required I2C clock in Hz. + * @retval I2C timing or 0 in case of error. + */ +uint32_t i2c_compute_timing(uint32_t clock_src_freq, uint32_t i2c_freq) +{ + uint32_t ret = 0; + uint32_t speed; + uint32_t idx; + + if ((clock_src_freq != 0U) && (i2c_freq != 0U)) { + for (speed = 0 ; speed <= (uint32_t)I2C_SPEED_FREQ_FAST_PLUS ; speed++) { + if ((i2c_freq >= I2C_Charac[speed].freq_min) && + (i2c_freq <= I2C_Charac[speed].freq_max)) { + i2c_compute_presc_scldel_sdadel(clock_src_freq, speed); + idx = i2c_compute_scll_sclh(clock_src_freq, speed); + + if (idx < I2C_VALID_TIMING_NBR) { + ret = ((I2c_valid_timing[idx].presc & 0x0FU) << 28) | \ + ((I2c_valid_timing[idx].tscldel & 0x0FU) << 20) | \ + ((I2c_valid_timing[idx].tsdadel & 0x0FU) << 16) | \ + ((I2c_valid_timing[idx].sclh & 0xFFU) << 8) | \ + ((I2c_valid_timing[idx].scll & 0xFFU) << 0); + } + break; + } + } + } + + return ret; +} + #endif // DEVICE_I2C_ASYNCH #endif // DEVICE_I2C