Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System clock of 32 MHz via PLLMul::Mul4 and PLLDiv::Div2 leads to hard fault because of default voltage range #139

Open
henriheimann opened this issue Jan 3, 2021 · 2 comments

Comments

@henriheimann
Copy link

When using the following configuration for a 32 MHz system clock, which is possible since #129, a hard fault is generated:

let mut rcc = dp.RCC.freeze(Config::pll(PLLSource::HSI16, PLLMul::Mul4, PLLDiv::Div2));

I traced the problem down to the default Vcore range. As shown by the following table (STM32L0 reference manual, p. 174), VcoreRange::Range1 would be required for frequencies greater than 16 MHz. The default configured Vcore range however, is VcoreRange::Range2 (STM32L0 reference manual, p. 158).

vcore_ranges

With the current interface of stm32l0xx-hal, it seems that configuration of the Vcore range is only possible after freezing the RCC, which is too late to prevent the hard fault:

let mut rcc = dp.RCC.freeze(Config::pll(PLLSource::HSI16, PLLMul::Mul4, PLLDiv::Div2));
let mut pwr = PWR::new(dp.PWR, &mut rcc);
pwr.switch_vcore_range(VcoreRange::Range1);

I would be glad to help resolve this issue myself, but as I am new to using Rust for embedded development it would be great if someone experienced could provide me with some hints on how to pass an instance of PWR to RCC.freeze / write to PWR registers from RCC.freeze / create PWR during RCC.freeze / or whatever the best way might be.

@kaidokert
Copy link

kaidokert commented Mar 25, 2021

Hmm, i ran into the same issue, and "fixed" it by looking at what STMCube generated. STMCube modified the flash wait state

This worked:

// code lifted from flash.set_wait_state()
device.FLASH.acr.modify(|_, w| w.latency().variant(hal::pac::flash::acr::LATENCY_A::WS1));
let cfg = hal::rcc::Config::pll(hal::rcc::PLLSource::HSI16, hal::rcc::PLLMul::Mul4, hal::rcc::PLLDiv::Div2);
let mut rcc = device.RCC.freeze(cfg);

Note that this doesn't work:

let cfg = hal::rcc::Config::pll(hal::rcc::PLLSource::HSI16, hal::rcc::PLLMul::Mul4, hal::rcc::PLLDiv::Div2);
let mut rcc = device.RCC.freeze(cfg);
let mut flash = hal::flash::FLASH::new(device.FLASH, &mut rcc);
flash.set_wait_states(hal::pac::flash::acr::LATENCY_A::WS1);

As it's too late to modify it, the device has already locked up. Same problem as for modifying VCore

EDIT: Another note, i think it would be useful to add an example for configuring non-default clock, i.e. MSI and PLL, all the examples seem to be running with default 16 Mhz HSI

@kaidokert
Copy link

After poring over datasheet, to be fully in spec, it looks like both the wait state and vcore need to be set. The device ( L062 here ) powers up at 1.5V by default in range 2, not at 1.8V,

So for anyone following along at home, if you want 32mhz, do this, it'll most likely work:

device.FLASH.acr.modify(|_, w| w.latency().variant(hal::pac::flash::acr::LATENCY_A::WS1));
let mut rcc = device.RCC.freeze(hal::rcc::Config::pll(
            hal::rcc::PLLSource::HSI16, hal::rcc::PLLMul::Mul4, hal::rcc::PLLDiv::Div2,
        ));
let mut pwr = hal::pwr::PWR::new(device.PWR, &mut rcc);
pwr.switch_vcore_range(hal::pwr::VcoreRange::Range1);

Although the latter bit still looks sketchy as the voltage should be upped before clock change. Copying the PAC code from switch_vcore_range out would also work, if you want to be super sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants