Skip to content

Commit 6059bda

Browse files
committed
add register for adc readout
1 parent 72ec22a commit 6059bda

4 files changed

Lines changed: 154 additions & 58 deletions

File tree

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
/build
22
/py
3+
/__pycache__/
4+
/.pytest_cache/
5+
*.jou
6+
*.log
7+
*.vcd
8+
*.gtkw

iir.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@ def __init__(self):
2121
self.p = p = Signal((48, True), reset_less=True)
2222
self.sync += [m.eq(a * b), p.eq(m + c), If(mux_p, p.eq(m + p))]
2323

24-
2524
class Iir(Module):
2625
def __init__(self, w_coeff, w_data, log2_a0, n_profiles, n_channels):
26+
"""
27+
w_coeff: 16 bits
28+
w_data: ADC_DATA_WIDTH = 16 bits
29+
log2_a0: log2 of a0 coefficient = 14 bits
30+
n_profiles: number of filter profiles = 4
31+
n_channels: number of channels = 2
32+
"""
2733
# input strobe signal (start processing all channels)
2834
self.stb_in = stb_in = Signal()
2935
self.stb_out = stb_out = Signal() # output strobe signal (all channels done)
@@ -77,21 +83,22 @@ def __init__(self, w_coeff, w_data, log2_a0, n_profiles, n_channels):
7783
self.submodules.dsp = dsp = Dsp()
7884
assert w_data <= len(dsp.b)
7985
assert w_coeff <= len(dsp.a)
80-
shift_c = len(dsp.a) + len(dsp.b) - w_data - (w_data - log2_a0)
81-
shift_a = len(dsp.a) - w_coeff
82-
shift_b = len(dsp.b) - w_data
86+
# shift_c = len(dsp.a) + len(dsp.b) - w_data - (w_data - log2_a0) # 25 bits without -9; 16 bits with -9
87+
shift_a = len(dsp.a) - w_coeff # 25-16 = 9 bits
88+
shift_b = len(dsp.b) - w_data # 18-16 = 2 bits
89+
shift_c = shift_a + shift_b # 9+2 = 11 bits
8390
# +1 from standard sign bit
84-
n_sign = len(dsp.p) - len(dsp.a) - len(dsp.b) + w_data - log2_a0 + 1
85-
c_rounding_offset = Constant((1 << shift_c - 1) - 1, shift_c)
91+
n_sign = len(dsp.p) - len(dsp.a) - len(dsp.b) + w_data - log2_a0 + 1 # 48-25-18+16-14+1 = 8 bits
92+
c_rounding_offset = Constant((1 << shift_c - 1) - 1, shift_c) # 25 or 16 bits of 1s depending on -9
8693

8794
self.sync += [
8895
# default to 0 and set to 1 further down if computation done in this cycle
8996
stb_out.eq(0),
90-
dsp.a.eq(coeff[step][profile_index][channel_index] << shift_a),
97+
dsp.a.eq(coeff[step][profile_index][channel_index] << shift_a), # 16 bits + 9 bits shift = 25 bits
9198
dsp.b.eq(
92-
x[channel_index][step] << shift_b
99+
x[channel_index][step] << shift_b # 16+2=18 bits
93100
), # overwritten later if at step==2
94-
dsp.c.eq(Cat(c_rounding_offset, offset[profile_index][channel_index])),
101+
dsp.c.eq(Cat(c_rounding_offset, offset[profile_index][channel_index])), # 16 bit offset + 25 bits rounding offsets = 41 bits
95102
If(
96103
stb_in & ~busy,
97104
busy.eq(1),
@@ -132,10 +139,10 @@ def __init__(self, w_coeff, w_data, log2_a0, n_profiles, n_channels):
132139
ch_profile_last_ch.eq(ch_profile[channel_index - 1]),
133140
[o.eq(y1[ch_profile[ch]][ch]) for ch, o in enumerate(outp)],
134141
# clipping to positive output range
135-
y0_clipped.eq(dsp.p >> shift_c),
142+
y0_clipped.eq(dsp.p >> (shift_c+22)), # 48 bit - 11 bits = 37 bits
136143
If(
137-
dsp.p[-n_sign:] != 0, # if out of output range
138-
y0_clipped.eq((1 << w_data - 1) - 1),
144+
dsp.p[-n_sign:] != 0, # dsp.p[47:40] != 0
145+
y0_clipped.eq((1 << w_data - 1) - 1), # 16-1 bits -1 = 32767
139146
),
140147
If(dsp.p[-1] != 0, y0_clipped.eq(0)), # if negative
141148
]

phaser.py

Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
SERVO_PROFILES = 4 # number iir coefficient profiles per servo channel
1313
SERVO_CHANNELS = 2 # number servochannels
1414

15+
ADC_DATA_WIDTH = 16 # bits per adc channel
1516

1617
class PWM(Module):
1718
"""Pulse width modulation"""
@@ -46,6 +47,7 @@ def __init__(self, platform):
4647
platform.add_period_constraint(eem.data0_p, 4.0 * 8)
4748
self.submodules.crg = CRG(platform, link=self.link.phy.clk)
4849
# Don't bother meeting s/h for the clk iserdes. We align it.
50+
platform.add_false_path_constraint(eem.data0_p, self.crg.cd_sys.clk)
4951
platform.add_false_path_constraint(eem.data0_p, self.crg.cd_sys2.clk)
5052
self.submodules.decoder = Decode(
5153
b_sample=14, n_channel=2, n_mux=8, t_frame=8 * 10
@@ -154,6 +156,27 @@ def __init__(self, platform):
154156
Register(read=False),
155157
)
156158
)
159+
160+
# place holder for miqro register
161+
# 0x72 - 0x78 Miqro channel profile/window memories
162+
for i in range(7):
163+
phaser_registers.append(
164+
(
165+
f"miqro_mem{i}",
166+
Register(),
167+
)
168+
)
169+
170+
# add adc data registers
171+
# 0x79-0x7c
172+
for ch in range(SERVO_CHANNELS):
173+
for loc in ["lo", "hi"]:
174+
phaser_registers.append(
175+
(
176+
f"adc_data{ch}_{loc}",
177+
Register(write=False),
178+
)
179+
)
157180

