Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
You can’t perform that action at this time.