Open birdistheword96 opened 6 months ago
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.
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();
}
}
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
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
.
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'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.
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.
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:
!PWR.csr1().read().actvosrdy() {}
in thercc::init
function.