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

STM32H7 Power Configuration issues leading to general unreliability to start-up #2806

Open
birdistheword96 opened this issue Apr 12, 2024 · 8 comments

Comments

@birdistheword96
Copy link

This is a placeholder issue to track the knowledge we have on why STM32H7's are so unreliable to start-up. all of my testing has been done on three different STM32H745 boards: a Nucleo, a Discovery board, and a custom in-house board. This is what I have found so far, and will update as I discover more:

  • Encountered the exact same issue on all three different STM32H745 boards
  • Whenever I try to bring a project to life using Rust/Embassy, it throws a tantrum, failing a few times and getting stuck at while !PWR.csr1().read().actvosrdy() {} in the rcc::init function.
  • Oddly enough, playing musical chairs with various example projects in the embassy repo seems to eventually coax it into working... until the next power cycle, that is.
  • Tweaking the voltage scales seems to have no effect on the frequency of the gremlin...
  • In a twist, flashing a bare-metal (C) project from STMCube initially follows the same script of failure (post-Embassy project flash). Yet, post a power cycle, it runs as smooth as butter - no hiccups or boot issues whatsoever, power cycle after power cycle.
@bsodmike
Copy link
Contributor

I had this issue for a while on the H747xi but managed to resolve it after much testing. Let me dig up the config I'm using.

I have a spare NUCLEO-H743ZI2 which I can test for you if you like.

@birdistheword96
Copy link
Author

This is the code I have configured for my custom board, which to be fair has an external oscillator, but I have equivalent C code which I can use t- get it running reliably. so i am trying to work out the difference. This is the config I have:

    let mut config = Config::default();
    {
        use embassy_stm32::rcc::*;
        // config.rcc.hsi = Some(HSIPrescaler::DIV1);
        config.rcc.hsi = None; // Since we're using HSE
        config.rcc.hse = Some(Hse { freq: mhz(20), mode: HseMode::Bypass});
        config.rcc.csi = false;
        config.rcc.pll1 = Some(Pll {
            source: PllSource::HSE,
            prediv: PllPreDiv::DIV2,
            mul: PllMul::MUL32,
            divp: Some(PllDiv::DIV2),
            divq: Some(PllDiv::DIV8),
            divr: Some(PllDiv::DIV2),
        });
        config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
        config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
        config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
        config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
        config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
        config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
        config.rcc.voltage_scale = VoltageScale::Scale3;
        config.rcc.supply_config = SupplyConfig::DirectSMPS;
    }
    let p = embassy_stm32::init(config);

And this is the equivalent config generated from STMCube:

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Macro to configure the PLL clock source
  */
  __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSE);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 2;
  RCC_OscInitStruct.PLL.PLLN = 32;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 8;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}

@birdistheword96
Copy link
Author

When I read out the PWR.CR3 register just before waiting for VOSRDY, the configuration from STMCube sets the register up as 0x5010044, whereas Embassy has it set up as 0x10044. Looking at RM0399, the difference is that the the register setup from the STMCUBE also has the USB33RDY and USB33DEN enabled, which are both USB specific and not something I am using.

I can only assume that the STMCube HAL is adding bloat and enabling those even though they arent specifically being used

@bsodmike
Copy link
Contributor

bsodmike commented Apr 13, 2024

Also tested on both STM32h7hxi Arduino Portenta H7 & GIGA R1 WiFi and hits the full 480MHz and 1.21 giga-watts!!

