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).
This commit is contained in:
Brian Viele 2020-03-06 00:57:21 -05:00 committed by Karl Palsson
parent df55d45cc1
commit e41ac6ea71
24 changed files with 860 additions and 94 deletions

View File

@ -67,6 +67,13 @@ bool rcc_is_osc_ready(enum rcc_osc osc);
*/ */
void rcc_wait_for_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 END_DECLS
/**@}*/ /**@}*/

View File

@ -149,6 +149,7 @@ Control</b>
#define RCC_CFGR_PPRE_SHIFT 8 #define RCC_CFGR_PPRE_SHIFT 8
#define RCC_CFGR_PPRE (7 << RCC_CFGR_PPRE_SHIFT) #define RCC_CFGR_PPRE (7 << RCC_CFGR_PPRE_SHIFT)
#define RCC_CFGR_PPRE_MASK 0x7
/** @defgroup rcc_cfgr_apb1pre RCC_CFGR APB prescale Factors /** @defgroup rcc_cfgr_apb1pre RCC_CFGR APB prescale Factors
@{*/ @{*/
#define RCC_CFGR_PPRE_NODIV (0 << RCC_CFGR_PPRE_SHIFT) #define RCC_CFGR_PPRE_NODIV (0 << RCC_CFGR_PPRE_SHIFT)
@ -160,6 +161,7 @@ Control</b>
#define RCC_CFGR_HPRE_SHIFT 4 #define RCC_CFGR_HPRE_SHIFT 4
#define RCC_CFGR_HPRE (0xf << RCC_CFGR_HPRE_SHIFT) #define RCC_CFGR_HPRE (0xf << RCC_CFGR_HPRE_SHIFT)
#define RCC_CFGR_HPRE_MASK 0xf
/** @defgroup rcc_cfgr_ahbpre RCC_CFGR AHB prescale Factors /** @defgroup rcc_cfgr_ahbpre RCC_CFGR AHB prescale Factors
@{*/ @{*/
#define RCC_CFGR_HPRE_NODIV (0x0 << RCC_CFGR_HPRE_SHIFT) #define RCC_CFGR_HPRE_NODIV (0x0 << RCC_CFGR_HPRE_SHIFT)
@ -383,6 +385,12 @@ Control</b>
/**@}*/ /**@}*/
/* --- RCC_CFGR3 values ---------------------------------------------------- */ /* --- 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_SHIFT 16
#define RCC_CFGR3_USART2SW (3 << RCC_CFGR3_USART2SW_SHIFT) #define RCC_CFGR3_USART2SW (3 << RCC_CFGR3_USART2SW_SHIFT)
@ -403,6 +411,8 @@ Control</b>
#define RCC_CFGR3_USART1SW_LSE (2 << RCC_CFGR3_USART1SW_SHIFT) #define RCC_CFGR3_USART1SW_LSE (2 << RCC_CFGR3_USART1SW_SHIFT)
#define RCC_CFGR3_USART1SW_HSI (3 << RCC_CFGR3_USART1SW_SHIFT) #define RCC_CFGR3_USART1SW_HSI (3 << RCC_CFGR3_USART1SW_SHIFT)
#define RCC_CFGR3_USARTxSW_MASK 3
/* --- RCC_CFGR3 values ---------------------------------------------------- */ /* --- RCC_CFGR3 values ---------------------------------------------------- */
#define RCC_CR2_HSI48CAL_SHIFT 24 #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_hse_8mhz_out_48mhz(void);
void rcc_clock_setup_in_hsi_out_48mhz(void); void rcc_clock_setup_in_hsi_out_48mhz(void);
void rcc_clock_setup_in_hsi48_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 END_DECLS

View File

@ -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_clock_setup_pll(const struct rcc_clock_scale *clock);
void rcc_backupdomain_reset(void); 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 END_DECLS
#endif #endif

View File

@ -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); uint32_t rcc_system_clock_source(void);
void rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock); void rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock);
void rcc_backupdomain_reset(void); 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 END_DECLS

View File

