Open darkwater opened 4 months ago
Interestingly, I can make the buffer larger, and the first call will still work, unless I make it too large; it breaks somewhere between 850 and 900 bytes. But the second call never works.
Actually, if it breaks from large buffer, the only log output I see (defmt level trace) is "calling", no hello world or flash/rcc debug info. Maybe some memory corruption is going on?
Hello. Maybe stupid question, but did you set right chip feature for crate embassy-stm32 in Cargo.toml? Something similar happened to me, when I copied local project a forgot to change feature from stm32f412re to stm32f411ce. Then it did hang on Timer::after_secs(1).await ...
Yeah, everything's configured properly for my chip. The only thing I'm not sure about is the RCC configuration, but it seems like all the RNG needs it the HSI48 input.
Something I noticed in Rng::reset()
:
/// Reset the RNG.
#[cfg(rng_v1)]
pub fn reset(&mut self) {
T::regs().cr().write(|reg| {
reg.set_rngen(false);
});
T::regs().sr().modify(|reg| {
reg.set_seis(false);
reg.set_ceis(false);
});
T::regs().cr().modify(|reg| {
reg.set_rngen(true);
});
// Reference manual says to discard the first.
let _ = self.next_u32();
}
The reference manual for the STM32H723/733, STM32H725/735 and STM32H730 doesn't mention anything about discarding the first sample after a reset. If I comment out that line, it doesn't immediately break after the first async_fill_bytes
.
However, after a while, a seed error will still occur, and it gets stuck at waiting for SECS to be cleared:
/// Try to recover from a seed error.
pub fn recover_seed_error(&mut self) {
self.reset();
// reset should also clear the SEIS flag
if T::regs().sr().read().seis() {
warn!("recovering from seed error failed");
return;
}
// wait for SECS to be cleared by RNG
while T::regs().sr().read().secs() {}
}
Looks like the sequence to recover from a seed error is different too:
The following sequence must be used to fully recover from a seed error:
- Software reset by writing CONDRST at 1 and at 0 (see bitfield description for details).
- wait for CONDRST to be cleared in the RNG_CR register, then confirm that SEIS is cleared in the RNG_SR register.
- wait for SECS to be cleared by RNG. The random number generation is now back to normal.
The following implementation seems to work:
/// Try to recover from a seed error.
#[cfg(feature = "stm32h723zg")]
pub fn recover_seed_error(&mut self) {
// set CONDRST = 1
T::regs().cr().write(|r| r.0 |= 1 << 30);
// set CONDRST = 0
T::regs().cr().write(|r| r.0 &= !(1 << 30));
// wait for CONDRST to be reset
while T::regs().cr().read().0 & (1 << 30) != 0 {}
T::regs().sr().modify(|r| {
if r.seis() {
// clear SEIS
r.set_seis(false)
}
});
// wait for SECS to be cleared
while T::regs().sr().read().secs() {}
// EDIT: a reset is also needed
self.reset();
}
Looks like it's just a different version of the RNG? I'm not sure how to implement that properly.
I'm using STM32H723VG on a custom board and the RNG works normally. Can you check your clock config for RNG is correct? (config.rcc.mux.rngsel
when you run embassy_stm32::init
)
I dont understand clock configs very well, this is what I've got:
let p = embassy_stm32::init({
let mut hal_config = embassy_stm32::Config::default();
hal_config.enable_debug_during_sleep = true;
hal_config.rcc.hsi = Some(HSIPrescaler::DIV1);
hal_config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: false });
hal_config.rcc.mux.rngsel = Rngsel::HSI48;
hal_config.rcc.csi = true;
hal_config.rcc.pll1 = Some(Pll {
source: PllSource::HSI,
prediv: PllPreDiv::DIV4,
mul: PllMul::MUL50,
divp: Some(PllDiv::DIV2),
divq: Some(PllDiv::DIV8),
divr: None,
});
hal_config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
hal_config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
hal_config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
hal_config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
hal_config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
hal_config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
hal_config.rcc.voltage_scale = VoltageScale::Scale1;
hal_config
});
But either way, the logic I'm seeing in the current Embassy implementation doesn't match what I'm reading in the reference manual, and the function I provided does work. Maybe the current implementation happens to works under some circumstances?
I have a STM32H723VG on a custom board, and I am seeing the same behaviour as @darkwater.
This is my clock config:
let mut config = Config::default();
{
use embassy_stm32::rcc::mux::*;
use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.hse = Some(Hse {
freq: mhz(16),
mode: HseMode::Oscillator,
});
config.rcc.csi = false;
config.rcc.hsi48 = Some(Hsi48Config {
sync_from_usb: false,
});
config.rcc.ls = LsConfig::default_lsi();
config.rcc.pll1 = Some(Pll {
source: PllSource::HSE,
prediv: PllPreDiv::DIV1,
mul: PllMul::MUL32,
divp: Some(PllDiv::DIV1),
divq: Some(PllDiv::DIV4),
divr: Some(PllDiv::DIV2),
});
config.rcc.pll2 = Some(Pll {
source: PllSource::HSE,
prediv: PllPreDiv::DIV1,
mul: PllMul::MUL20,
divp: Some(PllDiv::DIV8),
divq: Some(PllDiv::DIV2),
divr: Some(PllDiv::DIV2),
});
config.rcc.pll3 = Some(Pll {
source: PllSource::HSE,
prediv: PllPreDiv::DIV1,
mul: PllMul::MUL24,
divp: Some(PllDiv::DIV2),
divq: Some(PllDiv::DIV8),
divr: Some(PllDiv::DIV2),
});
config.rcc.sys = Sysclk::PLL1_P;
config.rcc.d1c_pre = AHBPrescaler::DIV1;
config.rcc.apb1_pre = APBPrescaler::DIV2;
config.rcc.apb2_pre = APBPrescaler::DIV2;
config.rcc.apb3_pre = APBPrescaler::DIV2;
config.rcc.apb4_pre = APBPrescaler::DIV2;
config.rcc.ahb_pre = AHBPrescaler::DIV2;
config.rcc.voltage_scale = VoltageScale::Scale0;
config.rcc.mux.spi123sel = Saisel::PLL1_Q;
config.rcc.mux.usart234578sel = Usart234578sel::PCLK1;
config.rcc.mux.rngsel = Rngsel::HSI48;
config.rcc.mux.i2c4sel = I2c4sel::PCLK4;
config.rcc.mux.i2c1235sel = I2c1235sel::PCLK1;
config.rcc.mux.spi6sel = Spi6sel::PCLK4;
config.rcc.mux.spi45sel = Spi45sel::PCLK2;
config.rcc.mux.adcsel = Adcsel::PLL2_P;
config.rcc.mux.fdcansel = Fdcansel::PLL1_Q;
config.rcc.mux.usbsel = Usbsel::PLL3_Q;
}
let p = embassy_stm32::init(config);
On an STM32H723ZG, Rng seems to lock up after the first call.
Tested using the rng example, by wrapping the call in a loop:
Output:
Tested on a Nucleo-H723ZG, with some stuff connected, but that shouldn't affect the RNG I believe.