Skip to content

Commit 46d9214

Browse files
WIP: applet.interface.freq_counter: implement basic frequency counter
This commit is work-in-progress: - Create `FrequencytCounterInterface` class - Add duration command line argument - longer run offers higher resolution - Clean up output
1 parent 7c76880 commit 46d9214

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

software/glasgow/applet/all.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .interface.jtag_svf import JTAGSVFApplet
1313
from .interface.ps2_host import PS2HostApplet
1414
from .interface.sbw_probe import SpyBiWireProbeApplet
15+
from .interface.freq_counter import FrequencyCounterApplet
1516

1617
from .memory._24x import Memory24xApplet
1718
from .memory._25x import Memory25xApplet
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import enum
2+
import asyncio
3+
import logging
4+
from nmigen import *
5+
6+
from ....gateware.pads import *
7+
from ....gateware.ripple import *
8+
from ....support.si_prefix import num_to_si
9+
from ... import *
10+
11+
12+
class _Command(enum.IntEnum):
13+
GO = 0x00
14+
15+
16+
class FrequencyCounterSubtarget(Elaboratable):
17+
def __init__(self, pads, clk_count, edge_count, running, out_fifo):
18+
self.pads = pads
19+
self.clk_count = clk_count
20+
self.edge_count = edge_count
21+
self.running = running
22+
self.out_fifo = out_fifo
23+
24+
def elaborate(self, platform):
25+
m = Module()
26+
27+
trigger = Signal()
28+
m.d.comb += [
29+
self.out_fifo.r_en.eq(self.out_fifo.r_rdy),
30+
trigger.eq(self.out_fifo.r_en & (self.out_fifo.r_data == _Command.GO)),
31+
]
32+
33+
clk_count = Signal.like(self.clk_count)
34+
with m.If(trigger):
35+
m.d.sync += clk_count.eq(self.clk_count)
36+
with m.Elif(clk_count > 0):
37+
m.d.sync += clk_count.eq(clk_count - 1)
38+
m.d.comb += self.running.eq(1)
39+
40+
m.submodules.ripple = RippleCounter(
41+
rst=trigger,
42+
clk=self.pads.i_t.i,
43+
clk_en=self.running,
44+
width=32,
45+
)
46+
m.d.comb += self.edge_count.eq(m.submodules.ripple.count)
47+
48+
return m
49+
50+
class FrequencyCounterApplet(GlasgowApplet, name="freq-counter"):
51+
logger = logging.getLogger(__name__)
52+
help = "frequency counter"
53+
description = """
54+
Simple frequency counter, based on a ripple counter.
55+
"""
56+
57+
@classmethod
58+
def add_build_arguments(cls, parser, access):
59+
super().add_build_arguments(parser, access)
60+
61+
access.add_pin_argument(parser, "i", default=True)
62+
63+
def build(self, target, args):
64+
self.mux_interface = iface = target.multiplexer.claim_interface(self, args)
65+
66+
reg_clk_count, self.__reg_clk_count = target.registers.add_rw(32)
67+
reg_edge_count, self.__reg_edge_count = target.registers.add_ro(32)
68+
reg_running, self.__reg_running = target.registers.add_ro(1)
69+
70+
subtarget = iface.add_subtarget(FrequencyCounterSubtarget(
71+
pads=iface.get_pads(args, pins=("i",)),
72+
clk_count=reg_clk_count,
73+
edge_count=reg_edge_count,
74+
running=reg_running,
75+
out_fifo=iface.get_out_fifo(),
76+
))
77+
78+
self.sys_clk_freq = target.sys_clk_freq
79+
80+
@classmethod
81+
def add_run_arguments(cls, parser, access):
82+
super().add_run_arguments(parser, access)
83+
84+
async def measure(self, device, args, clk_count):
85+
iface = await device.demultiplexer.claim_interface(self, self.mux_interface, args)
86+
87+
await device.write_register(self.__reg_clk_count, clk_count, width=4)
88+
89+
await iface.write([ _Command.GO ])
90+
await iface.flush()
91+
92+
while await device.read_register(self.__reg_running, width=1):
93+
await asyncio.sleep(0.1)
94+
95+
edge_count = await device.read_register(self.__reg_edge_count, width=4)
96+
97+
sample_duration = clk_count / self.sys_clk_freq
98+
signal_freq = edge_count / sample_duration
99+
100+
return signal_freq
101+
102+
async def run(self, device, args):
103+
signal_freq = await self.measure(device, args, int(self.sys_clk_freq * 2))
104+
print('signal frequency: {:>7.3f} {:1}Hz'.format( *num_to_si(signal_freq) ))

0 commit comments

Comments
 (0)