2022-09-02 06:00 AM
I'm using MSIS at 24 MHz for everything, like this:
SET_BIT(RCC->CR, RCC_CR_MSISON);
while (0 == (RCC->CR & RCC_CR_MSISRDY));
SET_BIT(RCC->ICSCR1, RCC_ICSCR1_MSIRGSEL);
MODIFY_REG(RCC->ICSCR1, RCC_ICSCR1_MSISRANGE, RCC_ICSCR1_MSISRANGE_0);
// enable 32kHz clock crystal
SET_BIT(PWR->DBPR, PWR_DBPR_DBP); // enable write access to backup domain
MODIFY_REG(RCC->BDCR, RCC_BDCR_LSEDRV, RCC_BDCR_LSEDRV_0); // medium-low drive power
SET_BIT(RCC->BDCR, RCC_BDCR_LSESYSEN); // enable propagation to other peripherals (like LPTIM4)
SET_BIT(RCC->BDCR, RCC_BDCR_LSEON); // LL_RCC_LSE_Enable
while (0 == READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY)); // wait until ready
// use it to trim the MSIS oscillator
MODIFY_REG(RCC->CR, RCC_CR_MSIPLLSEL, RCC_CR_MSIPLLSEL);
SET_BIT(RCC->CR, RCC_CR_MSIPLLEN);
// set MSIS as system clock
MODIFY_REG(RCC->CFGR1, RCC_CFGR1_SW, 0);
while (0 != READ_BIT(RCC->CFGR1, RCC_CFGR1_SWS)); /* Wait until system clock switched to MSIS */
SystemCoreClock = 24000000UL;
SET_BIT(PWR->CR3, PWR_CR3_FSTEN); // fast startup of regulator
MODIFY_REG(RCC->CFGR1, RCC_CFGR1_STOPWUCK, 0); /* use MSIS to wakeup from stop mode */
CLEAR_BIT(RCC->CR, RCC_CR_MSIPLLFAST);
CLEAR_BIT(FLASH->ACR, FLASH_ACR_PRFTEN | FLASH_ACR_LATENCY_Msk);
Then I configure the PLL like this:
SET_BIT(RCC->AHB2ENR1, RCC_AHB2ENR1_GPIOAEN);
SET_BIT(RCC->AHB3ENR, RCC_AHB3ENR_PWREN);
/* make sure PLL1 is off */
CLEAR_BIT(RCC->CR, RCC_CR_PLL1ON);
MODIFY_REG(RCC->PLL1CFGR,
RCC_PLL1CFGR_PLL1SRC | RCC_PLL1CFGR_PLL1RGE |
RCC_PLL1CFGR_PLL1FRACEN | RCC_PLL1CFGR_PLL1M |
RCC_PLL1CFGR_PLL1PEN | RCC_PLL1CFGR_PLL1QEN | RCC_PLL1CFGR_PLL1REN,
RCC_PLL1CFGR_PLL1SRC_0 /* MSI PLL */ |
RCC_PLL1CFGR_PLL1RGE /* MSI input range between 8 and 16 MHz */ |
RCC_PLL1CFGR_PLL1M_0 /* divide 24 MHz by 2 (prescaler before VCO, M) */ |
RCC_PLL1CFGR_PLL1REN /* enable output of PLL1R */
);
CLEAR_REG(RCC->PLL1FRACR); /* ensure a defined (but as far unused) fractional divider */
MODIFY_REG(RCC->PLL1DIVR,
RCC_PLL1DIVR_PLL1N | RCC_PLL1DIVR_PLL1R, /* clear what we need */
(11 << RCC_PLL1DIVR_PLL1N_Pos) /* VCO is this many times higher than its input frequency */ |
(0 << RCC_PLL1DIVR_PLL1R_Pos) /* post divider: value + 1 (?) */
);
Then I setup the MCO like this:
/**
* MCO GPIO Configuration
* CN13, Pin 2: PWM/D9
* PA8 ------> MCO
*/
MODIFY_REG(GPIOA->MODER, GPIO_MODER_MODE8, (2 << GPIO_MODER_MODE8_Pos)); // set mode to alternate function
CLEAR_BIT(GPIOA->OTYPER, GPIO_OTYPER_OT8); // set output type to push pull
CLEAR_BIT(GPIOA->PUPDR, GPIO_PUPDR_PUPD8); // no pullup
MODIFY_REG(GPIOA->OSPEEDR, GPIO_OSPEEDR_OSPEED8, (3 << GPIO_OSPEEDR_OSPEED8_Pos)); // set high speed for pins
MODIFY_REG(GPIOA->AFR[1], GPIO_AFRH_AFSEL8, (0 << GPIO_AFRH_AFSEL8_Pos)); // select alternate function 0 (MCO) on pin
/*
* 0x00000000U MCO output disabled, no clock on MCO
* RCC_CFGR1_MCOSEL_0 SYSCLK selection as MCO1 source
* RCC_CFGR1_MCOSEL_1 MSIS selection as MCO1 source
* (RCC_CFGR1_MCOSEL_0 | RCC_CFGR1_MCOSEL_1) HSI selection as MCO1 source
* RCC_CFGR1_MCOSEL_2 HSE selection as MCO1 source
* (RCC_CFGR1_MCOSEL_0 | RCC_CFGR1_MCOSEL_2) Main PLL selection as MCO1 source
* (RCC_CFGR1_MCOSEL_1 | RCC_CFGR1_MCOSEL_2) LSI selection as MCO1 source
* (RCC_CFGR1_MCOSEL_0 | RCC_CFGR1_MCOSEL_1| RCC_CFGR1_MCOSEL_2) LSE selection as MCO1 source
* RCC_CFGR1_MCOSEL_3 HSI48 selection as MCO1 source
* (RCC_CFGR1_MCOSEL_0 | RCC_CFGR1_MCOSEL_3) MSIK selection as MCO1 source
*/
MODIFY_REG(RCC->CFGR1, (RCC_CFGR1_MCOSEL | RCC_CFGR1_MCOPRE), (RCC_CFGR1_MCOSEL_0 | RCC_CFGR1_MCOSEL_2) | (3 << RCC_CFGR1_MCOPRE_Pos));
Just to check, this is what my scope gives me on MCO (PA/CN13-D9), when using SYSCLK on it. It gives nearly perfect 3MHz (24MHz/8). But the PLL1R is at 18 MHz, which means that the VCO has a frequency of 144 MHz, instead of the 132 MHz that I've configured (24MHz/2*11). What am I missing?
Solved! Go to Solution.
2022-09-02 06:11 AM
Argh, found it N of 11 implies a divider of 12
MODIFY_REG(RCC->PLL1DIVR,
RCC_PLL1DIVR_PLL1N | RCC_PLL1DIVR_PLL1R, /* clear what we need */
(11 << RCC_PLL1DIVR_PLL1N_Pos) /* VCO is this many times + 1 higher than its input frequency */ |
(0 << RCC_PLL1DIVR_PLL1R_Pos) /* post divider: value + 1 (?) */
);
2022-09-02 06:11 AM
Argh, found it N of 11 implies a divider of 12
MODIFY_REG(RCC->PLL1DIVR,
RCC_PLL1DIVR_PLL1N | RCC_PLL1DIVR_PLL1R, /* clear what we need */
(11 << RCC_PLL1DIVR_PLL1N_Pos) /* VCO is this many times + 1 higher than its input frequency */ |
(0 << RCC_PLL1DIVR_PLL1R_Pos) /* post divider: value + 1 (?) */
);