mirror of
https://github.com/m-labs/artiq.git
synced 2025-01-23 17:08:12 +08:00
80 lines
2.7 KiB
Python
80 lines
2.7 KiB
Python
from migen import *
|
|
from artiq.gateware.rtio import rtlink
|
|
|
|
|
|
class SimpleEdgeCounter(Module):
|
|
"""Counts rising/falling edges of an input signal.
|
|
|
|
Control (sensitivity/zeroing) is done via a single RTIO output channel,
|
|
which is is also used to request an input event to be emitted with the
|
|
current counter value.
|
|
|
|
:param input_state: The (scalar) input signal to detect edges of. This
|
|
should already be in the rio_phy clock domain.
|
|
:param counter_width: The width of the counter register, in bits. Defaults
|
|
to 31 to match integers being signed in ARTIQ Python.
|
|
"""
|
|
|
|
def __init__(self, input_state, counter_width=31):
|
|
assert counter_width >= 2
|
|
|
|
# RTIO interface:
|
|
# - output 0: 4 bits, <count_rising><count_falling><send_event><zero_counter>
|
|
# - input 0: 32 bits, accumulated edge count
|
|
self.rtlink = rtlink.Interface(
|
|
rtlink.OInterface(4, enable_replace=False),
|
|
rtlink.IInterface(counter_width))
|
|
|
|
# # #
|
|
|
|
current_count = Signal(counter_width)
|
|
|
|
count_rising = Signal()
|
|
count_falling = Signal()
|
|
send_event_stb = Signal()
|
|
zero_counter_stb = Signal()
|
|
|
|
# Read configuration from RTIO output events.
|
|
self.sync.rio += [
|
|
If(self.rtlink.o.stb,
|
|
count_rising.eq(self.rtlink.o.data[0]),
|
|
count_falling.eq(self.rtlink.o.data[1]),
|
|
send_event_stb.eq(self.rtlink.o.data[2]),
|
|
zero_counter_stb.eq(self.rtlink.o.data[3])
|
|
).Else(
|
|
send_event_stb.eq(0),
|
|
zero_counter_stb.eq(0)
|
|
)
|
|
]
|
|
|
|
# Generate RTIO input event with current count if requested.
|
|
event_data = Signal.like(current_count)
|
|
self.comb += [
|
|
self.rtlink.i.stb.eq(send_event_stb),
|
|
self.rtlink.i.data.eq(event_data)
|
|
]
|
|
|
|
# Keep previous input state for edge detection.
|
|
input_state_d = Signal()
|
|
self.sync.rio_phy += input_state_d.eq(input_state)
|
|
|
|
# Count input edges, saturating at the maximum.
|
|
new_count = Signal.like(current_count)
|
|
self.comb += new_count.eq(
|
|
current_count + Mux(current_count == 2**counter_width - 1,
|
|
0,
|
|
(count_rising & (input_state & ~input_state_d)) |
|
|
(count_falling & (~input_state & input_state_d))
|
|
)
|
|
)
|
|
|
|
self.sync.rio += [
|
|
event_data.eq(new_count),
|
|
current_count.eq(Mux(zero_counter_stb, 0, new_count))
|
|
]
|
|
|
|
|
|
if __name__ == '__main__':
|
|
input = Signal(name="input")
|
|
print(fhdl.verilog.convert(SimpleEdgeCounter(input)))
|