Initializing the clock for 72MHz, controlled by the external crystal:
/*
* Initialize the clock to our max speed (72MHz), assuming an external 8MHz crystal.
* This also involves configuring the flash for wait states, and dividing the APB1
* (low speed peripheral bus) clock.
*/
ClockInit:
/*
* Set the flash for 2 wait states - the max needed at 72MHz.
* (do this FIRST!)
*/
ldr r0, =FLASH_R_BASE /* Flash control register */
ldr r1, [r0, #FLASH_ACR]
orr r1, #FLASH_ACR_LATENCY_2 /* Set for two wait states */
str r1, [r0, #FLASH_ACR]
/*
* Enable the oscillator for the external crystal, and wait
* for it to finish starting up.
*/
ldr r0, =RCC_BASE /* Clock control registers*/
ldr r1, [r0, #RCC_CR] /* get control reg contents */
orr r1, #RCC_CR_HSEON /* Turn on crystal oscillator */
str r1, [r0, #RCC_CR]
clklp: ldr r1, [r0, #RCC_CR]
tst r1, #RCC_CR_HSERDY /* wait for clock ready */
beq.n clklp
/*
* Configure and enable the PLL,then start it and wait for lock.
*/
ldr r1, [r0, #RCC_CFGR] /* Get clock config register */
orr r1, #RCC_CFGR_PLLMULL9 + RCC_CFGR_PLLSRC_HSE /* Multiply osc by 9 */
orr r1, #RCC_CFGR_PPRE1_DIV2 /* But make sure APB1 is < 36MHz */
str r1, [r0, #RCC_CFGR]
ldr r1, [r0, #RCC_CR] /* get control reg contents */
orr r1, #RCC_CR_PLLON /* Turn on PLL */
str r1, [r0, #RCC_CR] /* store */
plllp: ldr r1, [r0, #RCC_CR]
tst r1, #RCC_CR_PLLRDY /* wait for clock ready */
beq.n plllp
/*
* Select the PLL output as our system clock
*/
ldr r1, [r0, #RCC_CFGR]
orr r1, #RCC_CFGR_SW_PLL /* Select PLL */
str r1, [r0, #RCC_CFGR]
bx lr /* Return */
What a pain in the neck - a perfect example of the sort of low-level grunt-work on uninteresting peripherals that an embedded programmer would rather not waste time figuring out. (The standard peripheral library code that does this looks like it would expand to "really big." It's got abstractions piled on top of abstractions, properly sets/clears the state of nearly every bit (even if you "know" the startup state) (and pretty much one bit/field at a time.))
(I keep or-ing bits into my registers, and forgetting to store them back to the peripheral. HLL habits.)
(Is it working? I dunno. It blinks faster than it used to. It doesn't look 9x faster, though. I'm not sure how those wait states end up affecting the timing of the simple blink loop. Next step; SysTick.)