@ -436,6 +436,9 @@
#define RCC_CFGR3_UART1SW_LSE 0x2 #define RCC_CFGR3_UART1SW_LSE 0x2
#define RCC_CFGR3_UART1SW_HSI 0x3 #define RCC_CFGR3_UART1SW_HSI 0x3
/* Shared mask for UART clock source. */
#define RCC_CFGR3_UARTxSW_MASK 0x3
/* --- Variable definitions ------------------------------------------------ */ /* --- Variable definitions ------------------------------------------------ */
extern uint32_t rcc_ahb_frequency; 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_5(void);
void rcc_usb_prescale_1(void); void rcc_usb_prescale_1(void);
void rcc_adc_prescale(uint32_t prescale1, uint32_t prescale2); 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 END_DECLS

View File

@ -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); uint32_t rcc_system_clock_source(void);
void rcc_clock_setup_pll(const struct rcc_clock_scale *clock); 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); 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 END_DECLS
#endif #endif
/**@}*/ /**@}*/

View File

@ -646,6 +646,10 @@
#define RCC_DCKCFGR2_UART2SEL_SHIFT 2 #define RCC_DCKCFGR2_UART2SEL_SHIFT 2
#define RCC_DCKCFGR2_UART1SEL_MASK 0x3 #define RCC_DCKCFGR2_UART1SEL_MASK 0x3
#define RCC_DCKCFGR2_UART1SEL_SHIFT 0 #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_ahb_frequency;
extern uint32_t rcc_apb1_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); 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_hse(const struct rcc_clock_scale *clock, uint32_t hse_mhz);
void rcc_clock_setup_hsi(const struct rcc_clock_scale *clock); 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 END_DECLS
/**@}*/ /**@}*/

View File

@ -251,7 +251,7 @@
#define RCC_PLLCFGR_PLLM_SHIFT 0x4 #define RCC_PLLCFGR_PLLM_SHIFT 0x4
#define RCC_PLLCFGR_PLLM_MASK 0x7 #define RCC_PLLCFGR_PLLM_MASK 0x7
/** @defgroup rcc_pllcfgr_pllm PLLM /** @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) #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 #define rcc_apb2_frequency rcc_apb1_frequency
/* --- Function prototypes ------------------------------------------------- */ /* --- Function prototypes ------------------------------------------------- */
#define _REG_BIT(offset, bit) (((offset) << 5) + (bit)) #define _REG_BIT(offset, bit) (((offset) << 5) + (bit))
enum rcc_osc { enum rcc_osc {
@ -778,7 +778,7 @@ enum rcc_periph_rst {
struct rcc_clock_scale { struct rcc_clock_scale {
enum rcc_osc sysclock_source; enum rcc_osc sysclock_source;
/* PLL as sysclock source cfg */ /* PLL as sysclock source cfg */
uint8_t pll_source; uint8_t pll_source;
uint8_t pll_div; 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_rng_clk_div(uint32_t rng_div);
void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t sel); 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 END_DECLS

View File

@ -409,6 +409,7 @@ LGPL License Terms @ref lgpl_license
#define RCC_D2CCIP2R_RNGSEL_LSI 3 #define RCC_D2CCIP2R_RNGSEL_LSI 3
#define RCC_D2CCIP2R_USART16SEL_PCLK2 0 #define RCC_D2CCIP2R_USART16SEL_PCLK2 0
#define RCC_D2CCIP2R_USART234578SEL_PCLK1 0 #define RCC_D2CCIP2R_USART234578SEL_PCLK1 0
#define RCC_D2CCIP2R_USARTSEL_PCLK 0
#define RCC_D2CCIP2R_USARTSEL_PLL2Q 1 #define RCC_D2CCIP2R_USARTSEL_PLL2Q 1
#define RCC_D2CCIP2R_USARTSEL_PLL3Q 2 #define RCC_D2CCIP2R_USARTSEL_PLL3Q 2
#define RCC_D2CCIP2R_USARTSEL_HSI 3 #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); 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 * Get the peripheral clock speed for the USART at base specified.
* proper sources out of the clock tree and calculate the clock for the * @param usart Base address of USART to get clock frequency for (e.g. USART1_BASE).
* 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.
*/ */
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 * Set the clksel value for the specified peripheral. This code will determine

View File

@ -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_msi_range(uint32_t msi_range);
void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t sel); void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t sel);
void rcc_set_lptim1_sel(uint32_t lptim1_sel); void rcc_set_lptim1_sel(uint32_t lptim1_sel);
void rcc_set_lpuart1_sel(uint32_t lpupart1_sel); void rcc_set_lpuart1_sel(uint32_t lpupart1_sel);
void rcc_set_usart1_sel(uint32_t usart1_sel); void rcc_set_usart1_sel(uint32_t usart1_sel);
void rcc_set_usart2_sel(uint32_t usart2_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 END_DECLS

View File

@ -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_hsi(const struct rcc_clock_scale *clock);
void rcc_clock_setup_pll(const struct rcc_clock_scale *clock); void rcc_clock_setup_pll(const struct rcc_clock_scale *clock);
void rcc_backupdomain_reset(void); 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 END_DECLS

View File

@ -987,6 +987,10 @@ void rcc_set_clock48_source(uint32_t clksel);
void rcc_enable_rtc_clock(void); void rcc_enable_rtc_clock(void);
void rcc_disable_rtc_clock(void); void rcc_disable_rtc_clock(void);
void rcc_set_rtc_clock_source(enum rcc_osc clk); 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 END_DECLS

View File

@ -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 #undef _RCC_REG

View File

@ -625,5 +625,73 @@ void rcc_clock_setup_in_hsi48_out_48mhz(void)
rcc_apb1_frequency = 48000000; rcc_apb1_frequency = 48000000;
rcc_ahb_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;
}
/**@}*/ /**@}*/

View File

@ -1289,5 +1289,45 @@ void rcc_backupdomain_reset(void)
RCC_BDCR &= ~RCC_BDCR_BDRST; 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;
}
/**@}*/ /**@}*/

View File

@ -389,4 +389,56 @@ void rcc_backupdomain_reset(void)
RCC_BDCR &= ~RCC_BDCR_BDRST; 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;
}
}
/**@}*/ /**@}*/

