From d974b4743939c8ba62483842c35f720180cf5120 Mon Sep 17 00:00:00 2001 From: Affrin Pinhero Date: Mon, 19 Apr 2021 16:57:27 +0530 Subject: [PATCH] driver/i2c: Added I2C timing calculation function. This commit adds I2C timing value automatic calculation algorithm for all supported families added. This patch improves I2C timing calculation according to I2C input clock and I2C bus speed. This commit also allows user to change the system clock and I2C input clock. Related issue: #12907 Pull request type: [x] Patch update (Bug fix / Target update / Docs update / Test update / Refactor) [] Feature update (New feature / Functionality change / New API) [] Major update (Breaking change E.g. Return code change / API behaviour change) Test results: [] No Tests required for this change (E.g docs only update) [x] Covered by existing mbed-os tests (Greentea or Unittest) [] Tests / results supplied as part of this PR Signed-off-by: Affrin Pinhero --- .../TARGET_STM/TARGET_STM32F0/CMakeLists.txt | 1 + .../TARGET_STM/TARGET_STM32F0/i2c_device.c | 90 +++++ .../TARGET_STM/TARGET_STM32F0/i2c_device.h | 46 +-- .../TARGET_STM/TARGET_STM32F3/CMakeLists.txt | 1 + .../TARGET_STM/TARGET_STM32F3/i2c_device.c | 134 +++++++ .../TARGET_STM/TARGET_STM32F3/i2c_device.h | 72 ++-- .../TARGET_STM/TARGET_STM32F7/CMakeLists.txt | 1 + .../TARGET_STM/TARGET_STM32F7/i2c_device.c | 144 ++++++++ .../TARGET_STM/TARGET_STM32F7/i2c_device.h | 48 +-- .../TARGET_STM/TARGET_STM32G0/CMakeLists.txt | 1 + .../TARGET_STM/TARGET_STM32G0/i2c_device.c | 90 +++++ .../TARGET_STM/TARGET_STM32G0/i2c_device.h | 43 +-- .../TARGET_STM/TARGET_STM32G4/CMakeLists.txt | 1 + .../TARGET_STM/TARGET_STM32G4/i2c_device.c | 143 ++++++++ .../TARGET_STM/TARGET_STM32G4/i2c_device.h | 39 +- .../TARGET_STM/TARGET_STM32H7/i2c_device.c | 339 ++---------------- .../TARGET_STM/TARGET_STM32H7/i2c_device.h | 19 +- .../TARGET_STM/TARGET_STM32L0/CMakeLists.txt | 1 + .../TARGET_STM/TARGET_STM32L0/i2c_device.c | 114 ++++++ .../TARGET_STM/TARGET_STM32L0/i2c_device.h | 39 +- .../TARGET_STM/TARGET_STM32L4/CMakeLists.txt | 1 + .../TARGET_STM/TARGET_STM32L4/i2c_device.c | 179 +++++++++ .../TARGET_STM/TARGET_STM32L4/i2c_device.h | 86 ++--- .../TARGET_STM/TARGET_STM32L5/CMakeLists.txt | 1 + .../TARGET_STM/TARGET_STM32L5/i2c_device.c | 153 ++++++++ .../TARGET_STM/TARGET_STM32L5/i2c_device.h | 45 +-- .../TARGET_STM/TARGET_STM32WB/CMakeLists.txt | 1 + .../TARGET_STM/TARGET_STM32WB/i2c_device.c | 151 ++++++++ .../TARGET_STM/TARGET_STM32WB/i2c_device.h | 64 ++-- .../TARGET_STM/TARGET_STM32WL/CMakeLists.txt | 1 + .../TARGET_STM/TARGET_STM32WL/i2c_device.c | 136 +++++++ .../TARGET_STM/TARGET_STM32WL/i2c_device.h | 40 +-- targets/TARGET_STM/i2c_api.c | 300 +++++++++++++++- 33 files changed, 1856 insertions(+), 668 deletions(-) create mode 100755 targets/TARGET_STM/TARGET_STM32F0/i2c_device.c create mode 100755 targets/TARGET_STM/TARGET_STM32F3/i2c_device.c create mode 100755 targets/TARGET_STM/TARGET_STM32F7/i2c_device.c create mode 100755 targets/TARGET_STM/TARGET_STM32G0/i2c_device.c create mode 100755 targets/TARGET_STM/TARGET_STM32G4/i2c_device.c mode change 100644 => 100755 targets/TARGET_STM/TARGET_STM32H7/i2c_device.c create mode 100755 targets/TARGET_STM/TARGET_STM32L0/i2c_device.c create mode 100755 targets/TARGET_STM/TARGET_STM32L4/i2c_device.c create mode 100755 targets/TARGET_STM/TARGET_STM32L5/i2c_device.c create mode 100755 targets/TARGET_STM/TARGET_STM32WB/i2c_device.c create mode 100755 targets/TARGET_STM/TARGET_STM32WL/i2c_device.c diff --git a/targets/TARGET_STM/TARGET_STM32F0/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32F0/CMakeLists.txt index fb1ef562912..cf33302d077 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 00000000000..a14f653d463 --- /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 bda4eb7adb6..1fb9f83404c 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 #endif // DEVICE_I2C - #endif diff --git a/targets/TARGET_STM/TARGET_STM32F3/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32F3/CMakeLists.txt index b13377e017e..f1684b7fc6b 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 00000000000..3ac6dc1b18b --- /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 7ef29226aa0..7e19708eb33 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 a7e0becfd30..9cada3e83c6 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 00000000000..01d39d0a726 --- /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 3bfbc23c862..66f9717bed7 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 697a933c3ec..6fabba85b54 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 00000000000..f20aae22f86 --- /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 21d527549cb..4b189f7abc1 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 298030962af..a670385d2d5 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 00000000000..dfd06765f93 --- /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 35f5c320e11..dada0818332 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 b1a9e8b182d..889192c1578 --- 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 829290d9c6f..cc56874f269 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 fbeb9c20d8d..a9a2a6c5d37 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 00000000000..21df6a93a6c --- /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 175bde9f2d9..b5e50a17eb7 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 0642e934d0c..66644730318 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 00000000000..0db4d130007 --- /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 6368b4c53b1..9cd57129543 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 fe6e123defb..54a213bb2b8 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 00000000000..84fe773c67f --- /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 90ee70c22fa..c3d1a2797a1 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 c1a9d969969..7e54bfb73b8 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 00000000000..0c234dcf6f4 --- /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 023f8ab9d58..53cdcff5ae7 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 36c47064a19..1b8e7848726 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 00000000000..bd18a50b6bf --- /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 eedf4707333..ef7df02404e 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 72c8c0bd96b..824512c268c 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