From ce7d7782086af8440756d917d71e5d8fa3e431dc Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Wed, 29 Mar 2023 12:19:44 -0400 Subject: [PATCH] add 80MHz clock example --- 00-80mhz/Makefile | 5 +++++ 00-80mhz/README.md | 14 +++++++++++++ 00-80mhz/main.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 00-80mhz/Makefile create mode 100644 00-80mhz/README.md create mode 100644 00-80mhz/main.c diff --git a/00-80mhz/Makefile b/00-80mhz/Makefile new file mode 100644 index 0000000..4a7074c --- /dev/null +++ b/00-80mhz/Makefile @@ -0,0 +1,5 @@ +COMMON_DIR := ../common + +CFILES += main.c + +include $(COMMON_DIR)/rules.mk diff --git a/00-80mhz/README.md b/00-80mhz/README.md new file mode 100644 index 0000000..356be7e --- /dev/null +++ b/00-80mhz/README.md @@ -0,0 +1,14 @@ +# 0. 80MHz system clock + +This example shows how to set up the STM32 microcontroller to execute at its faster clock speed of 80MHz. + +Achieving this speed requires two things: + +1. Setting up the Phase-Locked Loop (PLL) to multiply a source clock up to 80MHz. +2. Configuring flash wait-states to ensure that the processor does not execute faster than instructions can be fetched. + +Once the system clock is set to 80MHz, the Microcontroller Clock Output (MCO) is configured to output the system clock +over pin PA8. This output can be viewed with an oscilloscope to confirm the clock's speed. + +See `main.c` for comments describing the configuration steps in more detail. + diff --git a/00-80mhz/main.c b/00-80mhz/main.c new file mode 100644 index 0000000..b343bf7 --- /dev/null +++ b/00-80mhz/main.c @@ -0,0 +1,49 @@ +#include + +int main(void) +{ + // Disable interrupts + asm("cpsid i"); + + // Running at 80MHz requires configuring flash wait-states: + FLASH->ACR = (FLASH->ACR & ~(FLASH_ACR_LATENCY)) | FLASH_ACR_LATENCY_4WS; + + // Configure the PLL to output 80MHz: + // 1. MSI clock is 4MHz at reset, use MSI as source for PLL + // 2. Set PLLN multiplier to 40: 4MHz * 40 = 160MHz + // 3. PLLM divider is set to zero, no division there + // 4. Set PLLR system clock divider to zero = division by two + // 160MHz / 2 = 80MHz + RCC->PLLCFGR = RCC_PLLCFGR_PLLSRC_MSI | + (40 << RCC_PLLCFGR_PLLN_Pos) | + (0 << RCC_PLLCFGR_PLLR_Pos) | + RCC_PLLCFGR_PLLREN; + + // Enable the PLL + RCC->CR |= RCC_CR_PLLON; + while ((RCC->CR & RCC_CR_PLLRDY) != RCC_CR_PLLRDY); + + // Set the system clock to use PLL + // Also clear the HPRE divider to be safe + RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_HPRE_Msk | RCC_CFGR_SW_Msk)) | + RCC_CFGR_SW_PLL; + while ((RCC->CFGR & RCC_CFGR_SWS_PLL) != RCC_CFGR_SWS_PLL); + + // The processor is now running at 80MHz! + + // Enable MCO to output the system clock over PA8 + RCC->CFGR &= ~(RCC_CFGR_MCOPRE_Msk); + RCC->CFGR |= 2 << RCC_CFGR_MCOSEL_Pos; + + // Configure PA8 for alternate function zero (MCO) + RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN; + GPIOA->MODER &= ~(GPIO_MODER_MODE8_Msk); + GPIOA->MODER |= 2 << GPIO_MODER_MODE8_Pos; + GPIOA->AFR[1] &= ~(GPIO_AFRH_AFSEL8_Msk); + + // Using a volatile assembly instruction ensures that this loop is not + // optimized away by the compiler. + while (1) + asm volatile("nop"); +} +