View File

@ -493,5 +493,87 @@ void rcc_adc_prescale(uint32_t prescale1, uint32_t prescale2)
RCC_CFGR2 &= ~(clear_mask); RCC_CFGR2 &= ~(clear_mask);
RCC_CFGR2 |= (set); 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;
}
}
/**@}*/ /**@}*/

View File

@ -791,4 +791,56 @@ void rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock)
rcc_clock_setup_pll(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;
}
}
/**@}*/ /**@}*/

View File

@ -484,4 +484,91 @@ void rcc_clock_setup_hsi(const struct rcc_clock_scale *clock)
rcc_apb2_frequency = clock->apb2_frequency; 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;
}
}
/**@}*/ /**@}*/

View File

@ -437,7 +437,7 @@ void rcc_set_mcopre(uint32_t mcopre)
* @param clock rcc_clock_scale with desired parameters * @param clock rcc_clock_scale with desired parameters
*/ */
void rcc_clock_setup(const struct rcc_clock_scale *clock) void rcc_clock_setup(const struct rcc_clock_scale *clock)
{ {
if (clock->sysclock_source == RCC_PLL) { if (clock->sysclock_source == RCC_PLL) {
enum rcc_osc pll_source; 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); 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;
}
/**@}*/ /**@}*/

View File

@ -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 rcc_get_usart_clk_freq(uint32_t usart)
uint32_t clksel; {
switch (periph) { uint32_t clksel, pclk;
case FDCAN1_BASE: if (usart == USART1_BASE || usart == USART6_BASE) {
case FDCAN2_BASE: pclk = rcc_clock_tree.per.pclk2_mhz * HZ_PER_MHZ;;
clksel = (RCC_D2CCIP1R >> RCC_D2CCIP1R_FDCANSEL_SHIFT) & RCC_D2CCIP1R_FDCANSEL_MASK; clksel = (RCC_D2CCIP2R >> RCC_D2CCIP2R_USART16SEL_SHIFT) & RCC_D2CCIP2R_USARTSEL_MASK;
if (clksel == RCC_D2CCIP1R_FDCANSEL_HSE) { } else {
return rcc_clock_tree.hse_khz * HZ_PER_KHZ; pclk = rcc_clock_tree.per.pclk1_mhz * HZ_PER_MHZ;
} else if (clksel == RCC_D2CCIP1R_FDCANSEL_PLL1Q) { clksel = (RCC_D2CCIP2R >> RCC_D2CCIP2R_USART234578SEL_SHIFT) & RCC_D2CCIP2R_USARTSEL_MASK;
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; /* Based on extracted clksel value, return the clock. */
} else { if (clksel == RCC_D2CCIP2R_USARTSEL_PCLK) {
return 0U; return pclk;
} } else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL2Q) {
case SPI1_BASE: return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ;
case SPI2_BASE: } else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL3Q) {
case SPI3_BASE: return rcc_clock_tree.pll3.q_mhz * HZ_PER_MHZ;
clksel = (RCC_D2CCIP1R >> RCC_D2CCIP1R_SPI123SEL_SHIFT) & RCC_D2CCIP1R_SPI123SEL_MASK; } else if (clksel == RCC_D2CCIP2R_USARTSEL_HSI) {
if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL1Q) { return RCC_HSI_BASE_FREQUENCY;
return rcc_clock_tree.pll1.q_mhz * HZ_PER_MHZ; } else {
} else if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL2P) { return 0U;
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) { uint32_t rcc_get_timer_clk_freq(uint32_t timer __attribute__((unused)))
return rcc_get_bus_clk_freq(RCC_PERCLK); {
} else { if (timer >= LPTIM2_BASE && timer <= LPTIM5_BASE) {
return 0U; /* TODO: Read LPTIMxSEL values from D3CCIPR to determine clock source. */
} return rcc_clock_tree.per.pclk4_mhz * HZ_PER_MHZ;
case SPI4_BASE: } else if (timer >= TIM1_BASE && timer <= HRTIM_BASE) {
case SPI5_BASE: return rcc_clock_tree.per.pclk2_mhz * HZ_PER_MHZ;
clksel = (RCC_D2CCIP1R >> RCC_D2CCIP1R_SPI45SEL_SHIFT) & RCC_D2CCIP1R_SPI45SEL_MASK; } else {
if (clksel == RCC_D2CCIP1R_SPI45SEL_APB4){ return rcc_clock_tree.per.pclk1_mhz * HZ_PER_MHZ;
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){ uint32_t rcc_get_i2c_clk_freq(uint32_t i2c)
return rcc_clock_tree.pll3.q_mhz * HZ_PER_MHZ; {
} else if (clksel == RCC_D2CCIP1R_SPI45SEL_HSI){ if (i2c == I2C4_BASE) {
return RCC_HSI_BASE_FREQUENCY; /* TODO: Read I2C4SEL from D3CCIPR to determine clock source. */
} else if (clksel == RCC_D2CCIP1R_SPI45SEL_HSE) { return rcc_clock_tree.per.pclk3_mhz * HZ_PER_MHZ;
return rcc_clock_tree.hse_khz * HZ_PER_KHZ; } else {
} else { /* TODO: Read I2C123SEL from D2CCIP2R to determine clock source. */
return 0U; return rcc_clock_tree.per.pclk1_mhz * HZ_PER_MHZ;
} }
case USART1_BASE: }
case USART6_BASE:
clksel = (RCC_D2CCIP2R >> RCC_D2CCIP2R_USART16SEL_SHIFT) & RCC_D2CCIP2R_USARTSEL_MASK; uint32_t rcc_get_spi_clk_freq(uint32_t spi)
if (clksel == RCC_D2CCIP2R_USART16SEL_PCLK2) { {
return rcc_get_bus_clk_freq(RCC_APB2CLK); if (spi == SPI4_BASE || spi == SPI5_BASE) {
} else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL2Q) { uint32_t clksel =
return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ; (RCC_D2CCIP1R >> RCC_D2CCIP1R_SPI45SEL_SHIFT) & RCC_D2CCIP1R_SPI45SEL_MASK;
} else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL3Q) { if (clksel == RCC_D2CCIP1R_SPI45SEL_APB4){
return rcc_clock_tree.pll3.q_mhz * HZ_PER_MHZ; return rcc_clock_tree.per.pclk2_mhz * HZ_PER_MHZ;
} else if (clksel == RCC_D2CCIP2R_USARTSEL_HSI) { } else if (clksel == RCC_D2CCIP1R_SPI45SEL_PLL2Q){
return RCC_HSI_BASE_FREQUENCY; return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ;
} else { } else if (clksel == RCC_D2CCIP1R_SPI45SEL_PLL3Q){
return 0U; return rcc_clock_tree.pll3.q_mhz * HZ_PER_MHZ;
} } else if (clksel == RCC_D2CCIP1R_SPI45SEL_HSI){
case USART2_BASE: return RCC_HSI_BASE_FREQUENCY;
case USART3_BASE: } else if (clksel == RCC_D2CCIP1R_SPI45SEL_HSE) {
case UART4_BASE: return rcc_clock_tree.hse_khz * HZ_PER_KHZ;
case UART5_BASE: } else {
case UART7_BASE: return 0U;
case UART8_BASE: }
clksel = (RCC_D2CCIP2R >> RCC_D2CCIP2R_USART234578SEL_SHIFT) & RCC_D2CCIP2R_USARTSEL_MASK; } else {
if (clksel == RCC_D2CCIP2R_USART234578SEL_PCLK1) { uint32_t clksel =
return rcc_get_bus_clk_freq(RCC_APB1CLK); (RCC_D2CCIP1R >> RCC_D2CCIP1R_SPI123SEL_SHIFT) & RCC_D2CCIP1R_SPI123SEL_MASK;
} else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL2Q) { if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL1Q) {
return rcc_clock_tree.pll2.q_mhz * HZ_PER_MHZ; return rcc_clock_tree.pll1.q_mhz * HZ_PER_MHZ;
} else if (clksel == RCC_D2CCIP2R_USARTSEL_PLL3Q) { } else if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL2P) {
return rcc_clock_tree.pll3.q_mhz * HZ_PER_MHZ; return rcc_clock_tree.pll2.p_mhz * HZ_PER_MHZ;
} else if (clksel == RCC_D2CCIP2R_USARTSEL_HSI) { } else if (clksel == RCC_D2CCIP1R_SPI123SEL_PLL3P) {
return RCC_HSI_BASE_FREQUENCY; return rcc_clock_tree.pll3.p_mhz * HZ_PER_MHZ;
} else { } else if (clksel == RCC_D2CCIP1R_SPI123SEL_PERCK) {
return 0U; return rcc_get_bus_clk_freq(RCC_PERCLK);
} } else {
default: return 0U;
cm3_assert_not_reached(); }
return 0; }
}
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;
} }
} }

View File

@ -495,6 +495,83 @@ void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t sel)
RCC_CCIPR = reg32 | (sel << shift); 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. /** @brief RCC Setup PLL and use it as Sysclk source.
* *
* @param[in] clock full struct with desired parameters * @param[in] clock full struct with desired parameters

View File

@ -39,6 +39,7 @@ system clock. Not all possible configurations are included.
*/ */
/**@{*/ /**@{*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/rcc.h> #include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include <libopencm3/stm32/pwr.h> #include <libopencm3/stm32/pwr.h>
@ -555,4 +556,55 @@ void rcc_clock_setup_pll(const struct rcc_clock_scale *clock)
rcc_apb2_frequency = clock->apb2_frequency; 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;
}
}
/**@}*/ /**@}*/

View File

@ -36,6 +36,7 @@
*/ */
/**@{*/ /**@{*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/rcc.h> #include <libopencm3/stm32/rcc.h>
/* Set the default clock frequencies after reset. */ /* 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;
}
}
/**@}*/ /**@}*/