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}