158181
self.decoder.map_registers(phaser_registers)
159182

@@ -242,7 +265,7 @@ def __init__(self, platform):
242265
# Note that there is one extra cycle (4 ns) at the end of a transaction.
243266
# Total: 264 ns -> 3.788 MSps
244267
adc_parameters = AdcParams(
245-
width=16, channels=2, lanes=2, t_cnvh=8, t_conv=3, t_rtt=6
268+
width=ADC_DATA_WIDTH, channels=2, lanes=2, t_cnvh=8, t_conv=3, t_rtt=6
246269
)
247270

248271
self.submodules.adc = adc = Adc(platform.request("adc"), adc_parameters)
@@ -255,8 +278,8 @@ def __init__(self, platform):
255278

256279
# log2_a0 = 14 bit for an effective fixedpoint a0 of 0.5
257280
self.submodules.iir = iir = Iir(
258-
w_coeff=16,
259-
w_data=16,
281+
w_coeff=16,
282+
w_data=ADC_DATA_WIDTH,
260283
log2_a0=14,
261284
n_profiles=SERVO_PROFILES,
262285
n_channels=SERVO_CHANNELS,
@@ -266,6 +289,23 @@ def __init__(self, platform):
266289
iir.stb_in.eq(adc.done),
267290
]
268291

292+
# add adc data to adc data register
293+
for ch in range(SERVO_CHANNELS):
294+
assert SERVO_CHANNELS <= len(adc.data)
295+
sample_reg = Signal((16, True), name=f"adc_sample_reg_{ch}")
296+
self.sync += If(adc.done, sample_reg.eq(adc.data[ch]))
297+
# self.sync += If(adc.done, sample_reg.eq(0xFFFF))
298+
299+
# expose the registered value to the decoder read ports combinatorially
300+
# split into low / high bytes to match the two Register() entries
301+
self.comb += [
302+
self.decoder.get(f"adc_data{ch}_lo", "read").eq(sample_reg[0:8]),
303+
self.decoder.get(f"adc_data{ch}_hi", "read").eq(sample_reg[8:16]),
304+
# self.decoder.get(f"adc_data{ch}_lo", "read").eq(0xaa),
305+
# self.decoder.get(f"adc_data{ch}_hi", "read").eq(0xbb),
306+
]
307+
308+
269309
# connect iir to servo data registers
270310
for i in range(SERVO_CHANNELS):
271311
for j in range(SERVO_PROFILES):
@@ -368,39 +408,41 @@ def __init__(self, platform):
368408
]
369409

370410
# use liberally for debugging
371-
self.comb += [
372-
Cat([platform.request("test_point", i) for i in range(6)]).eq(
373-
Cat(
374-
ClockSignal("clk125"),
375-
ClockSignal("link"),
376-
# ClockSignal(),
377-
# ResetSignal(),
378-
# # self.link.slip.bitslip,
379-
# # self.link.unframe.data[0],
380-
# # self.link.unframe.data[1],
381-
# # self.link.unframe.clk_stb,
382-
# # self.link.unframe.marker_stb,
383-
# # self.link.unframe.end_of_frame,
384-
# self.link.checker.frame_stb,
385-
# # self.decoder.bus.bus.we,
386-
# # self.decoder.bus.bus.re,
387-
# # self.decoder.bus.bus.adr[0],
388-
# self.link.checker.miso,
389-
# # self.dac.data_sync,
390-
# self.dac.istr,
391-
# dac_ctrl.alarm,
392-
ClockSignal("ret"),
393-
adc.cnvn,
394-
adc.sdo[0],
395-
adc.data[1][0],
396-
)
397-
)
398-
]
411+
self.comb += [platform.request("test_point", 0).eq(adc.data[1][0])]
412+
# self.comb += [
413+
# Cat([platform.request("test_point", i) for i in range(6)]).eq(
414+
# Cat(
415+
# ClockSignal("clk125"),
416+
# ClockSignal("link"),
417+
# # ClockSignal(),
418+
# # ResetSignal(),
419+
# # # self.link.slip.bitslip,
420+
# # # self.link.unframe.data[0],
421+
# # # self.link.unframe.data[1],
422+
# # # self.link.unframe.clk_stb,
423+
# # # self.link.unframe.marker_stb,
424+
# # # self.link.unframe.end_of_frame,
425+
# # self.link.checker.frame_stb,
426+
# # # self.decoder.bus.bus.we,
427+
# # # self.decoder.bus.bus.re,
428+
# # # self.decoder.bus.bus.adr[0],
429+
# # self.link.checker.miso,
430+
# # # self.dac.data_sync,
431+
# # self.dac.istr,
432+
# # dac_ctrl.alarm,
433+
# ClockSignal("ret"),
434+
# adc.cnvn,
435+
# adc.sdo[0],
436+
# adc.data[1][0],
437+
# )
438+
# )
439+
# ]
399440

