Skip to content

Instantly share code, notes, and snippets.

@stecman
Last active February 23, 2020 22:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stecman/9fef6214276cc17df7ab624c8fccc860 to your computer and use it in GitHub Desktop.
Save stecman/9fef6214276cc17df7ab624c8fccc860 to your computer and use it in GitHub Desktop.
OpenCM3 USB clock configuration

USB with libopenCM3 on the STM32F070F6

This specific part doesn't work out of the box with the OpenCM3 STM32 F0 USB example/testcase for two reasons:

  • The USB pins (PA11/PA12) are hidden behind a mux on pins PA9/PA10 and need to be switched in. This physically connects the USB peripheral to the pins.
  • The STM32F070 must use an external oscillator to drive the 48MHz USB clock. My design used a 12MHz HSE, which libopencm3 didn't have a built-in clock configuration function for.
#include <libopencm3/stm32/flash.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/syscfg.h>
#include <libopencm3/usb/usbd.h>
/**
* Configure a 12MHz HSE to give a 48MHz PLL clock for the USB peripheral to function
*
* This is based on a clock configuration calculated in STM32 Cube. Note that
* the STM32F070 requires an external oscillator for USB as its HSI is not
* precise enough per the datasheet:
*
* > [USB] requires a precise 48 MHz clock which can be generated from the
* > internal main PLL (the clock source must use an HSE crystal oscillator).
*/
static void clock_setup_12mhz_hse_out_48mhz(void)
{
rcc_osc_on(RCC_HSE);
rcc_wait_for_osc_ready(RCC_HSE);
rcc_set_sysclk_source(RCC_HSE);
rcc_set_hpre(RCC_CFGR_HPRE_NODIV); // AHB Prescaler
rcc_set_ppre(RCC_CFGR_PPRE_NODIV); // APB1 Prescaler
flash_prefetch_enable();
flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ);
// PLL for USB: (12MHz * 8) / 2 = 48MHz
rcc_set_prediv(RCC_CFGR2_PREDIV_DIV2);
rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL8);
rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK);
rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK_DIV2);
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);
rcc_set_sysclk_source(RCC_PLL);
rcc_set_usbclk_source(RCC_PLL);
rcc_apb1_frequency = 48000000;
rcc_ahb_frequency = 48000000;
}
int main(void)
{
// Turn on the SYSCFG module and switch out PA9/PA10 for PA11/PA12
// The USB peripheral is not phsyically connected without this and won't be enumerated
RCC_APB2ENR |= RCC_APB2ENR_SYSCFGCOMPEN;
SYSCFG_CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
clock_setup_12mhz_hse_out_48mhz();
// ...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment