esp-hal
esp-hal copied to clipboard
Feature: correct TRNG mechanism
Thank you for your contribution!
We appreciate the time and effort you've put into this pull request. To help us review it efficiently, please ensure you've gone through the following checklist:
Submission Checklist 📝
- [x] I have updated existing examples or added new ones (if applicable).
- [x] My changes were added to the
CHANGELOG.md
in the proper section.\
Pull Request Details 📖
Description
Based on what's discussed in #1499 and previous related issues, created a TRNG struct, which takes RNG peripheral and ADC instance. Working on using ADC peripheral instead of instance, this will be draft until it's done
Testing
#![no_std]
#![no_main]
use esp_backtrace as _;
use esp_hal::{prelude::*, rng::Trng,
analog::adc::{AdcConfig, Attenuation, ADC},
clock::ClockControl,
delay::Delay,
gpio::IO,
peripherals::{Peripherals, ADC1}};
use esp_println::println;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let analog_pin = io.pins.gpio3.into_analog();
let mut adc1_config = AdcConfig::new();
let mut adc1_pin = adc1_config.enable_pin(analog_pin, Attenuation::Attenuation11dB);
let mut adc1 = ADC::<ADC1>::new(peripherals.ADC1, adc1_config);
let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap();
let mut trng = Trng::new(peripherals.RNG, &mut adc1);
let (mut rng, adc1) = trng.downgrade();
// Fill a buffer with random bytes:
let mut buf = [0u8; 16];
// trng.read(&mut buf);
println!("Random bytes: {:?}", buf);
loop {
println!("Random u32: {}", rng.random());
let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap();
println!("ADC reading = {}", pin_value);
}
}
I guess Trng should implement https://docs.rs/rand_core/0.6.4/rand_core/trait.CryptoRngCore.html not just CryptRng
Would deserve some docs (but I see this is draft so you probably already thought about that)
According to rand_core
docs:
CryptoRngCore An extension trait that is automatically implemented for any type implementing RngCore and CryptoRng.
According to
rand_core
docs: CryptoRngCore An extension trait that is automatically implemented for any type implementing RngCore and CryptoRng.
But RngCore isn't implemented? Maybe the diff looks weird for me
Oh, I did it, but maybe it's lost in another branch 😄. Will double check when I'm near my PC again.
Looks good! Thanks for your continuous effort here. I think we should address the comment about the example code but otherwise looks good to me
I tested on hardware and with ADC example changed to this:
//! Connect a potentiometer to an IO pin and see the read values change when
//! rotating the shaft.
//!
//! Alternatively, you could also connect the IO pin to GND or 3V3 to see the
//! maximum and minimum raw values read.
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use esp_backtrace as _;
use esp_hal::{
analog::adc::{Adc, AdcConfig, Attenuation},
clock::ClockControl,
delay::Delay,
gpio::Io,
peripherals::Peripherals,
prelude::*,
rng::Trng,
system::SystemControl,
};
use esp_println::println;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
cfg_if::cfg_if! {
if #[cfg(feature = "esp32")] {
let analog_pin = io.pins.gpio32;
} else if #[cfg(any(feature = "esp32s2", feature = "esp32s3"))] {
let analog_pin = io.pins.gpio3;
} else {
let analog_pin = io.pins.gpio2;
}
}
let mut adc = peripherals.ADC1;
let mut trng = esp_hal::rng::Trng::new(peripherals.RNG, &mut adc);
let mut buff = [0u8; 32];
trng.read(&mut buff);
println!("{:?}", buff);
core::mem::drop(trng);
// Create ADC instances
let mut adc1_config = AdcConfig::new();
let mut adc1_pin = adc1_config.enable_pin(analog_pin, Attenuation::Attenuation11dB);
let mut adc1 = Adc::new(&mut adc, adc1_config);
let delay = Delay::new(&clocks);
loop {
let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap();
println!("ADC reading = {}", pin_value);
delay.delay_millis(1500);
}
}
The C6 reads 0 once and then dies. Looks good on all other targets for me
The C6 reads 0 once and then dies. Looks good on all other targets for me.
After some tests, it turned out that there's a same issue in esp-idf
as well. I've created an issue there already: https://github.com/espressif/esp-idf/issues/14124
All the limitations for esp32c6
are temporary since at this moment user cannot use ADC
after TRNG
is dropped (see https://github.com/espressif/esp-idf/issues/14124)
We probably should document that calling core::mem:drop
on Trng
on ESP32-C6 will result in ADC1 being still unusable for now