400441

401442
if __name__ == "__main__":
402443
from migen.build.platforms.sinara.phaser import Platform
403444

445+
# platform = Platform(speed_grade="-3")
404446
platform = Platform()
405447
# platform.toolchain.additional_commands.extend([
406448
# "set argv phaser.bit",

test_iir.py

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -87,24 +87,65 @@ def profile_switch(dut, inp, coeff, offset, outp):
8787
o = yield dut.outp[0]
8888
outp.append(o)
8989

90+
def servo_operation(dut, inp_list, coeff, offset, outp):
91+
yield
92+
yield dut.inp[0].eq(inp_list[0])
93+
yield dut.coeff[0][0][0].eq(coeff) # b0
94+
# yield dut.coeff[1][0][0].eq(coeff) # b1
95+
# yield dut.coeff[2][0][0].eq(0)
96+
yield dut.offset[0][0].eq(offset)
97+
yield dut.stb_in.eq(1)
98+
yield
99+
yield dut.stb_in.eq(0)
100+
for i in range(100):
101+
yield dut.inp[0].eq(inp_list[i % len(inp_list)])
102+
for _ in range(delay_cycles):
103+
yield
104+
yield dut.stb_in.eq(1)
105+
yield
106+
yield dut.stb_in.eq(0)
107+
for _ in range(delay_cycles):
108+
yield
109+
o = yield dut.outp[0]
110+
outp.append(o)
111+
yield
112+
90113

91114
class TestIir(unittest.TestCase):
92115
def setUp(self):
93-
self.dut = Iir(w_coeff=24, w_data=16, log2_a0=15, n_profiles=2, n_channels=2)
116+
self.dut = Iir(w_coeff=16, w_data=16, log2_a0=14, n_profiles=4, n_channels=2)
94117

95-
def test_profile_switch(self):
96-
inp = 1000
97-
coeff = [0x200000, 0x300000]
98-
offset = [10, 30]
99-
outp = []
100-
run_simulation(self.dut, profile_switch(self.dut, inp, coeff, offset, outp))
101-
self.assertEqual(inp // 2 + offset[0], outp[0])
102-
self.assertEqual(inp * 3 // 4 + offset[1], outp[1])
118+
# def test_profile_switch(self):
119+
# inp = 1000
120+
# coeff = [0x200000, 0x300000]
121+
# offset = [10, 30]
122+
# outp = []
123+
# run_simulation(self.dut, profile_switch(self.dut, inp, coeff, offset, outp))
124+
# self.assertEqual(inp // 2 + offset[0], outp[0])
125+
# self.assertEqual(inp * 3 // 4 + offset[1], outp[1])
103126

104-
def test_rounding(self):
105-
inp = 2345
106-
coeff = 0x200000 # 0.25 for both b0, b1
127+
# def test_rounding(self):
128+
# inp = 2345
129+
# coeff = 0x200000 # 0.25 for both b0, b1
130+
# outp = []
131+
# run_simulation(self.dut, rounding(self.dut, inp, coeff, outp))
132+
# self.assertEqual(inp // 2, outp[0])
133+
# self.assertEqual((inp // 2) + 1, outp[1])
134+
135+
def test_servo_operation(self):
136+
global delay_cycles
137+
delay_cycles = 25
138+
# inp_list = [512, 1024, 2048, 4096, 8192, 16384, 32768]
139+
# inp_list = []
140+
# start = 0
141+
# stop = 10
142+
# step = 10
143+
# for i in range(step):
144+
# inp_list.append(start + i * (stop - start) // step)
145+
inp_list = [32763]
146+
coeff = 32765 # 0.5
147+
offset = 0
107148
outp = []
108-
run_simulation(self.dut, rounding(self.dut, inp, coeff, outp))
109-
self.assertEqual(inp // 2, outp[0])
110-
self.assertEqual((inp // 2) + 1, outp[1])
149+
run_simulation(self.dut, servo_operation(self.dut, inp_list, coeff, offset, outp), vcd_name="iir_servo.vcd")
150+
151+
print(outp)

0 commit comments

Comments
 (0)