stm32f1: rcc: provide struct based clock helpers

As on every other family.

Fixes: https://github.com/libopencm3/libopencm3/issues/1172
This commit is contained in:
Karl Palsson 2020-10-25 17:33:34 +00:00
parent a7902aa4d0
commit 5f051241a8
2 changed files with 233 additions and 0 deletions

View File

@ -704,6 +704,45 @@ enum rcc_periph_rst {
#include <libopencm3/stm32/common/rcc_common_all.h>
enum rcc_clock_hsi {
RCC_CLOCK_HSI_24MHZ,
RCC_CLOCK_HSI_48MHZ,
RCC_CLOCK_HSI_64MHZ,
RCC_CLOCK_HSI_END
};
enum rcc_clock_hse {
RCC_CLOCK_HSE12_72MHZ,
RCC_CLOCK_HSE16_72MHZ,
RCC_CLOCK_HSE25_72MHZ,
RCC_CLOCK_HSE8_24MHZ,
RCC_CLOCK_HSE8_72MHZ,
RCC_CLOCK_HSE_END
};
/* Union of all options for f100 through to f107 */
struct rcc_clock_scale {
uint8_t pll_mul;
uint8_t pll_source;
uint8_t hpre;
uint8_t ppre1;
uint8_t ppre2;
uint8_t adcpre;
uint8_t flash_waitstates;
uint8_t prediv1; /* aka xtpre, only one bit on smaller parts */
uint8_t prediv1_source;
uint8_t prediv2;
uint8_t pll2_mul;
uint8_t pll3_mul;
uint8_t usbpre;
uint32_t ahb_frequency;
uint32_t apb1_frequency;
uint32_t apb2_frequency;
};
extern const struct rcc_clock_scale rcc_hsi_configs[RCC_CLOCK_HSI_END];
extern const struct rcc_clock_scale rcc_hse_configs[RCC_CLOCK_HSE_END];
BEGIN_DECLS
void rcc_osc_ready_int_clear(enum rcc_osc osc);
@ -742,6 +781,14 @@ void rcc_clock_setup_in_hse_8mhz_out_72mhz(void);
void rcc_clock_setup_in_hse_12mhz_out_72mhz(void);
void rcc_clock_setup_in_hse_16mhz_out_72mhz(void);
void rcc_clock_setup_in_hse_25mhz_out_72mhz(void);
/**
* Switch sysclock to PLL with the given parameters.
* This should be usable from any point in time, but only if you have used
* library functions to manage clocks.
* @param clock full struct with desired parameters
*/
void rcc_clock_setup_pll(const struct rcc_clock_scale *clock);
void rcc_backupdomain_reset(void);
END_DECLS

View File

@ -58,6 +58,129 @@ uint32_t rcc_apb1_frequency = 8000000;
uint32_t rcc_apb2_frequency = 8000000;
uint32_t rcc_ahb_frequency = 8000000;
const struct rcc_clock_scale rcc_hse_configs[RCC_CLOCK_HSE_END] = {
{
/* hse-12, pll to 72 */
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.pll_mul = RCC_CFGR_PLLMUL_PLL_CLK_MUL6,
.prediv1 = RCC_CFGR2_PREDIV_NODIV,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV6,
.flash_waitstates = 2,
.ahb_frequency = 72000000,
.apb1_frequency = 36000000,
.apb2_frequency = 72000000,
},
{
/* hse16, pll to 72 */
.pll_mul = RCC_CFGR_PLLMUL_PLL_CLK_MUL9,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV6,
.flash_waitstates = 2,
.prediv1 = RCC_CFGR2_PREDIV_DIV2,
.ahb_frequency = 72e6,
.apb1_frequency = 36e6,
.apb2_frequency = 72e6,
},
{
/* hse25 to 72, this was a f105 config originally! intention preserved */
.pll_mul = RCC_CFGR_PLLMUL_PLL_CLK_MUL9,
.pll_source = RCC_CFGR_PLLSRC_PREDIV1_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV6,
.flash_waitstates = 2,
.prediv1 = RCC_CFGR2_PREDIV_DIV5,
.prediv1_source = RCC_CFGR2_PREDIV1SRC_PLL2_CLK,
.pll2_mul = RCC_CFGR2_PLL2MUL_PLL2_CLK_MUL8,
.prediv2 = RCC_CFGR2_PREDIV2_DIV5,
.usbpre = RCC_CFGR_USBPRE_PLL_VCO_CLK_DIV3,
.ahb_frequency = 72e6,
.apb1_frequency = 36e6,
.apb2_frequency = 72e6,
},
{
/* hse8, pll to 24 (f100 value line max) */
.pll_mul = RCC_CFGR_PLLMUL_PLL_CLK_MUL3,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_NODIV,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV2,
.flash_waitstates = 0,
.prediv1 = RCC_CFGR2_PREDIV_NODIV,
.ahb_frequency = 24e6,
.apb1_frequency = 24e6,
.apb2_frequency = 24e6,
},
{
/* hse8, pll to 72 */
.pll_mul = RCC_CFGR_PLLMUL_PLL_CLK_MUL9,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV8,
.flash_waitstates = 2,
.prediv1 = RCC_CFGR2_PREDIV_NODIV,
.ahb_frequency = 72e6,
.apb1_frequency = 36e6,
.apb2_frequency = 72e6,
},
};
const struct rcc_clock_scale rcc_hsi_configs[RCC_CLOCK_HSI_END] = {
{
/* hsi to 24Mhz, max for f100 */
.pll_source = RCC_CFGR_PLLSRC_HSI_CLK_DIV2,
.pll_mul = RCC_CFGR_PLLMUL_PLL_CLK_MUL6,
.prediv1 = RCC_CFGR2_PREDIV_NODIV,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_NODIV,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV2,
.flash_waitstates = 0,
.ahb_frequency = 24e6,
.apb1_frequency = 24e6,
.apb2_frequency = 24e6,
},
{
/* hsi to 48Mhz, allows usb, but out of spec */
.pll_source = RCC_CFGR_PLLSRC_HSI_CLK_DIV2,
.pll_mul = RCC_CFGR_PLLMUL_PLL_CLK_MUL12,
.prediv1 = RCC_CFGR2_PREDIV_NODIV,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV8,
.usbpre = RCC_CFGR_USBPRE_PLL_CLK_NODIV,
.flash_waitstates = 1,
.ahb_frequency = 48e6,
.apb1_frequency = 24e6,
.apb2_frequency = 48e6,
},
{
/* hsi to 64Mhz, max possible from hsi */
.pll_source = RCC_CFGR_PLLSRC_HSI_CLK_DIV2,
.pll_mul = RCC_CFGR_PLLMUL_PLL_CLK_MUL16,
.prediv1 = RCC_CFGR2_PREDIV_NODIV,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV8,
.flash_waitstates = 2,
.ahb_frequency = 64e6,
.apb1_frequency = 32e6,
.apb2_frequency = 64e6,
},
};
/*---------------------------------------------------------------------------*/
/** @brief RCC Clear the Oscillator Ready Interrupt Flag
@ -1087,6 +1210,69 @@ void rcc_clock_setup_in_hse_25mhz_out_72mhz(void)
rcc_apb2_frequency = 72000000;
}
void rcc_clock_setup_pll(const struct rcc_clock_scale *clock)
{
if (clock->pll_source == RCC_CFGR_PLLSRC_HSE_CLK) {
rcc_osc_on(RCC_HSE);
rcc_wait_for_osc_ready(RCC_HSE);
} else {
rcc_osc_on(RCC_HSI);
rcc_wait_for_osc_ready(RCC_HSI);
}
rcc_set_hpre(clock->hpre);
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
rcc_set_adcpre(clock->adcpre);
rcc_set_usbpre(clock->usbpre);
flash_set_ws(clock->flash_waitstates);
rcc_set_pll_multiplication_factor(clock->pll_mul);
rcc_set_pll_source(clock->pll_source);
/*
* Magically handle F105/7 parts too.
* xtpre == prediv1 bit 0.
*/
if (clock->prediv1 > RCC_CFGR2_PREDIV_DIV2) {
rcc_set_prediv1(clock->prediv1);
} else {
rcc_set_pllxtpre(clock->prediv1);
}
if (clock->prediv1_source) {
rcc_set_prediv1_source(clock->prediv1_source);
}
/*
* Magically handle other plls/prescalers on other parts
*/
if (clock->prediv2) {
rcc_set_prediv2(clock->prediv2);
}
if (clock->pll2_mul) {
rcc_set_pll2_multiplication_factor(clock->pll2_mul);
rcc_osc_on(RCC_PLL2);
rcc_wait_for_osc_ready(RCC_PLL2);
}
if (clock->pll3_mul) {
rcc_set_pll3_multiplication_factor(clock->pll3_mul);
rcc_osc_on(RCC_PLL3);
rcc_wait_for_osc_ready(RCC_PLL3);
}
/* Enable PLL oscillator and wait for it to stabilize. */
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);
/* Select PLL as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
/* Set the peripheral clock frequencies used. */
rcc_ahb_frequency = clock->ahb_frequency;
rcc_apb1_frequency = clock->apb1_frequency;
rcc_apb2_frequency = clock->apb2_frequency;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Reset the Backup Domain