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:
committed by
Karl Palsson
parent
df55d45cc1
commit
e41ac6ea71
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/flash.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;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
#include <libopencm3/cm3/assert.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
Reference in New Issue
Block a user