cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L0 cannot change PWR_CR_ VOS

RinGO
Associate II

Hi, I'm stuck on a problem with setting PWR_CR_VOS on NUCLEO-32 STM32L031K6
- I want to select HSI16-PLL as clock source
- VDD is 3.3V
- FLASH latency is set to 1WS
But I can only set PWR_CR_VOS to RANGE 2 and RANGE 3.
RANGE 1 cannot be selected, so I can't set HSI-PLL to 32MHz
where am I going wrong?

Example code:

// Set the Flash ACR to use 1 wait-state
// and enable the prefetch buffer and pre-read.
FLASH->ACR |= (FLASH_ACR_LATENCY | FLASH_ACR_PRFTEN | FLASH_ACR_PRE_READ);

//----------------------------------------------------
// 1. POWER ENABLE CLOCK and VOLTAGE REGULATOR
//----------------------------------------------------
// APB2ENR->SYSCFGEN
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;

// APB1ENR->PWREN: Power interface clock enable bit for PWR
RCC->APB1ENR |= RCC_APB1ENR_PWREN;

// PWR: VOS[11:2] bits (Voltage scaling range selection)
// !!! 0x0UL: FORBIDDEN
// 0x1UL: 0b01 RANGE 1 1.8V 32MHz
// 0x2UL: 0b10 RANGE 2 1.5V 16MHz
// 0x3UL: 0b11 RANGE 3 1.2V 4.2MHz
// Clear VOS bits
PWR->CR &= ~PWR_CR_VOS;
// SET RANGE 1
PWR->CR |= (0x1UL << 11U);
// Wait until ready
while (PWR->CSR & PWR_CSR_VOSF);

The value in the register is still 0x2UL, when trying to change to 0x1UL the register is 0x3UL
Where am I making a mistake that RANGE1 cannot be set to 0x1UL?

5 REPLIES 5
RinGO
Associate II

Interestingly, if I generate the CubeMX code with the LL library, it works. PWR_CR_VOS set to 0x1UL

I've taken the code step by step, but up to the PWR_CR_VOS setting, everything is the same except for the NVIC setting for SysTick, which shouldn't affect the registry settings.

waclawek.jan
Super User

It's in the comments

// PWR: VOS[11:2] bits (Voltage scaling range selection)
// !!! 0x0UL: FORBIDDEN

yet you still do it

PWR->CR &= ~PWR_CR_VOS;

NEVER split a read-clear_bits-set_bits-write operation into two (i.e. read-clear_bits-write, read-set_bits-write).

JW

Okay, I canceled the PWR_CR_VOS register reset. Still the same result. I want to write 0x1UL to the VOS register, but it changes from 0x2UL to 0x3UL
Why?

(Virus scan in progress ...)
RinGO
Associate II

An incomprehensible phenomenon for me.
If I try to change the VOS bit value in the PWR_CR register,
// SET RANGE 1
PWR->CR |= (0x1UL << 11U);
It doesn't work. The value changes from 0x2UL to 0x3UL

 

If I change the value of the entire PWR_CR register in hard mode,
// SET RANGE 1
PWR-> CR = 0x00000800;
it works. The value changes from 0x2UL to 0x1UL

Why doesn't it work the first way? Overwriting the entire register is not a solution.

waclawek.jan
Super User

The reset value of the VOS field is 0b01, if you OR it with 0b10 the result is 0b11.

You may want to do something like:

uint32_t tmp;

tmp = PWR->CR & (~PWR_CR_VOS);
tmp = tmp |= (0x1UL << 11U);
PWR->CR = tmp;

JW