2025-12-10 4:40 AM
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?
2025-12-10 4:47 AM
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.
2025-12-10 6:01 AM - edited 2025-12-10 6:03 AM
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
2025-12-10 7:22 AM
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?
2025-12-10 7:49 AM
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.
2025-12-10 8:00 AM
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