rust_hdl_widgets/
strobe.rs

1use rust_hdl_core::prelude::*;
2
3use crate::{dff::DFF, dff_setup};
4
5/// A [Strobe] generates a periodic pulse train, with a single clock-cycle wide pulse
6/// at the prescribed frequency.  The argument [N] of the generic [Strobe<N>] is used
7/// to size the counter that stores the internal delay value.  Unfortunately, Rust const
8/// generics are currently not good enough to compute [N] on the fly.  However, a compile
9/// time assert ensures that the number of clock cycles between pulses does not overflow
10/// the [N]-bit wide register inside the [Strobe].
11#[derive(Clone, Debug, LogicBlock)]
12pub struct Strobe<const N: usize> {
13    /// Set this to true to enable the pulse train.
14    pub enable: Signal<In, Bit>,
15    /// This is the strobing signal - it will fire for 1 clock cycle such that the strobe frequency is generated.
16    pub strobe: Signal<Out, Bit>,
17    /// The clock that drives the [Strobe].  All signals are synchronous to this clock.
18    pub clock: Signal<In, Clock>,
19    threshold: Constant<Bits<N>>,
20    counter: DFF<Bits<N>>,
21}
22
23impl<const N: usize> Strobe<N> {
24    /// Generate a [Strobe] widget that can be used in a RustHDL circuit.
25    ///
26    /// # Arguments
27    ///
28    /// * `frequency`: The frequency (in Hz) of the clock signal driving the circuit.
29    /// * `strobe_freq_hz`: The desired frequency in Hz of the output strobe.  Note that
30    /// the strobe frequency will be rounded to something that can be obtained by dividing
31    /// the input clock by an integer.  As such, it may not produce exactly the desired
32    /// frequency, unless `frequency`/`strobe_freq_hz` is an integer.
33    ///
34    /// returns: Strobe<{ N }>
35    ///
36    /// # Examples
37    ///
38    /// See [BlinkExample] for an example.
39    pub fn new(frequency: u64, strobe_freq_hz: f64) -> Self {
40        let clock_duration_femto = freq_hz_to_period_femto(frequency as f64);
41        let strobe_interval_femto = freq_hz_to_period_femto(strobe_freq_hz);
42        let interval = strobe_interval_femto / clock_duration_femto;
43        let threshold = interval.round() as u64;
44        assert!((threshold as u128) < (1_u128 << (N as u128)));
45        assert!(threshold > 2);
46        Self {
47            enable: Signal::default(),
48            strobe: Signal::default(),
49            clock: Signal::default(),
50            threshold: Constant::new(threshold.into()),
51            counter: Default::default(),
52        }
53    }
54}
55
56impl<const N: usize> Logic for Strobe<N> {
57    #[hdl_gen]
58    fn update(&mut self) {
59        // Connect the counter clock to my clock
60        dff_setup!(self, clock, counter);
61        if self.enable.val() {
62            self.counter.d.next = self.counter.q.val() + 1;
63        }
64        self.strobe.next = self.enable.val() & (self.counter.q.val() == self.threshold.val());
65        if self.strobe.val() {
66            self.counter.d.next = 1.into();
67        }
68    }
69}