-
Notifications
You must be signed in to change notification settings - Fork 8.7k
Description
Describe the bug
The stm32 clock driver does not set the VOS0 mode as it claims to do.
In the function prepare_regulator_voltage_scale(void) there is the following code:
/* Make sure to put the CPU in highest Voltage scale during clock configuration */
/* Highest voltage is SCALE0 */
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE0);
The comments clearly say the purpose of the function to set VOS0 and also the value used LL_PWR_REGU_VOLTAGE_SCALE0 means VOS0, however the LL_PWR_SetRegulVoltageScaling function is unable to do so:
/**
* @brief Set the main internal Regulator output voltage
* @rmtoll D3CR VOS LL_PWR_SetRegulVoltageScaling
* @param VoltageScaling This parameter can be one of the following values:
* @arg @ref LL_PWR_REGU_VOLTAGE_SCALE0
* @arg @ref LL_PWR_REGU_VOLTAGE_SCALE1
* @arg @ref LL_PWR_REGU_VOLTAGE_SCALE2
* @arg @ref LL_PWR_REGU_VOLTAGE_SCALE3
* @note For all H7 lines except STM32H7Axxx and STM32H7Bxxx lines, VOS0
* is applied when PWR_D3CR_VOS[1:0] = 0b11 and SYSCFG_PWRCR_ODEN = 0b1.
* @retval None
*/
__STATIC_INLINE void LL_PWR_SetRegulVoltageScaling(uint32_t VoltageScaling)
{
#if defined (PWR_CPUCR_PDDS_D2)
MODIFY_REG(PWR->D3CR, PWR_D3CR_VOS, VoltageScaling);
#else
MODIFY_REG(PWR->SRDCR, PWR_SRDCR_VOS, VoltageScaling);
#endif /* PWR_CPUCR_PDDS_D2 */
}
The note correctly states that to use VOS0 is necessary also to set the ODEN bit, but this function does not modify it.
To actually activate the VOS0 is necessary to use something like:
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
This macro correctly sets VOS1 and then sets the ODEN bit which eventually set VOS0 correctly.
The effect of this bug is that in case of highly demanding fw (many peripherals used at the same time), the fw could crash because it fails to correctly read from ram (especially during initialization phase). It is a subtle bug because in many cases the VOS1 setting is enough to keep things working also in case high AXI Interface clock frequency (225MHz,240MHz) is used. (See table 16 of STM32H747 Reference manual, RM0399, pag. 166).
Below I classified the bug as "major" because it could be very problematic to detect and lead to unusable boards: perfectly fine application crashes only when many peripheral are use together. Nevertheless it is very easy to reproduce and systematic.
Regression
- This is a regression.
Steps to reproduce
Use the following function to print the vos status:
#include <soc.h>
/**
* @brief Prints the current STM32H7 Voltage Scaling (VOS) state.
* This reads the raw hardware registers from the PWR and SYSCFG
* peripherals to determine the exact voltage being supplied to the core.
*/
void print_vos_setting(void)
{
/* Ensure the SYSCFG clock is enabled so we can read its registers */
__HAL_RCC_SYSCFG_CLK_ENABLE();
/* Read the hardware registers */
uint32_t pwr_d3cr = PWR->D3CR;
uint32_t syscfg_pwrcr = SYSCFG->PWRCR;
/* Extract the specific bits */
/* VOS is located at bits 14 and 15 of PWR->D3CR */
uint32_t vos_bits = (pwr_d3cr & PWR_D3CR_VOS) >> PWR_D3CR_VOS_Pos;
/* ODEN is bit 0 of SYSCFG->PWRCR */
uint32_t oden_bit = (syscfg_pwrcr & SYSCFG_PWRCR_ODEN) ? 1 : 0;
printk("\n========================================\n");
printk(" DIAGNOSTIC: VOLTAGE SCALE \n");
printk("========================================\n");
printk("PWR_D3CR (VOS bits) : %u\n", vos_bits);
printk("SYSCFG_PWRCR (ODEN) : %u\n", oden_bit);
/* 4. Interpret the results based on the STM32H7 datasheet */
if (vos_bits == 3) {
if (oden_bit == 1) {
printk("Current State : VOS0 (Overdrive / 1.35V)\n");
} else {
printk("Current State : VOS1 (1.25V)\n");
}
} else if (vos_bits == 2) {
printk("Current State : VOS2 (1.15V)\n");
} else if (vos_bits == 1) {
printk("Current State : VOS3 (1.05V)\n");
} else {
printk("Current State : Unknown\n");
}
printk("========================================\n\n");
}
The function will print:
=======================================
DIAGNOSTIC: VOLTAGE SCALE
========================================
PWR_D3CR (VOS bits) : 3
SYSCFG_PWRCR (ODEN) : 0
Current State : VOS1 (1.25V)
========================================
This means that the current code calling LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE0); does not work properly.
Relevant log output
Impact
Major – Severely degrades functionality; workaround is difficult or unavailable.
Environment
OS: Linux (Ubuntu 22.04)
Zephyr SDK version: 0.17.4
Zephyr version: tag v4.3.0 (SHA: 3568e1b)
Additional Context
No response