[stm32l1] Never write illegal values to voltage range selection

According to the reference manual, you are _forbidden_ from writing 00 to the
VOS[1:0] bits in PWR_CR.  Writing a 00 is automatically turned into range 2,
or, 10.  Attempting to then |= the bits for range 1 (01) results in the final
result of choosing voltage range 3 (11).  This has fairly catastrophic effects
if you then attempt to switch to PLL clock at 32Mhz.

Oddly, the existing code was working fine on STM32L151C6 revision W, but
failing with revision V silicon.  Regardless, the existing code was wrong and
not following the reference manual.

Further, attempting to change any power voltage range settings without the RCC
enabled will have no effect, so all the higher level helper routines
have added peripheral enable lines before attempting to set the range.
This commit is contained in:
Karl Palsson 2013-05-29 14:42:01 +00:00 committed by Karl Palsson
parent 8cfaef7fb6
commit a5966093e6
2 changed files with 11 additions and 4 deletions

View File

@ -35,20 +35,24 @@ LGPL License Terms @ref lgpl_license
*/
#include <libopencm3/stm32/pwr.h>
#include <libopencm3/stm32/rcc.h>
void pwr_set_vos_scale(vos_scale_t scale)
{
PWR_CR &= ~(PWR_CR_VOS_MASK);
/* You are not allowed to write zeros here, don't try and optimize! */
u32 reg = PWR_CR;
reg &= ~(PWR_CR_VOS_MASK);
switch (scale) {
case RANGE1:
PWR_CR |= PWR_CR_VOS_RANGE1;
reg |= PWR_CR_VOS_RANGE1;
break;
case RANGE2:
PWR_CR |= PWR_CR_VOS_RANGE2;
reg |= PWR_CR_VOS_RANGE2;
break;
case RANGE3:
PWR_CR |= PWR_CR_VOS_RANGE3;
reg |= PWR_CR_VOS_RANGE3;
break;
}
PWR_CR = reg;
}

View File

@ -466,6 +466,7 @@ void rcc_clock_setup_msi(const clock_scale_t *clock)
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN);
pwr_set_vos_scale(clock->voltage_scale);
// I guess this should be in the settings?
@ -496,6 +497,7 @@ void rcc_clock_setup_hsi(const clock_scale_t *clock)
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN);
pwr_set_vos_scale(clock->voltage_scale);
// I guess this should be in the settings?
@ -523,6 +525,7 @@ void rcc_clock_setup_pll(const clock_scale_t *clock)
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_PWREN);
pwr_set_vos_scale(clock->voltage_scale);
// I guess this should be in the settings?