From e41ac6ea711c86f3b029d3728c665a3712c3dca9 Mon Sep 17 00:00:00 2001 From: Brian Viele Date: Fri, 6 Mar 2020 00:57:21 -0500 Subject: [PATCH] stm32: added peripheral clock get helpers for all stm32 platforms. Allows for abstraction for code that's dependent on knowing the source clock for a peripheral. Implemented a few core peripherals that tend to have clock tree differences between platforms (USART, timers, I2C, SPI). --- .../libopencm3/stm32/common/rcc_common_all.h | 7 + include/libopencm3/stm32/f0/rcc.h | 14 ++ include/libopencm3/stm32/f1/rcc.h | 5 +- include/libopencm3/stm32/f2/rcc.h | 4 + include/libopencm3/stm32/f3/rcc.h | 7 + include/libopencm3/stm32/f4/rcc.h | 6 +- include/libopencm3/stm32/f7/rcc.h | 9 + include/libopencm3/stm32/g0/rcc.h | 10 +- include/libopencm3/stm32/h7/rcc.h | 34 +++- include/libopencm3/stm32/l0/rcc.h | 5 +- include/libopencm3/stm32/l1/rcc.h | 4 + include/libopencm3/stm32/l4/rcc.h | 4 + lib/stm32/common/rcc_common_all.c | 12 ++ lib/stm32/f0/rcc.c | 68 +++++++ lib/stm32/f1/rcc.c | 40 ++++ lib/stm32/f2/rcc.c | 52 ++++++ lib/stm32/f3/rcc.c | 82 ++++++++ lib/stm32/f4/rcc.c | 52 ++++++ lib/stm32/f7/rcc.c | 87 +++++++++ lib/stm32/g0/rcc.c | 65 ++++++- lib/stm32/h7/rcc.c | 176 ++++++++++-------- lib/stm32/l0/rcc.c | 77 ++++++++ lib/stm32/l1/rcc.c | 52 ++++++ lib/stm32/l4/rcc.c | 82 ++++++++ 24 files changed, 860 insertions(+), 94 deletions(-) diff --git a/include/libopencm3/stm32/common/rcc_common_all.h b/include/libopencm3/stm32/common/rcc_common_all.h index 49837137..2db980ff 100644 --- a/include/libopencm3/stm32/common/rcc_common_all.h +++ b/include/libopencm3/stm32/common/rcc_common_all.h @@ -67,6 +67,13 @@ bool rcc_is_osc_ready(enum rcc_osc osc); */ void rcc_wait_for_osc_ready(enum rcc_osc osc); +/** + * This will return the divisor 1/2/4/8/16/64/128/256/512 which is set as a + * 4-bit value, typically used for hpre and other prescalers. + * @param div_val Masked and shifted divider value from register (e.g. RCC_CFGR) + */ +uint16_t rcc_get_div_from_hpre(uint8_t div_val); + END_DECLS /**@}*/ diff --git a/include/libopencm3/stm32/f0/rcc.h b/include/libopencm3/stm32/f0/rcc.h index 3bd4f58f..e0663eb5 100644 --- a/include/libopencm3/stm32/f0/rcc.h +++ b/include/libopencm3/stm32/f0/rcc.h @@ -149,6 +149,7 @@ Control #define RCC_CFGR_PPRE_SHIFT 8 #define RCC_CFGR_PPRE (7 << RCC_CFGR_PPRE_SHIFT) +#define RCC_CFGR_PPRE_MASK 0x7 /** @defgroup rcc_cfgr_apb1pre RCC_CFGR APB prescale Factors @{*/ #define RCC_CFGR_PPRE_NODIV (0 << RCC_CFGR_PPRE_SHIFT) @@ -160,6 +161,7 @@ Control #define RCC_CFGR_HPRE_SHIFT 4 #define RCC_CFGR_HPRE (0xf << RCC_CFGR_HPRE_SHIFT) +#define RCC_CFGR_HPRE_MASK 0xf /** @defgroup rcc_cfgr_ahbpre RCC_CFGR AHB prescale Factors @{*/ #define RCC_CFGR_HPRE_NODIV (0x0 << RCC_CFGR_HPRE_SHIFT) @@ -383,6 +385,12 @@ Control /**@}*/ /* --- RCC_CFGR3 values ---------------------------------------------------- */ +#define RCC_CFGR3_USART3SW_SHIFT 18 +#define RCC_CFGR3_USART3SW (3 << RCC_CFGR3_USART2SW_SHIFT) +#define RCC_CFGR3_USART3SW_PCLK (0 << RCC_CFGR3_USART2SW_SHIFT) +#define RCC_CFGR3_USART3SW_SYSCLK (1 << RCC_CFGR3_USART2SW_SHIFT) +#define RCC_CFGR3_USART3SW_LSE (2 << RCC_CFGR3_USART2SW_SHIFT) +#define RCC_CFGR3_USART3SW_HSI (3 << RCC_CFGR3_USART2SW_SHIFT) #define RCC_CFGR3_USART2SW_SHIFT 16 #define RCC_CFGR3_USART2SW (3 << RCC_CFGR3_USART2SW_SHIFT) @@ -403,6 +411,8 @@ Control #define RCC_CFGR3_USART1SW_LSE (2 << RCC_CFGR3_USART1SW_SHIFT) #define RCC_CFGR3_USART1SW_HSI (3 << RCC_CFGR3_USART1SW_SHIFT) +#define RCC_CFGR3_USARTxSW_MASK 3 + /* --- RCC_CFGR3 values ---------------------------------------------------- */ #define RCC_CR2_HSI48CAL_SHIFT 24 @@ -579,6 +589,10 @@ enum rcc_osc rcc_usb_clock_source(void); void rcc_clock_setup_in_hse_8mhz_out_48mhz(void); void rcc_clock_setup_in_hsi_out_48mhz(void); void rcc_clock_setup_in_hsi48_out_48mhz(void); +uint32_t rcc_get_usart_clk_freq(uint32_t usart); +uint32_t rcc_get_timer_clk_freq(uint32_t timer); +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); +uint32_t rcc_get_spi_clk_freq(uint32_t spi); END_DECLS diff --git a/include/libopencm3/stm32/f1/rcc.h b/include/libopencm3/stm32/f1/rcc.h index f497d110..55cd54b0 100644 --- a/include/libopencm3/stm32/f1/rcc.h +++ b/include/libopencm3/stm32/f1/rcc.h @@ -790,7 +790,10 @@ void rcc_clock_setup_in_hse_25mhz_out_72mhz(void) LIBOPENCM3_DEPRECATED("use rcc */ void rcc_clock_setup_pll(const struct rcc_clock_scale *clock); void rcc_backupdomain_reset(void); - +uint32_t rcc_get_usart_clk_freq(uint32_t usart); +uint32_t rcc_get_timer_clk_freq(uint32_t timer); +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); +uint32_t rcc_get_spi_clk_freq(uint32_t spi); END_DECLS #endif diff --git a/include/libopencm3/stm32/f2/rcc.h b/include/libopencm3/stm32/f2/rcc.h index 1831feb0..d758d318 100644 --- a/include/libopencm3/stm32/f2/rcc.h +++ b/include/libopencm3/stm32/f2/rcc.h @@ -850,6 +850,10 @@ void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp, uint32_t rcc_system_clock_source(void); void rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock); void rcc_backupdomain_reset(void); +uint32_t rcc_get_usart_clk_freq(uint32_t usart); +uint32_t rcc_get_timer_clk_freq(uint32_t timer); +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); +uint32_t rcc_get_spi_clk_freq(uint32_t spi); END_DECLS diff --git a/include/libopencm3/stm32/f3/rcc.h b/include/libopencm3/stm32/f3/rcc.h index fd6fe286..f77df32e 100644 --- a/include/libopencm3/stm32/f3/rcc.h +++ b/include/libopencm3/stm32/f3/rcc.h @@ -436,6 +436,9 @@ #define RCC_CFGR3_UART1SW_LSE 0x2 #define RCC_CFGR3_UART1SW_HSI 0x3 +/* Shared mask for UART clock source. */ +#define RCC_CFGR3_UARTxSW_MASK 0x3 + /* --- Variable definitions ------------------------------------------------ */ extern uint32_t rcc_ahb_frequency; @@ -655,6 +658,10 @@ uint32_t rcc_get_i2c_clocks(void); void rcc_usb_prescale_1_5(void); void rcc_usb_prescale_1(void); void rcc_adc_prescale(uint32_t prescale1, uint32_t prescale2); +uint32_t rcc_get_usart_clk_freq(uint32_t usart); +uint32_t rcc_get_timer_clk_freq(uint32_t timer); +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); +uint32_t rcc_get_spi_clk_freq(uint32_t spi); END_DECLS diff --git a/include/libopencm3/stm32/f4/rcc.h b/include/libopencm3/stm32/f4/rcc.h index e957b06c..31cce195 100644 --- a/include/libopencm3/stm32/f4/rcc.h +++ b/include/libopencm3/stm32/f4/rcc.h @@ -1127,8 +1127,12 @@ void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp, uint32_t rcc_system_clock_source(void); void rcc_clock_setup_pll(const struct rcc_clock_scale *clock); void __attribute__((deprecated("Use rcc_clock_setup_pll as direct replacement"))) rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock); +uint32_t rcc_get_usart_clk_freq(uint32_t usart); +uint32_t rcc_get_timer_clk_freq(uint32_t timer); +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); +uint32_t rcc_get_spi_clk_freq(uint32_t spi); END_DECLS #endif -/**@}*/ \ No newline at end of file +/**@}*/ diff --git a/include/libopencm3/stm32/f7/rcc.h b/include/libopencm3/stm32/f7/rcc.h index bace1c3a..2f3bcc73 100644 --- a/include/libopencm3/stm32/f7/rcc.h +++ b/include/libopencm3/stm32/f7/rcc.h @@ -646,6 +646,10 @@ #define RCC_DCKCFGR2_UART2SEL_SHIFT 2 #define RCC_DCKCFGR2_UART1SEL_MASK 0x3 #define RCC_DCKCFGR2_UART1SEL_SHIFT 0 +#define RCC_DCKCFGR2_UARTxSEL_PCLK 0 +#define RCC_DCKCFGR2_UARTxSEL_SYSCLK 1 +#define RCC_DCKCFGR2_UARTxSEL_HSI 2 + extern uint32_t rcc_ahb_frequency; extern uint32_t rcc_apb1_frequency; @@ -986,6 +990,11 @@ void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp, uint32_t rcc_system_clock_source(void); void rcc_clock_setup_hse(const struct rcc_clock_scale *clock, uint32_t hse_mhz); void rcc_clock_setup_hsi(const struct rcc_clock_scale *clock); +uint32_t rcc_get_usart_clk_freq(uint32_t usart); +uint32_t rcc_get_timer_clk_freq(uint32_t timer); +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); +uint32_t rcc_get_spi_clk_freq(uint32_t spi); + END_DECLS /**@}*/ diff --git a/include/libopencm3/stm32/g0/rcc.h b/include/libopencm3/stm32/g0/rcc.h index 77409f7f..dd3d4acf 100644 --- a/include/libopencm3/stm32/g0/rcc.h +++ b/include/libopencm3/stm32/g0/rcc.h @@ -251,7 +251,7 @@ #define RCC_PLLCFGR_PLLM_SHIFT 0x4 #define RCC_PLLCFGR_PLLM_MASK 0x7 /** @defgroup rcc_pllcfgr_pllm PLLM - * @brief Division factor M [1..8] for PLL input clock. Input frequency must be between 4mhz and 16mhz. + * @brief Division factor M [1..8] for PLL input clock. Input frequency must be between 4mhz and 16mhz. @{*/ #define RCC_PLLCFGR_PLLM_DIV(x) ((x)-1) /**@}*/ @@ -629,7 +629,7 @@ extern uint32_t rcc_apb1_frequency; #define rcc_apb2_frequency rcc_apb1_frequency /* --- Function prototypes ------------------------------------------------- */ - + #define _REG_BIT(offset, bit) (((offset) << 5) + (bit)) enum rcc_osc { @@ -778,7 +778,7 @@ enum rcc_periph_rst { struct rcc_clock_scale { enum rcc_osc sysclock_source; - + /* PLL as sysclock source cfg */ uint8_t pll_source; uint8_t pll_div; @@ -841,6 +841,10 @@ void rcc_clock_setup(const struct rcc_clock_scale *clock); void rcc_set_rng_clk_div(uint32_t rng_div); void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t sel); +uint32_t rcc_get_usart_clk_freq(uint32_t usart); +uint32_t rcc_get_timer_clk_freq(uint32_t timer); +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); +uint32_t rcc_get_spi_clk_freq(uint32_t spi); END_DECLS diff --git a/include/libopencm3/stm32/h7/rcc.h b/include/libopencm3/stm32/h7/rcc.h index 8593d076..ebef3935 100644 --- a/include/libopencm3/stm32/h7/rcc.h +++ b/include/libopencm3/stm32/h7/rcc.h @@ -409,6 +409,7 @@ LGPL License Terms @ref lgpl_license #define RCC_D2CCIP2R_RNGSEL_LSI 3 #define RCC_D2CCIP2R_USART16SEL_PCLK2 0 #define RCC_D2CCIP2R_USART234578SEL_PCLK1 0 +#define RCC_D2CCIP2R_USARTSEL_PCLK 0 #define RCC_D2CCIP2R_USARTSEL_PLL2Q 1 #define RCC_D2CCIP2R_USARTSEL_PLL3Q 2 #define RCC_D2CCIP2R_USARTSEL_HSI 3 @@ -732,13 +733,34 @@ void rcc_clock_setup_pll(const struct rcc_pll_config *config); uint32_t rcc_get_bus_clk_freq(enum rcc_clock_source source); /** - * Get the clock rate (in Hz) of the specified peripheral. This will pull the - * proper sources out of the clock tree and calculate the clock for the - * peripheral for return to the user, based on current settings. - * @param[in] periph Peripheral base address to get the clock rate for. - * @return Clock rate in Hz for the specified peripheral. 0 if undefined or error. + * Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for (e.g. USART1_BASE). */ -uint32_t rcc_get_peripheral_clk_freq(uint32_t periph); +uint32_t rcc_get_usart_clk_freq(uint32_t usart); + +/** + * Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIMER to get clock frequency for (e.g. TIM1_BASE). + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer); + +/** + * Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for (e.g. I2C1_BASE). + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); + +/** + * Get the peripheral clock speed for the SPI device at base specified. + * @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE). + */ +uint32_t rcc_get_spi_clk_freq(uint32_t spi); + +/** + * Get the peripheral clock speed for the FDCAN device at base specified. + * @param fdcan Base address of FDCAN to get clock frequency for (e.g. FDCAN1_BASE). + */ +uint32_t rcc_get_fdcan_clk_freq(uint32_t fdcan); /** * Set the clksel value for the specified peripheral. This code will determine diff --git a/include/libopencm3/stm32/l0/rcc.h b/include/libopencm3/stm32/l0/rcc.h index 287f6b99..6aa9d4b4 100644 --- a/include/libopencm3/stm32/l0/rcc.h +++ b/include/libopencm3/stm32/l0/rcc.h @@ -709,11 +709,14 @@ void rcc_clock_setup_pll(const struct rcc_clock_scale *clock); void rcc_set_msi_range(uint32_t msi_range); void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t sel); - void rcc_set_lptim1_sel(uint32_t lptim1_sel); void rcc_set_lpuart1_sel(uint32_t lpupart1_sel); void rcc_set_usart1_sel(uint32_t usart1_sel); void rcc_set_usart2_sel(uint32_t usart2_sel); +uint32_t rcc_get_usart_clk_freq(uint32_t usart); +uint32_t rcc_get_timer_clk_freq(uint32_t timer); +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); +uint32_t rcc_get_spi_clk_freq(uint32_t spi); END_DECLS diff --git a/include/libopencm3/stm32/l1/rcc.h b/include/libopencm3/stm32/l1/rcc.h index cf8a7197..220d1f88 100644 --- a/include/libopencm3/stm32/l1/rcc.h +++ b/include/libopencm3/stm32/l1/rcc.h @@ -660,6 +660,10 @@ void rcc_clock_setup_msi(const struct rcc_clock_scale *clock); void rcc_clock_setup_hsi(const struct rcc_clock_scale *clock); void rcc_clock_setup_pll(const struct rcc_clock_scale *clock); void rcc_backupdomain_reset(void); +uint32_t rcc_get_usart_clk_freq(uint32_t usart); +uint32_t rcc_get_timer_clk_freq(uint32_t timer); +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); +uint32_t rcc_get_spi_clk_freq(uint32_t spi); END_DECLS diff --git a/include/libopencm3/stm32/l4/rcc.h b/include/libopencm3/stm32/l4/rcc.h index 09b9d9bf..24f9b391 100644 --- a/include/libopencm3/stm32/l4/rcc.h +++ b/include/libopencm3/stm32/l4/rcc.h @@ -987,6 +987,10 @@ void rcc_set_clock48_source(uint32_t clksel); void rcc_enable_rtc_clock(void); void rcc_disable_rtc_clock(void); void rcc_set_rtc_clock_source(enum rcc_osc clk); +uint32_t rcc_get_usart_clk_freq(uint32_t usart); +uint32_t rcc_get_timer_clk_freq(uint32_t timer); +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c); +uint32_t rcc_get_spi_clk_freq(uint32_t spi); END_DECLS diff --git a/lib/stm32/common/rcc_common_all.c b/lib/stm32/common/rcc_common_all.c index e5068114..4cbe0a81 100644 --- a/lib/stm32/common/rcc_common_all.c +++ b/lib/stm32/common/rcc_common_all.c @@ -270,6 +270,18 @@ void rcc_osc_bypass_disable(enum rcc_osc osc) } } +/* This is a helper to calculate dividers that go 2/4/8/16/64/128/256/512. + * These dividers also use the top bit as an "enable". This is tyipcally + * used for AHB and other system clock prescaler. */ +uint16_t rcc_get_div_from_hpre(uint8_t div_val) { + if (div_val < 0x8) { + return 1; + } else if (div_val <= 0x0b /* DIV16 */) { + return (1U << (div_val - 7)); + } else { + return (1U << (div_val - 6)); + } +} /**@}*/ #undef _RCC_REG diff --git a/lib/stm32/f0/rcc.c b/lib/stm32/f0/rcc.c index 182bdd28..5a679124 100644 --- a/lib/stm32/f0/rcc.c +++ b/lib/stm32/f0/rcc.c @@ -625,5 +625,73 @@ void rcc_clock_setup_in_hsi48_out_48mhz(void) rcc_apb1_frequency = 48000000; rcc_ahb_frequency = 48000000; } + +static uint32_t rcc_get_usart_clksel_freq(uint8_t shift) { + uint8_t clksel = (RCC_CFGR3 >> shift) & RCC_CFGR3_USARTxSW_MASK; + uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK; + switch (clksel) { + case RCC_CFGR3_USART1SW_PCLK: + return rcc_apb1_frequency; + case RCC_CFGR3_USART1SW_SYSCLK: + return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre); + case RCC_CFGR3_USART1SW_HSI: + return 8000000U; + } + cm3_assert_not_reached(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for. + */ +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + if (usart == USART1_BASE) { + return rcc_get_usart_clksel_freq(RCC_CFGR3_USART1SW_SHIFT); + } else if (usart == USART2_BASE) { + return rcc_get_usart_clksel_freq(RCC_CFGR3_USART2SW_SHIFT); + } else if (usart == USART3_BASE) { + return rcc_get_usart_clksel_freq(RCC_CFGR3_USART3SW_SHIFT); + } else { + return rcc_apb1_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIM to get clock frequency for. + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer __attribute__((unused))) +{ + uint8_t ppre = (RCC_CFGR >> RCC_CFGR_PPRE_SHIFT) & RCC_CFGR_PPRE_MASK; + return (ppre == RCC_CFGR_PPRE_NODIV) ? rcc_apb1_frequency + : 2 * rcc_apb1_frequency; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for. + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c) +{ + if (i2c == I2C1_BASE) { + if (RCC_CFGR3 & RCC_CFGR3_I2C1SW) { + uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK; + return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre); + } else { + return 8000000U; + } + } else { + return rcc_apb1_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the SPI device at base specified. + * @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE). + */ +uint32_t rcc_get_spi_clk_freq(uint32_t spi __attribute__((unused))) { + return rcc_apb1_frequency; +} /**@}*/ diff --git a/lib/stm32/f1/rcc.c b/lib/stm32/f1/rcc.c index 78c4f840..ba64d604 100644 --- a/lib/stm32/f1/rcc.c +++ b/lib/stm32/f1/rcc.c @@ -1289,5 +1289,45 @@ void rcc_backupdomain_reset(void) RCC_BDCR &= ~RCC_BDCR_BDRST; } +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for. + */ +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + if (usart == USART1_BASE) { + return rcc_apb2_frequency; + } else { + return rcc_apb1_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIM to get clock frequency for. + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer) +{ + /* Handle APB1 timer clocks. */ + if (timer >= TIM2_BASE && timer <= TIM14_BASE) { + uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK; + return (ppre1 == RCC_CFGR_PPRE1_HCLK_NODIV) ? rcc_apb1_frequency + : 2 * rcc_apb1_frequency; + } else { + uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK; + return (ppre2 == RCC_CFGR_PPRE2_HCLK_NODIV) ? rcc_apb2_frequency + : 2 * rcc_apb2_frequency; + } + cm3_assert_not_reached(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for. + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c __attribute__((unused))) +{ + return rcc_apb1_frequency; +} /**@}*/ diff --git a/lib/stm32/f2/rcc.c b/lib/stm32/f2/rcc.c index 80db1935..12567874 100644 --- a/lib/stm32/f2/rcc.c +++ b/lib/stm32/f2/rcc.c @@ -389,4 +389,56 @@ void rcc_backupdomain_reset(void) RCC_BDCR &= ~RCC_BDCR_BDRST; } + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for. + */ +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + if (usart == USART1_BASE || usart == USART6_BASE) { + return rcc_apb2_frequency; + } else { + return rcc_apb1_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIM to get clock frequency for. + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer) +{ + /* Handle APB1 timer clocks. */ + if (timer >= TIM2_BASE && timer <= TIM14_BASE) { + uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK; + return (ppre1 == RCC_CFGR_PPRE_DIV_NONE) ? rcc_apb1_frequency + : 2 * rcc_apb1_frequency; + } else { + uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK; + return (ppre2 == RCC_CFGR_PPRE_DIV_NONE) ? rcc_apb2_frequency + : 2 * rcc_apb2_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for. + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c __attribute__((unused))) +{ + return rcc_apb1_frequency; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the SPI device at base specified. + * @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE). + */ +uint32_t rcc_get_spi_clk_freq(uint32_t spi) { + if (spi == SPI1_BASE) { + return rcc_apb2_frequency; + } else { + return rcc_apb1_frequency; + } +} /**@}*/ diff --git a/lib/stm32/f3/rcc.c b/lib/stm32/f3/rcc.c index 9d5fc6d5..831ce263 100644 --- a/lib/stm32/f3/rcc.c +++ b/lib/stm32/f3/rcc.c @@ -493,5 +493,87 @@ void rcc_adc_prescale(uint32_t prescale1, uint32_t prescale2) RCC_CFGR2 &= ~(clear_mask); RCC_CFGR2 |= (set); } + +static uint32_t rcc_get_usart_clksel_freq(uint32_t apb_clk, uint8_t shift) { + uint8_t clksel = (RCC_CFGR3 >> shift) & RCC_CFGR3_UARTxSW_MASK; + uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK; + switch (clksel) { + case RCC_CFGR3_UART1SW_PCLK: + return apb_clk; + case RCC_CFGR3_UART1SW_SYSCLK: + return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre); + case RCC_CFGR3_UART1SW_HSI: + return 8000000U; + } + cm3_assert_not_reached(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for. + */ +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + /* Handle values with selectable clocks. */ + if (usart == USART1_BASE) { + return rcc_get_usart_clksel_freq(rcc_apb2_frequency, RCC_CFGR3_UART1SW_SHIFT); + } else if (usart == USART2_BASE) { + return rcc_get_usart_clksel_freq(rcc_apb1_frequency, RCC_CFGR3_UART2SW_SHIFT); + } else if (usart == USART3_BASE) { + return rcc_get_usart_clksel_freq(rcc_apb1_frequency, RCC_CFGR3_UART3SW_SHIFT); + } else if (usart == UART4_BASE) { + return rcc_get_usart_clksel_freq(rcc_apb1_frequency, RCC_CFGR3_UART4SW_SHIFT); + } else { /* UART5 */ + return rcc_get_usart_clksel_freq(rcc_apb1_frequency, RCC_CFGR3_UART5SW_SHIFT); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIM to get clock frequency for. + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer) +{ + /* Handle APB1 timer clocks. */ + if (timer >= TIM2_BASE && timer <= TIM7_BASE) { + uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK; + return (ppre1 == RCC_CFGR_PPRE1_DIV_NONE) ? rcc_apb1_frequency + : 2 * rcc_apb1_frequency; + } else { + uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK; + return (ppre2 == RCC_CFGR_PPRE2_DIV_NONE) ? rcc_apb2_frequency + : 2 * rcc_apb2_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for. + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c) +{ + if (i2c == I2C1_BASE) { + if (RCC_CFGR3 & RCC_CFGR3_I2C1SW) { + uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK; + return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre); + } else { + return 8000000U; + } + } else { + return rcc_apb1_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the SPI device at base specified. + * @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE). + */ +uint32_t rcc_get_spi_clk_freq(uint32_t spi) { + if (spi == SPI1_BASE || spi == SPI4_BASE) { + return rcc_apb2_frequency; + } else { + return rcc_apb1_frequency; + } +} /**@}*/ diff --git a/lib/stm32/f4/rcc.c b/lib/stm32/f4/rcc.c index ba3f2469..6b4da4ac 100644 --- a/lib/stm32/f4/rcc.c +++ b/lib/stm32/f4/rcc.c @@ -791,4 +791,56 @@ void rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock) rcc_clock_setup_pll(clock); } +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for. + */ +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + /* Handle values with selectable clocks. */ + if (usart == USART1_BASE || usart == USART6_BASE) { + return rcc_apb2_frequency; + } else { + return rcc_apb1_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIM to get clock frequency for. + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer) +{ + /* Handle APB1 timer clocks. */ + if (timer >= TIM2_BASE && timer <= TIM14_BASE) { + uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK; + return (ppre1 == RCC_CFGR_PPRE_DIV_NONE) ? rcc_apb1_frequency + : 2 * rcc_apb1_frequency; + } else { + uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK; + return (ppre2 == RCC_CFGR_PPRE_DIV_NONE) ? rcc_apb2_frequency + : 2 * rcc_apb2_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for. + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c __attribute__((unused))) +{ + return rcc_apb1_frequency; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the SPI device at base specified. + * @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE). + */ +uint32_t rcc_get_spi_clk_freq(uint32_t spi) { + if (spi == SPI2_BASE || spi == SPI3_BASE) { + return rcc_apb1_frequency; + } else { + return rcc_apb2_frequency; + } +} /**@}*/ diff --git a/lib/stm32/f7/rcc.c b/lib/stm32/f7/rcc.c index 4246036a..99a697d4 100644 --- a/lib/stm32/f7/rcc.c +++ b/lib/stm32/f7/rcc.c @@ -484,4 +484,91 @@ void rcc_clock_setup_hsi(const struct rcc_clock_scale *clock) rcc_apb2_frequency = clock->apb2_frequency; } +static uint32_t rcc_usart_i2c_clksel_freq(uint32_t apb_clk, uint8_t shift) { + uint8_t clksel = (RCC_DCKCFGR2 >> shift) & RCC_DCKCFGR2_UART1SEL_MASK; + uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK; + switch (clksel) { + case RCC_DCKCFGR2_UARTxSEL_PCLK: + return apb_clk; + case RCC_DCKCFGR2_UARTxSEL_SYSCLK: + return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre); + case RCC_DCKCFGR2_UARTxSEL_HSI: + return 16000000U; + default: + cm3_assert_not_reached(); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for. + */ +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + /* F7 is highly configurable, every USART can be configured in DCKCFGR2. */ + if (usart == USART1_BASE) { + return rcc_usart_i2c_clksel_freq(rcc_apb2_frequency, RCC_DCKCFGR2_UART1SEL_SHIFT); + } else if (usart == USART2_BASE) { + return rcc_usart_i2c_clksel_freq(rcc_apb1_frequency, RCC_DCKCFGR2_UART2SEL_SHIFT); + } else if (usart == USART3_BASE) { + return rcc_usart_i2c_clksel_freq(rcc_apb1_frequency, RCC_DCKCFGR2_UART3SEL_SHIFT); + } else if (usart == UART4_BASE) { + return rcc_usart_i2c_clksel_freq(rcc_apb1_frequency, RCC_DCKCFGR2_UART4SEL_SHIFT); + } else if (usart == UART5_BASE) { + return rcc_usart_i2c_clksel_freq(rcc_apb1_frequency, RCC_DCKCFGR2_UART5SEL_SHIFT); + } else if (usart == USART6_BASE) { + return rcc_usart_i2c_clksel_freq(rcc_apb2_frequency, RCC_DCKCFGR2_USART6SEL_SHIFT); + } else if (usart == UART7_BASE) { + return rcc_usart_i2c_clksel_freq(rcc_apb1_frequency, RCC_DCKCFGR2_UART7SEL_SHIFT); + } else { /* UART8 */ + return rcc_usart_i2c_clksel_freq(rcc_apb1_frequency, RCC_DCKCFGR2_UART8SEL_SHIFT); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIM to get clock frequency for. + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer) +{ + /* Handle APB1 timer clocks. */ + if (timer >= TIM2_BASE && timer <= TIM14_BASE) { + uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK; + return (ppre1 == RCC_CFGR_PPRE_DIV_NONE) ? rcc_apb1_frequency + : 2 * rcc_apb1_frequency; + } else { + uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK; + return (ppre2 == RCC_CFGR_PPRE_DIV_NONE) ? rcc_apb2_frequency + : 2 * rcc_apb2_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for. + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c __attribute__((unused))) +{ + if (i2c == I2C1_BASE) { + return rcc_usart_i2c_clksel_freq(rcc_apb1_frequency, RCC_DCKCFGR2_I2C1SEL_SHIFT); + } else if (i2c == I2C2_BASE) { + return rcc_usart_i2c_clksel_freq(rcc_apb1_frequency, RCC_DCKCFGR2_I2C2SEL_SHIFT); + } else if (i2c == I2C3_BASE) { + return rcc_usart_i2c_clksel_freq(rcc_apb1_frequency, RCC_DCKCFGR2_I2C3SEL_SHIFT); + } else { /* I2C4 */ + return rcc_usart_i2c_clksel_freq(rcc_apb1_frequency, RCC_DCKCFGR2_I2C4SEL_SHIFT); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the SPI device at base specified. + * @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE). + */ +uint32_t rcc_get_spi_clk_freq(uint32_t spi) { + if (spi == SPI2_BASE || spi == SPI3_BASE) { + return rcc_apb1_frequency; + } else { + return rcc_apb2_frequency; + } +} /**@}*/ diff --git a/lib/stm32/g0/rcc.c b/lib/stm32/g0/rcc.c index c3f157ab..9e05bb93 100644 --- a/lib/stm32/g0/rcc.c +++ b/lib/stm32/g0/rcc.c @@ -437,7 +437,7 @@ void rcc_set_mcopre(uint32_t mcopre) * @param clock rcc_clock_scale with desired parameters */ void rcc_clock_setup(const struct rcc_clock_scale *clock) -{ +{ if (clock->sysclock_source == RCC_PLL) { enum rcc_osc pll_source; @@ -547,4 +547,67 @@ void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t sel) RCC_CCIPR = reg32 | (sel << shift); } +static uint32_t rcc_get_clksel_freq(uint8_t shift) { + uint8_t clksel = (RCC_CCIPR >> shift) & RCC_CCIPR_USART1SEL_MASK; + uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK; + switch (clksel) { + case RCC_CCIPR_USART1SEL_PCLK: + return rcc_apb1_frequency; + case RCC_CCIPR_USART1SEL_SYSCLK: + return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre); + case RCC_CCIPR_USART1SEL_HSI16: + return 16000000U; + } + cm3_assert_not_reached(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for. + */ +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + if (usart == USART1_BASE) { + return rcc_get_clksel_freq(RCC_CCIPR_USART1SEL_SHIFT); + } else if (usart == USART2_BASE) { + return rcc_get_clksel_freq(RCC_CCIPR_USART2SEL_SHIFT); + } else if (usart == LPUART1_BASE) { + return rcc_get_clksel_freq(RCC_CCIPR_LPUART1SEL_SHIFT); + } else { + return rcc_apb1_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIM to get clock frequency for. + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer __attribute__((unused))) +{ + uint8_t ppre = (RCC_CFGR >> RCC_CFGR_PPRE_SHIFT) & RCC_CFGR_PPRE_MASK; + return (ppre == RCC_CFGR_PPRE_NODIV) ? rcc_apb1_frequency + : 2 * rcc_apb1_frequency; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for. + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c __attribute__((unused))) +{ + if (i2c == I2C1_BASE) { + return rcc_get_clksel_freq(RCC_CCIPR_I2C1SEL_SHIFT); + } else { + return rcc_apb1_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the SPI device at base specified. + * @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE). + */ +uint32_t rcc_get_spi_clk_freq(uint32_t spi __attribute__((unused))) { + return rcc_apb1_frequency; +} + /**@}*/ diff --git a/lib/stm32/h7/rcc.c b/lib/stm32/h7/rcc.c index 0977ebdf..71f7fae9 100644 --- a/lib/stm32/h7/rcc.c +++ b/lib/stm32/h7/rcc.c @@ -265,87 +265,101 @@ uint32_t rcc_get_bus_clk_freq(enum rcc_clock_source source) { } } -uint32_t rcc_get_peripheral_clk_freq(uint32_t periph) { - uint32_t clksel; - switch (periph) { - case FDCAN1_BASE: - case FDCAN2_BASE: - clksel = (RCC_D2CCIP1R >> RCC_D2CCIP1R_FDCANSEL_SHIFT) & RCC_D2CCIP1R_FDCANSEL_MASK; - if (clksel == RCC_D2CCIP1R_FDCANSEL_HSE) { - return rcc_clock_tree.hse_khz * HZ_PER_KHZ; - } else if (clksel == RCC_D2CCIP1R_FDCANSEL_PLL1Q) { - return rcc_clock_tree.pll1.q_mhz * HZ_PER_MHZ; - } else if (clksel == RCC_D2CCIP1R_FDCANSEL_PLL2Q) { - return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ; - } else { - return 0U; - } - case SPI1_BASE: - case SPI2_BASE: - case SPI3_BASE: - clksel = (RCC_D2CCIP1R >> RCC_D2CCIP1R_SPI123SEL_SHIFT) & RCC_D2CCIP1R_SPI123SEL_MASK; - if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL1Q) { - return rcc_clock_tree.pll1.q_mhz * HZ_PER_MHZ; - } else if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL2P) { - return rcc_clock_tree.pll2.p_mhz * HZ_PER_MHZ; - } else if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL3P) { - return rcc_clock_tree.pll3.p_mhz * HZ_PER_MHZ; - } else if (clksel == RCC_D2CCIP1R_SPI123SEL_PERCK) { - return rcc_get_bus_clk_freq(RCC_PERCLK); - } else { - return 0U; - } - case SPI4_BASE: - case SPI5_BASE: - clksel = (RCC_D2CCIP1R >> RCC_D2CCIP1R_SPI45SEL_SHIFT) & RCC_D2CCIP1R_SPI45SEL_MASK; - if (clksel == RCC_D2CCIP1R_SPI45SEL_APB4){ - return rcc_get_bus_clk_freq(RCC_APB1CLK); - } else if (clksel == RCC_D2CCIP1R_SPI45SEL_PLL2Q){ - return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ; - } else if (clksel == RCC_D2CCIP1R_SPI45SEL_PLL3Q){ - return rcc_clock_tree.pll3.q_mhz * HZ_PER_MHZ; - } else if (clksel == RCC_D2CCIP1R_SPI45SEL_HSI){ - return RCC_HSI_BASE_FREQUENCY; - } else if (clksel == RCC_D2CCIP1R_SPI45SEL_HSE) { - return rcc_clock_tree.hse_khz * HZ_PER_KHZ; - } else { - return 0U; - } - case USART1_BASE: - case USART6_BASE: - clksel = (RCC_D2CCIP2R >> RCC_D2CCIP2R_USART16SEL_SHIFT) & RCC_D2CCIP2R_USARTSEL_MASK; - if (clksel == RCC_D2CCIP2R_USART16SEL_PCLK2) { - return rcc_get_bus_clk_freq(RCC_APB2CLK); - } else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL2Q) { - return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ; - } else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL3Q) { - return rcc_clock_tree.pll3.q_mhz * HZ_PER_MHZ; - } else if (clksel == RCC_D2CCIP2R_USARTSEL_HSI) { - return RCC_HSI_BASE_FREQUENCY; - } else { - return 0U; - } - case USART2_BASE: - case USART3_BASE: - case UART4_BASE: - case UART5_BASE: - case UART7_BASE: - case UART8_BASE: - clksel = (RCC_D2CCIP2R >> RCC_D2CCIP2R_USART234578SEL_SHIFT) & RCC_D2CCIP2R_USARTSEL_MASK; - if (clksel == RCC_D2CCIP2R_USART234578SEL_PCLK1) { - return rcc_get_bus_clk_freq(RCC_APB1CLK); - } else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL2Q) { - return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ; - } else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL3Q) { - return rcc_clock_tree.pll3.q_mhz * HZ_PER_MHZ; - } else if (clksel == RCC_D2CCIP2R_USARTSEL_HSI) { - return RCC_HSI_BASE_FREQUENCY; - } else { - return 0U; - } - default: - cm3_assert_not_reached(); - return 0; +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + uint32_t clksel, pclk; + if (usart == USART1_BASE || usart == USART6_BASE) { + pclk = rcc_clock_tree.per.pclk2_mhz * HZ_PER_MHZ;; + clksel = (RCC_D2CCIP2R >> RCC_D2CCIP2R_USART16SEL_SHIFT) & RCC_D2CCIP2R_USARTSEL_MASK; + } else { + pclk = rcc_clock_tree.per.pclk1_mhz * HZ_PER_MHZ; + clksel = (RCC_D2CCIP2R >> RCC_D2CCIP2R_USART234578SEL_SHIFT) & RCC_D2CCIP2R_USARTSEL_MASK; + } + + /* Based on extracted clksel value, return the clock. */ + if (clksel == RCC_D2CCIP2R_USARTSEL_PCLK) { + return pclk; + } else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL2Q) { + return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ; + } else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL3Q) { + return rcc_clock_tree.pll3.q_mhz * HZ_PER_MHZ; + } else if (clksel == RCC_D2CCIP2R_USARTSEL_HSI) { + return RCC_HSI_BASE_FREQUENCY; + } else { + return 0U; + } +} + +uint32_t rcc_get_timer_clk_freq(uint32_t timer __attribute__((unused))) +{ + if (timer >= LPTIM2_BASE && timer <= LPTIM5_BASE) { + /* TODO: Read LPTIMxSEL values from D3CCIPR to determine clock source. */ + return rcc_clock_tree.per.pclk4_mhz * HZ_PER_MHZ; + } else if (timer >= TIM1_BASE && timer <= HRTIM_BASE) { + return rcc_clock_tree.per.pclk2_mhz * HZ_PER_MHZ; + } else { + return rcc_clock_tree.per.pclk1_mhz * HZ_PER_MHZ; + } +} + +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c) +{ + if (i2c == I2C4_BASE) { + /* TODO: Read I2C4SEL from D3CCIPR to determine clock source. */ + return rcc_clock_tree.per.pclk3_mhz * HZ_PER_MHZ; + } else { + /* TODO: Read I2C123SEL from D2CCIP2R to determine clock source. */ + return rcc_clock_tree.per.pclk1_mhz * HZ_PER_MHZ; + } +} + +uint32_t rcc_get_spi_clk_freq(uint32_t spi) +{ + if (spi == SPI4_BASE || spi == SPI5_BASE) { + uint32_t clksel = + (RCC_D2CCIP1R >> RCC_D2CCIP1R_SPI45SEL_SHIFT) & RCC_D2CCIP1R_SPI45SEL_MASK; + if (clksel == RCC_D2CCIP1R_SPI45SEL_APB4){ + return rcc_clock_tree.per.pclk2_mhz * HZ_PER_MHZ; + } else if (clksel == RCC_D2CCIP1R_SPI45SEL_PLL2Q){ + return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ; + } else if (clksel == RCC_D2CCIP1R_SPI45SEL_PLL3Q){ + return rcc_clock_tree.pll3.q_mhz * HZ_PER_MHZ; + } else if (clksel == RCC_D2CCIP1R_SPI45SEL_HSI){ + return RCC_HSI_BASE_FREQUENCY; + } else if (clksel == RCC_D2CCIP1R_SPI45SEL_HSE) { + return rcc_clock_tree.hse_khz * HZ_PER_KHZ; + } else { + return 0U; + } + } else { + uint32_t clksel = + (RCC_D2CCIP1R >> RCC_D2CCIP1R_SPI123SEL_SHIFT) & RCC_D2CCIP1R_SPI123SEL_MASK; + if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL1Q) { + return rcc_clock_tree.pll1.q_mhz * HZ_PER_MHZ; + } else if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL2P) { + return rcc_clock_tree.pll2.p_mhz * HZ_PER_MHZ; + } else if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL3P) { + return rcc_clock_tree.pll3.p_mhz * HZ_PER_MHZ; + } else if (clksel == RCC_D2CCIP1R_SPI123SEL_PERCK) { + return rcc_get_bus_clk_freq(RCC_PERCLK); + } else { + return 0U; + } + } +} + +uint32_t rcc_get_fdcan_clk_freq(uint32_t fdcan __attribute__((unused))) +{ + uint32_t clksel = + (RCC_D2CCIP1R >> RCC_D2CCIP1R_FDCANSEL_SHIFT) & RCC_D2CCIP1R_FDCANSEL_MASK; + if (clksel == RCC_D2CCIP1R_FDCANSEL_HSE) { + return rcc_clock_tree.hse_khz * HZ_PER_KHZ; + } else if (clksel == RCC_D2CCIP1R_FDCANSEL_PLL1Q) { + return rcc_clock_tree.pll1.q_mhz * HZ_PER_MHZ; + } else if (clksel == RCC_D2CCIP1R_FDCANSEL_PLL2Q) { + return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ; + } else { + return 0U; } } diff --git a/lib/stm32/l0/rcc.c b/lib/stm32/l0/rcc.c index 39bdaff7..01e84ac0 100644 --- a/lib/stm32/l0/rcc.c +++ b/lib/stm32/l0/rcc.c @@ -495,6 +495,83 @@ void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t sel) RCC_CCIPR = reg32 | (sel << shift); } + +/* Helper to calculate the frequency of a clksel based clock. */ +static uint32_t rcc_uart_i2c_clksel_freq_hz(uint32_t apb_clk, uint8_t shift) { + uint8_t clksel = (RCC_CCIPR >> shift) & RCC_CCIPR_I2C1SEL_MASK; + uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK; + switch (clksel) { + case RCC_CCIPR_USART1SEL_APB: + return apb_clk; + case RCC_CCIPR_USART1SEL_SYS: + return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre); + case RCC_CCIPR_USART1SEL_HSI16: + return 16000000U; + } + cm3_assert_not_reached(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for. + */ +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + if (usart == LPUART1_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_LPUART1SEL_SHIFT); + } else if (usart == USART1_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb2_frequency, RCC_CCIPR_USART1SEL_SHIFT); + } else { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_USART2SEL_SHIFT); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIM to get clock frequency for. + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer) +{ + /* Handle APB1 timers, and apply multiplier if necessary. */ + if (timer >= TIM2_BASE && timer <= TIM7_BASE) { + uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK; + return (ppre1 == RCC_CFGR_PPRE1_NODIV) ? rcc_apb1_frequency + : 2 * rcc_apb1_frequency; + } else { + uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK; + return (ppre2 == RCC_CFGR_PPRE2_NODIV) ? rcc_apb2_frequency + : 2 * rcc_apb2_frequency; + } + +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for. + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c) +{ + if (i2c == I2C1_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_I2C1SEL_SHIFT); + } else if (i2c == I2C3_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_I2C3SEL_SHIFT); + } else { + return rcc_apb1_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the SPI device at base specified. + * @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE). + */ +uint32_t rcc_get_spi_clk_freq(uint32_t spi) { + if (spi == SPI1_BASE) { + return rcc_apb2_frequency; + } else { + return rcc_apb1_frequency; + } +} + /** @brief RCC Setup PLL and use it as Sysclk source. * * @param[in] clock full struct with desired parameters diff --git a/lib/stm32/l1/rcc.c b/lib/stm32/l1/rcc.c index 06898d00..ddef69b6 100644 --- a/lib/stm32/l1/rcc.c +++ b/lib/stm32/l1/rcc.c @@ -39,6 +39,7 @@ system clock. Not all possible configurations are included. */ /**@{*/ +#include #include #include #include @@ -555,4 +556,55 @@ void rcc_clock_setup_pll(const struct rcc_clock_scale *clock) rcc_apb2_frequency = clock->apb2_frequency; } +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for. + */ +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + if (usart == USART1_BASE) { + return rcc_apb2_frequency; + } else { + return rcc_apb1_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIM to get clock frequency for. + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer) +{ + /* Handle APB1 timers, and apply multiplier if necessary. */ + if (timer >= TIM2_BASE && timer <= TIM7_BASE) { + uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK; + return (ppre1 == RCC_CFGR_PPRE1_HCLK_NODIV) ? rcc_apb1_frequency + : 2 * rcc_apb1_frequency; + } else { + uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK; + return (ppre2 == RCC_CFGR_PPRE2_HCLK_NODIV) ? rcc_apb2_frequency + : 2 * rcc_apb2_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for. + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c __attribute__((unused))) +{ + return rcc_apb1_frequency; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the SPI device at base specified. + * @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE). + */ +uint32_t rcc_get_spi_clk_freq(uint32_t spi) { + if (spi == SPI1_BASE) { + return rcc_apb2_frequency; + } else { + return rcc_apb1_frequency; + } +} /**@}*/ diff --git a/lib/stm32/l4/rcc.c b/lib/stm32/l4/rcc.c index 1d3e3472..c8429184 100644 --- a/lib/stm32/l4/rcc.c +++ b/lib/stm32/l4/rcc.c @@ -36,6 +36,7 @@ */ /**@{*/ +#include #include /* Set the default clock frequencies after reset. */ @@ -434,4 +435,85 @@ void rcc_set_rtc_clock_source(enum rcc_osc clk) } } +/* Helper to calculate the frequency of a UART/I2C based on the apb and clksel value. */ +static uint32_t rcc_uart_i2c_clksel_freq_hz(uint32_t apb_clk, uint8_t shift) { + uint8_t clksel = (RCC_CCIPR >> shift) & RCC_CCIPR_USARTxSEL_MASK; + uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK; + switch (clksel) { + case RCC_CCIPR_USARTxSEL_APB: + return apb_clk; + case RCC_CCIPR_USARTxSEL_SYS: + return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre); + case RCC_CCIPR_USARTxSEL_HSI16: + return 16000000U; + } + cm3_assert_not_reached(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the USART at base specified. + * @param usart Base address of USART to get clock frequency for. + */ +uint32_t rcc_get_usart_clk_freq(uint32_t usart) +{ + /* Handle values with selectable clocks. */ + if (usart == LPUART1_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb2_frequency, RCC_CCIPR_LPUART1SEL_SHIFT); + } else if (usart == USART1_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_USART1SEL_SHIFT); + } else if (usart == USART2_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_USART2SEL_SHIFT); + } else if (usart == USART3_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_USART3SEL_SHIFT); + } else if (usart == UART4_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_UART4SEL_SHIFT); + } else { /* USART5 */ + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_UART5SEL_SHIFT); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the Timer at base specified. + * @param timer Base address of TIM to get clock frequency for. + */ +uint32_t rcc_get_timer_clk_freq(uint32_t timer) +{ + /* Handle APB1 timers, and apply multiplier if necessary. */ + if (timer >= TIM2_BASE && timer <= TIM7_BASE) { + uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK; + return (ppre1 == RCC_CFGR_PPRE1_NODIV) ? rcc_apb1_frequency + : 2 * rcc_apb1_frequency; + } else { + uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK; + return (ppre2 == RCC_CFGR_PPRE2_NODIV) ? rcc_apb2_frequency + : 2 * rcc_apb2_frequency; + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the I2C device at base specified. + * @param i2c Base address of I2C to get clock frequency for. + */ +uint32_t rcc_get_i2c_clk_freq(uint32_t i2c) +{ + if (i2c == I2C1_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_I2C1SEL_SHIFT); + } else if (i2c == I2C2_BASE) { + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_I2C2SEL_SHIFT); + } else { /* I2C3 */ + return rcc_uart_i2c_clksel_freq_hz(rcc_apb1_frequency, RCC_CCIPR_I2C3SEL_SHIFT); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Get the peripheral clock speed for the SPI device at base specified. + * @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE). + */ +uint32_t rcc_get_spi_clk_freq(uint32_t spi) { + if (spi == SPI1_BASE) { + return rcc_apb2_frequency; + } else { + return rcc_apb1_frequency; + } +} /**@}*/