0.000000 TRACE BDCR configured: 00008113
└─ embassy_stm32::rcc::bd::{impl#3}::init::{closure#4} @ /Users/mdesilva/.cargo/git/checkouts/embassy-9312dcb0ed774b29/49807c0/embassy-stm32/src/fmt.rs:117 
0.000000 DEBUG rcc: Clocks { csi: Some(Hertz(4000000)), hclk1: Some(Hertz(240000000)), hclk2: Some(Hertz(240000000)), hclk3: Some(Hertz(240000000)), hclk4: Some(Hertz(240000000)), hse: None, hsi: Some(Hertz(64000000)), hsi48: Some(Hertz(48000000)), i2s_ckin: None, lse: None, lsi: None, pclk1: Some(Hertz(120000000)), pclk1_tim: Some(Hertz(240000000)), pclk2: Some(Hertz(120000000)), pclk2_tim: Some(Hertz(240000000)), pclk3: Some(Hertz(120000000)), pclk4: Some(Hertz(120000000)), pll1_q: Some(Hertz(120000000)), pll2_p: Some(Hertz(100000000)), pll2_q: None, pll2_r: None, pll3_p: None, pll3_q: None, pll3_r: None, rtc: Some(Hertz(32768)), sys: Some(Hertz(480000000)) }

Use the following config:

pub fn init() -> (embassy_stm32::Peripherals, cortex_m::Peripherals) {
    let mut config = Config::default();
    {
        use embassy_stm32::rcc::*;
        config.rcc.supply_config = SupplyConfig::LDO;
        config.rcc.hsi = Some(HSIPrescaler::DIV1); // // 64MHz
        config.rcc.csi = true;
        config.rcc.hsi48 = Some(Hsi48Config {
            sync_from_usb: true,
        }); // needed for USB

        #[cfg(feature = "stm32h747_400")]
        {
            config.rcc.pll1 = Some(Pll {
                source: PllSource::HSI,
                prediv: PllPreDiv::DIV4,
                mul: PllMul::MUL50,
                divp: Some(PllDiv::DIV2), // ((64/4)*50)/2 = 400MHz
                divq: Some(PllDiv::DIV8), // ((64/4)*50)/8 = 100MHz / SPI1 cksel defaults to pll1_q
                divr: None,
            });
            config.rcc.pll2 = Some(Pll {
                source: PllSource::HSI,
                prediv: PllPreDiv::DIV8,
                mul: PllMul::MUL50,
                divp: Some(PllDiv::DIV4), // ((64/8)*50)/4 = 100MHz
                divq: None,
                divr: None,
            });
        }
        #[cfg(feature = "stm32h747_480")]
        {
            config.rcc.pll1 = Some(Pll {
                source: PllSource::HSI,
                prediv: PllPreDiv::DIV8,
                mul: PllMul::MUL120,
                divp: Some(PllDiv::DIV2), // ((64/8)*120)/2 = 480MHz
                divq: Some(PllDiv::DIV8), // ((64/8)*120)/8 = 120MHz / SPI1 cksel defaults to pll1_q
                divr: None,
            });
            config.rcc.pll2 = Some(Pll {
                source: PllSource::HSI,
                prediv: PllPreDiv::DIV8,
                mul: PllMul::MUL50,
                divp: Some(PllDiv::DIV4), // ((64/8)*50)/4 = 100MHz
                divq: None,
                divr: None,
            });
        }
        config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
        config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
        config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
        config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
        config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
        config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
        config.rcc.voltage_scale = VoltageScale::Scale0;

        let mut mux = rcc::mux::ClockMux::default();
        mux.adcsel = rcc::mux::Adcsel::PLL2_P;
        config.rcc.mux = mux;

        // RTC
        config.rcc.ls = LsConfig::default_lse();

        trace!("Voltage::Scale{=i32}", config.rcc.voltage_scale as i32);
    }

    let p: embassy_stm32::Peripherals = embassy_stm32::init(config);
    let core_peri = cortex_m::Peripherals::take().unwrap();

    (p, core_peri)
}

This is my config, I don't think I had much luck with config.rcc.hse.

@bsodmike
Copy link
Contributor

Also, this works on the STM32h7hxi Arduino Portenta H7
https://github.com/embassy-rs/embassy/blob/main/examples/stm32h7/src/bin/dac_dma.rs

@bsodmike
Copy link
Contributor

I've found some instability in my power configuration for the STM32h7hxi and have shared https://github.com/bsodmike/stm32h747xi-embassy-uart-troubleshoot which can be flashed onto an Arduino Portenta H7. See REDME for details.

If anyone has a working config for UART with stm32h747xi please let me know.

@romainreignier
Copy link
Contributor

Also, this works on the STM32h7hxi Arduino Portenta H7
https://github.com/embassy-rs/embassy/blob/main/examples/stm32h7/src/bin/dac_dma.rs

I have tested the same rcc config in the blinky sketch on a Portenta and it seems that the clock speed is not right, the blink seems quite slow (will need to check with a logic analyzer).

This zephyr PR has some interesting comments and seems to have a working RCC config to get to 400 MHz.

@bsodmike
Copy link
Contributor

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

3 participants