From cb1ccf098b00bcf1c01bb23b2ef3c9a7e612c56d Mon Sep 17 00:00:00 2001 From: Matt Johnston <matt@ucc.asn.au> Date: Fri, 7 Oct 2022 23:28:51 +0800 Subject: [PATCH] Switch to AnyPin etc Add histogram. Doesn't seem to be working though --- Cargo.toml | 10 +++- examples/noise.rs | 108 ++++++++++++++++++++++++++++++--- src/cap.rs | 150 ++++++++++++++++++++++++---------------------- src/lib.rs | 1 + src/rng.rs | 20 +++---- 5 files changed, 196 insertions(+), 93 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3ea912a..79052f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,10 @@ debug = 2 [patch.crates-io] # embassy isn't released to crates.io yet -embassy-rp = { git = "https://github.com/embassy-rs/embassy", rev = "1d6f5493e7764767eb592e0b90d6b07d46b100ca" } -embassy-executor = { git = "https://github.com/embassy-rs/embassy", rev = "1d6f5493e7764767eb592e0b90d6b07d46b100ca" } -embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "1d6f5493e7764767eb592e0b90d6b07d46b100ca" } +# embassy-rp = { git = "https://github.com/embassy-rs/embassy", rev = "1d6f5493e7764767eb592e0b90d6b07d46b100ca" } +# embassy-executor = { git = "https://github.com/embassy-rs/embassy", rev = "1d6f5493e7764767eb592e0b90d6b07d46b100ca" } +# embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "1d6f5493e7764767eb592e0b90d6b07d46b100ca" } + +embassy-rp = { path = "/home/matt/3rd/rs/embassy/embassy-rp" } +embassy-executor = { path = "/home/matt/3rd/rs/embassy/embassy-executor" } +embassy-time = { path = "/home/matt/3rd/rs/embassy/embassy-time" } diff --git a/examples/noise.rs b/examples/noise.rs index 24e83a1..c089326 100644 --- a/examples/noise.rs +++ b/examples/noise.rs @@ -14,7 +14,8 @@ use defmt::{debug, info, warn, panic, error}; #[cfg(feature = "defmt")] use {defmt_rtt as _, panic_probe as _}; -use embassy_rp::gpio::Flex; +use embassy_rp::gpio::{Flex, AnyPin, Pin}; +use embassy_rp::Peripheral; use embassy_executor::Spawner; #[embassy_executor::main] @@ -22,11 +23,102 @@ async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let mut cp = cortex_m::peripheral::Peripherals::take().unwrap(); - let mut gpio = (Flex::new(p.PIN_10), 10); - // let mut gpio = (Flex::new(p.PIN_22), 22); - caprand::noise(&mut gpio.0, gpio.1, &mut cp.SYST, - |v, overshoot| { - info!("{} {}", v, overshoot); - true - }).unwrap(); + // 0.1uF + // let mut gpio = (Flex::new(p.PIN_6), 6); + // 0.01uF ? + // let mut gpio = (Flex::new(p.PIN_10), 10); + // nothing + // let mut gpio = Flex::new(p.PIN_22); + // nothing, adc pin + // let mut gpio = (Flex::new(p.PIN_28), 28); + + // let mut gpio = (Flex::new(p.PIN_15), 15); + + // // wifi sd_clk, or led for non-w + // let mut gpio = (Flex::new(p.PIN_29), 29); + // // check wifi is off. + // let mut gpio23 = Flex::new(p.PIN_23); + // assert!(gpio23.is_low()); + // // wifi cs high + // let mut gpio25 = Flex::new(p.PIN_25); + // gpio25.set_low(); + // gpio25.set_as_output(); + + // let mut gpio = Flex::new(p.PIN_15); + // let mut gpio = Flex::new(p.PIN_20); + // let mut gpio = p.PIN_20.into(); + + let mut hist = [0u32; 200]; + let mut n = 0; + + let PRINT = 50000; + // let PRINT = 50; + + let mut gpios = [ + p.PIN_6.degrade().into_ref(), + p.PIN_10.degrade().into_ref(), + p.PIN_13.degrade().into_ref(), + p.PIN_22.degrade().into_ref(), + // p.PIN_23.degrade().into_ref(), + // p.PIN_24.degrade().into_ref(), + p.PIN_25.degrade().into_ref(), + ]; + + // let mut gpios = [ + // p.PIN_0.degrade().into_ref(), + // p.PIN_1.degrade().into_ref(), + // p.PIN_2.degrade().into_ref(), + // p.PIN_3.degrade().into_ref(), + // p.PIN_4.degrade().into_ref(), + // p.PIN_5.degrade().into_ref(), + // p.PIN_6.degrade().into_ref(), + // p.PIN_7.degrade().into_ref(), + // p.PIN_8.degrade().into_ref(), + // p.PIN_9.degrade().into_ref(), + // p.PIN_10.degrade().into_ref(), + // p.PIN_11.degrade().into_ref(), + // p.PIN_12.degrade().into_ref(), + // p.PIN_13.degrade().into_ref(), + // p.PIN_14.degrade().into_ref(), + // p.PIN_15.degrade().into_ref(), + // p.PIN_16.degrade().into_ref(), + // p.PIN_17.degrade().into_ref(), + // p.PIN_18.degrade().into_ref(), + // p.PIN_19.degrade().into_ref(), + // p.PIN_20.degrade().into_ref(), + // p.PIN_21.degrade().into_ref(), + // p.PIN_22.degrade().into_ref(), + // // p.PIN_23.degrade().into_ref(), + // // p.PIN_24.degrade().into_ref(), + // p.PIN_25.degrade().into_ref(), + // p.PIN_26.degrade().into_ref(), + // p.PIN_27.degrade().into_ref(), + // p.PIN_28.degrade().into_ref(), + // // p.PIN_29.degrade().into_ref(), + // ]; + + for gpio in gpios.iter_mut() { + let pin = gpio.pin(); + caprand::noise(gpio.reborrow(), &mut cp.SYST, + |v, overshoot| { + // info!("{}", v); + + let vu = v as usize; + hist[vu.min(hist.len()-1)] += 1; + n += 1; + if n % PRINT == 0 { + info!("gpio {} iter {}", pin, n); + for (p, h) in hist.iter_mut().enumerate() { + if *h > 0 { + info!("{}: {}", p, h); + *h = 0; + } + } + false + } else { + true + } + }).unwrap(); + } + } diff --git a/src/cap.rs b/src/cap.rs index a5be1ca..07cfcb1 100644 --- a/src/cap.rs +++ b/src/cap.rs @@ -7,8 +7,8 @@ use defmt::{error, debug, info, panic}; use core::arch::asm; use cortex_m::peripheral::SYST; -use embassy_rp::gpio::{Flex, Pin, Pull}; -use embassy_rp::pac; +use embassy_rp::gpio::{Flex, Pin, Pull, AnyPin}; +use embassy_rp::{pac, Peripheral, PeripheralRef}; /// _ still pullup, =up_x /// t3 t4 t1 t2 / @@ -64,8 +64,8 @@ GPIO13 // const LOW_OVER: u32 = 1000; // // Power of two for faster modulo // const HIGH_OVER: u32 = LOW_OVER + 1023; -const LOW_OVER: u32 = 0; -const HIGH_OVER: u32 = 0; +const LOW_OVER: u32 = 100; +const HIGH_OVER: u32 = 100; // Assume worst case from rp2040 datasheet. // 3.3v vdd, 2v logical high voltage, 50kohm pullup, 0.01uF capacitor, 125Mhz clock. @@ -103,56 +103,40 @@ impl<'t> SyTi<'t> { Ok(self.t1 - t2) } } +// Returns (ticks: u32, precise: bool) +fn time_rise(pin: PeripheralRef<AnyPin>, wait: &mut u32, rpos: &mut u32, syst: &mut SYST) -> Result<(u32, bool), ()> { - -/// Equivalent to -/// `while gpioN.is_high() {}` -/// but with known 4 cycle loop time (vs 26 cycles for the `while` loop at -/// at time of writing) -fn time_fall(pin_num: usize, syst: &mut SYST) -> Result<u32, ()> { + let pin_num = pin.pin(); // bank 0 single cycle IO in let gpio_in = pac::SIO.gpio_in(0).ptr(); let mask = 1u32 << pin_num; - let t = SyTi::new(syst); + + let so = pac::SIO.gpio_out(0); + let soe = pac::SIO.gpio_oe(0); unsafe { - asm!( - "222:", - // read gpio_in register, 1 cycle - "ldr {tmp}, [{gpio_in}]", - // AND with the desired pin bit, 1 cycle - "ands {tmp}, {mask}", - // loop if bit set, 2 cycles - "bne 222b", - tmp = out(reg) _, - mask = in(reg) mask, - gpio_in = in(reg) gpio_in, - options(nostack, readonly), - ); + so.value_clr().write_value(1<<pin_num); + soe.value_set().write_value(1<<pin_num); } - t.done() -} - -// Returns (ticks: u32, precise: bool) -fn time_fall_unroll(pin_num: usize, syst: &mut SYST) -> Result<(u32, bool), ()> { - // bank 0 single cycle IO in - let gpio_in = pac::SIO.gpio_in(0).ptr(); - let mask = 1u32 << pin_num; - - // let so = pac::SIO.gpio_out(0); - // let soe = pac::SIO.gpio_out(0); - // unsafe { - // so.value_set().write_value(1<<pin_num); - // soe.value_set().write_value(1<<pin_num); - // } - // cortex_m::asm::delay(10000); // unsafe { - // soe.value_clr().write_value(1<<pin_num); + // asm!( + // "nop", + // ) // } + // cortex_m::asm::delay(200); + cortex_m::asm::delay(1000); + unsafe { + soe.value_clr().write_value(1<<pin_num); + } + // for testing with logic analyzer // let mut out = Flex::new(unsafe { embassy_rp::peripherals::PIN_16::steal() }); // out.set_as_output(); // so.value_clr().write_value(1<<16); + // pin.set_pull(Pull::Down); + // cortex_m::asm::delay(900); + // pin.set_pull(Pull::None); + let t = SyTi::new(syst); let x0: u32; @@ -161,6 +145,8 @@ fn time_fall_unroll(pin_num: usize, syst: &mut SYST) -> Result<(u32, bool), ()> let x3: u32; let x4: u32; let x5: u32; + let mut gpio = Flex::<AnyPin>::new(pin); + gpio.set_pull(Pull::Up); unsafe { asm!( // save @@ -177,7 +163,7 @@ fn time_fall_unroll(pin_num: usize, syst: &mut SYST) -> Result<(u32, bool), ()> // only test the most recent sample. 1 cycle "ands r7, {mask}", // Loop if bit set, 2 cycles - "bne 222b", + "beq 222b", // return last sample in x5 "mov {mask}, r7", @@ -198,38 +184,45 @@ fn time_fall_unroll(pin_num: usize, syst: &mut SYST) -> Result<(u32, bool), ()> let tick = t.done()?; - let pos = if x0 & mask == 0 { + let pos = if x0 & mask != 0 { 0 - } else if x1 & mask == 0 { + } else if x1 & mask != 0 { 1 - } else if x2 & mask == 0 { + } else if x2 & mask != 0 { 2 - } else if x3 & mask == 0 { + } else if x3 & mask != 0 { 3 - } else if x4 & mask == 0 { + } else if x4 & mask != 0 { 4 - } else if x5 & mask == 0 { + } else if x5 & mask != 0 { 5 } else { 6 }; let tick = tick + pos; - // let precise = pos != 0; - let precise = true; + // first measurement is less precise. + let precise = pos != 0; + + if tick > 600 { + *wait = wait.saturating_sub(1); + } else if tick > 600 { + *wait = (*wait+1).max(10000); + } + *rpos = pos; Ok((tick, precise)) } // `f()` is called on each output `u32`. -pub fn noise<'d, P: Pin, F>( - pin: &mut Flex<'d, P>, - pin_num: usize, +pub fn noise<'d, F>( + mut pin: PeripheralRef<AnyPin>, syst: &mut SYST, mut f: F, ) -> Result<(), ()> where F: FnMut(u32, u32) -> bool, { + let pin_num = pin.pin() as usize; syst.set_clock_source(cortex_m::peripheral::syst::SystClkSource::Core); // prescribed sequence for setup syst.set_reload(10_000_000 - 1); @@ -248,20 +241,22 @@ where .modify(|s| s.set_schmitt(false)) }; - // Measure pulldown time from vcc as a sanity check - pin.set_as_output(); - pin.set_high(); - // Long enough to drive the capacitor high + let mut gpio = Flex::<AnyPin>::new(pin.reborrow()); + // Measure pullup time from 0 as a sanity check + gpio.set_as_output(); + gpio.set_low(); + // Long enough to drive the capacitor low cortex_m::asm::delay(10000); - pin.set_as_input(); + gpio.set_as_input(); let del = critical_section::with(|_cs| { - pin.set_pull(Pull::Down); + gpio.set_pull(Pull::Up); let t = SyTi::new(syst); // Get it near the threshold to begin. - while pin.is_high() {} + while gpio.is_low() {} t.done() })?; - info!("Initial pulldown del is {}", del); + drop(gpio); + // info!("Initial pullup del is {}", del); if del < MIN_CAPACITOR_DEL { error!("Capacitor seems small or missing?"); @@ -272,6 +267,8 @@ where let mut overshoot = 1u32; let mut warming = WARMUP; + let mut wait = 0; + let mut pos = 0; // After warmup we sample twice at each "overshoot" value. // One sample is returned as random output, the other is mixed @@ -279,28 +276,37 @@ where for (i, _) in core::iter::repeat(()).enumerate() { let (meas, precise) = critical_section::with(|_cs| { - pin.set_pull(Pull::Up); - while pin.is_low() {} - // Keep pulling up for `overshoot` cycles - cortex_m::asm::delay(overshoot); + // pin.set_pull(Pull::Down); + // // let t = SyTi::new(syst); + // while pin.is_high() {} + // // let ticks = t.done()?; + // // Keep pulling down for `overshoot` cycles + // cortex_m::asm::delay(overshoot); - // Pull down, time how long to reach threshold - pin.set_pull(Pull::Down); + // // Pull up, time how long to reach threshold + // pin.set_pull(Pull::None); + // debug!("pulldown {}", ticks); // let t = SyTi::new(syst); // while pin.is_high() {} // let r = t.done().map(|t| (t, true)); - let r = time_fall_unroll(pin_num, syst); + let (r, precise) = time_rise(pin.reborrow(), &mut wait, &mut pos, syst)?; + + let mut gpio = Flex::<AnyPin>::new(pin.reborrow()); + gpio.set_pull(Pull::None); + + // if (r > ) + - pin.set_pull(Pull::None); - r + Ok((r, precise)) })?; if i % 2 == 0 { // real output - if precise && warming == 0 { - if !f(meas, overshoot) { + // if precise && warming == 0 { + if warming == 0 { + if !f(meas, pos) { // no more output wanted break } diff --git a/src/lib.rs b/src/lib.rs index 0a53d3a..f57abc6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ use log::error; mod rng; mod cap; +// mod numpin; pub use rng::{setup, random}; pub use cap::noise; diff --git a/src/rng.rs b/src/rng.rs index cc5377a..8120373 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -13,10 +13,12 @@ use rand_chacha::ChaCha20Rng; use sha2::{Digest, Sha256}; use cortex_m::peripheral::SYST; -use embassy_rp::gpio::{Flex, Pin}; +use embassy_rp::gpio::{Flex, Pin, Pull, AnyPin}; +use embassy_rp::{pac, Peripheral, PeripheralRef}; use rand_chacha::rand_core::{RngCore, SeedableRng}; + // arbitrary constant pub const CAPRAND_ERR: u32 = getrandom::Error::CUSTOM_START + 510132368; @@ -45,12 +47,11 @@ pub fn random(buf: &mut [u8]) -> Result<(), getrandom::Error> { /// Call this at early startup. If noisy interrupts or time slicing is happening the caller /// should disable interrupts. /// `syst` will be modified. -pub fn setup<P: Pin>( - pin: &mut Flex<P>, - pin_num: usize, +pub fn setup( + pin: PeripheralRef<AnyPin>, syst: &mut SYST, ) -> Result<(), getrandom::Error> { - let r = CapRng::new(pin, pin_num, syst)?; + let r = CapRng::new(pin, syst)?; critical_section::with(|cs| { let mut rng = RNG.borrow_ref_mut(cs); @@ -64,19 +65,18 @@ pub fn setup<P: Pin>( struct CapRng(ChaCha20Rng); impl CapRng { - const SEED_SAMPLES: usize = 1024; + // const SEED_SAMPLES: usize = 1024; + const SEED_SAMPLES: usize = 50000; /// Call this at early startup. If noisy interrupts or time slicing is happening the caller /// should disable interrupts. /// `syst` will be modified. - fn new<P: Pin>( - pin: &mut Flex<P>, - pin_num: usize, + fn new(pin: PeripheralRef<AnyPin>, syst: &mut SYST, ) -> Result<Self, getrandom::Error> { let mut h = Sha256::new(); let mut count = 0; - crate::cap::noise(pin, pin_num, syst, |v, _over| { + crate::cap::noise(pin, syst, |v, _over| { h.update(v.to_be_bytes()); count += 1; count < Self::SEED_SAMPLES -- GitLab