mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-14 02:26:59 -07:00
New LF edge detection algorithm + lowpass filter
This is a new LF edge detection algorithm for the FPGA. - It uses a low-pass IIR filter to clean the signal (see https://fail0verflow.com/blog/2014/proxmark3-fpga-iir-filter.html) - The algorithm is able to detect consecutive peaks in the same direction - It uses an envelope follower to dynamically adjust the peak thresholds - The main threshold used in the envelope follower can be set from the ARM side fpga/lf_edge_detect.v, fpga/lp20khz_1MSa_iir_filter.v, fpga/min_max_tracker.v: New file. fpga/lo_edge_detect.v, fpga/fpga_lf.v: Modify accordingly. armsrc/apps.h (FPGA_CMD_SET_USER_BYTE1, FPGA_CMD_SET_EDGE_DETECT_THRESHOLD): New FPGA command. fpga/fpga_lf.v: Modify accordingly/Add a 8bit user register. fpga/fpga_lf.bit: Update accordingly. fpga/tests: New directory for testbenches fpga/tests/Makefile: New file. It compiles the testbenches and runs all the tests by default (comparing with the golden output) fpga/tests/tb_lp20khz_1MSa_iir_filter.v, fpga/tests/tb_min_max_tracker.v, fpga/tests/tb_lf_edge_detect.v: New testbenches fpga/tests/plot_edgedetect.py: New script to plot the results from the edge detection tests. fpga/tests/tb_data: New directory for data and golden outputs
This commit is contained in:
parent
e17437f985
commit
3b2fee43ea
36 changed files with 685 additions and 57 deletions
87
fpga/tests/Makefile
Normal file
87
fpga/tests/Makefile
Normal file
|
@ -0,0 +1,87 @@
|
|||
#-----------------------------------------------------------------------------
|
||||
# Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
#
|
||||
# This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
# at your option, any later version. See the LICENSE.txt file for the text of
|
||||
# the license.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
TEST_OUTDIR = tb_tmp
|
||||
|
||||
TB_SOURCES = \
|
||||
tb_lp20khz_1MSa_iir_filter.v \
|
||||
tb_min_max_tracker.v \
|
||||
tb_lf_edge_detect.v
|
||||
|
||||
TBS = $(TB_SOURCES:.v=.vvp)
|
||||
|
||||
TB_DATA = \
|
||||
pcf7931_write1byte_1MSA_data \
|
||||
pcf7931_read_1MSA_data
|
||||
|
||||
all: $(TBS) tests
|
||||
|
||||
%.vvp: %.v
|
||||
iverilog -I .. -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf *.vvp $(TEST_OUTDIR)
|
||||
|
||||
tests: tb_lp20khz_1MSa_iir_filter tb_min_max_tracker tb_lf_edge_detect
|
||||
|
||||
tb_lp20khz_1MSa_iir_filter: tb_lp20khz_1MSa_iir_filter.vvp | test_dir
|
||||
@printf "Testing $@\n"
|
||||
@for d in $(TB_DATA); do \
|
||||
$(call run_test,$@.vvp,$$d,in); \
|
||||
$(call check_golden,$$d,filtered); \
|
||||
done; \
|
||||
rm -f $(TEST_OUTDIR)/data.*
|
||||
|
||||
tb_min_max_tracker: tb_min_max_tracker.vvp | test_dir
|
||||
@printf "Testing $@\n"
|
||||
@for d in $(TB_DATA); do \
|
||||
$(call run_test,$@.vvp,$$d,in filtered.gold); \
|
||||
$(call check_golden,$$d,min); \
|
||||
$(call check_golden,$$d,max); \
|
||||
done; \
|
||||
rm -f $(TEST_OUTDIR)/data.*
|
||||
|
||||
tb_lf_edge_detect: tb_lf_edge_detect.vvp | test_dir
|
||||
@printf "Testing $@\n"
|
||||
@for d in $(TB_DATA); do \
|
||||
$(call run_test,$@.vvp,$$d,in filtered.gold); \
|
||||
$(call check_golden,$$d,min); \
|
||||
$(call check_golden,$$d,max); \
|
||||
$(call check_golden,$$d,state); \
|
||||
$(call check_golden,$$d,toggle); \
|
||||
$(call check_golden,$$d,high); \
|
||||
$(call check_golden,$$d,highz); \
|
||||
$(call check_golden,$$d,lowz); \
|
||||
$(call check_golden,$$d,low); \
|
||||
done; \
|
||||
rm -f $(TEST_OUTDIR)/data.*
|
||||
|
||||
test_dir:
|
||||
@if [ ! -d $(TEST_OUTDIR) ] ; then mkdir $(TEST_OUTDIR) ; fi
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
# $(1) = basename
|
||||
# $(2) = extension to check
|
||||
check_golden = \
|
||||
printf " Checking $(1).$(2)... "; \
|
||||
mv $(TEST_OUTDIR)/data.$(2) $(TEST_OUTDIR)/$(1).$(2); \
|
||||
if cmp -s tb_data/$(1).$(2).gold $(TEST_OUTDIR)/$(1).$(2); then \
|
||||
printf "OK\n"; \
|
||||
else \
|
||||
printf "ERROR\n"; \
|
||||
fi
|
||||
|
||||
# $(1) = vvp file
|
||||
# $(2) = data basename
|
||||
# $(3) = data extensions to copy
|
||||
run_test = \
|
||||
env echo " With $(2)... "; \
|
||||
cp tb_data/$(2).time $(TEST_OUTDIR); \
|
||||
for e in $(3); do cp tb_data/$(2).$$e $(TEST_OUTDIR)/data.$$e; done; \
|
||||
./$(1)
|
58
fpga/tests/plot_edgedetect.py
Executable file
58
fpga/tests/plot_edgedetect.py
Executable file
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env python
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
#
|
||||
# This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
# at your option, any later version. See the LICENSE.txt file for the text of
|
||||
# the license.
|
||||
#-----------------------------------------------------------------------------
|
||||
import numpy
|
||||
import matplotlib.pyplot as plt
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print "Usage: %s <basename>" % sys.argv[0]
|
||||
sys.exit(1)
|
||||
|
||||
BASENAME = sys.argv[1]
|
||||
|
||||
nx = numpy.fromfile(BASENAME + ".time")
|
||||
|
||||
def plot_time(dat1):
|
||||
plt.plot(nx, dat1)
|
||||
|
||||
sig = open(BASENAME + ".filtered").read()
|
||||
sig = map(lambda x: ord(x), sig)
|
||||
|
||||
min_vals = open(BASENAME + ".min").read()
|
||||
min_vals = map(lambda x: ord(x), min_vals)
|
||||
|
||||
max_vals = open(BASENAME + ".max").read()
|
||||
max_vals = map(lambda x: ord(x), max_vals)
|
||||
|
||||
states = open(BASENAME + ".state").read()
|
||||
states = map(lambda x: ord(x) * 10 + 65, states)
|
||||
|
||||
toggles = open(BASENAME+ ".toggle").read()
|
||||
toggles = map(lambda x: ord(x) * 10 + 80, toggles)
|
||||
|
||||
high = open(BASENAME + ".high").read()
|
||||
high = map(lambda x: ord(x), high)
|
||||
highz = open(BASENAME + ".highz").read()
|
||||
highz = map(lambda x: ord(x), highz)
|
||||
lowz = open(BASENAME + ".lowz").read()
|
||||
lowz = map(lambda x: ord(x), lowz)
|
||||
low = open(BASENAME + ".low").read()
|
||||
low = map(lambda x: ord(x), low)
|
||||
|
||||
plot_time(sig)
|
||||
plot_time(min_vals)
|
||||
plot_time(max_vals)
|
||||
plot_time(states)
|
||||
plot_time(toggles)
|
||||
plot_time(high)
|
||||
plot_time(highz)
|
||||
plot_time(lowz)
|
||||
plot_time(low)
|
||||
|
||||
plt.show()
|
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.filtered.gold
Normal file
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.filtered.gold
Normal file
File diff suppressed because one or more lines are too long
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.high.gold
Normal file
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.high.gold
Normal file
File diff suppressed because one or more lines are too long
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.highz.gold
Normal file
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.highz.gold
Normal file
File diff suppressed because one or more lines are too long
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.in
Normal file
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.in
Normal file
File diff suppressed because one or more lines are too long
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.low.gold
Normal file
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.low.gold
Normal file
File diff suppressed because one or more lines are too long
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.lowz.gold
Normal file
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.lowz.gold
Normal file
File diff suppressed because one or more lines are too long
BIN
fpga/tests/tb_data/pcf7931_read_1MSA_data.max.gold
Normal file
BIN
fpga/tests/tb_data/pcf7931_read_1MSA_data.max.gold
Normal file
Binary file not shown.
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.min.gold
Normal file
1
fpga/tests/tb_data/pcf7931_read_1MSA_data.min.gold
Normal file
File diff suppressed because one or more lines are too long
BIN
fpga/tests/tb_data/pcf7931_read_1MSA_data.state.gold
Normal file
BIN
fpga/tests/tb_data/pcf7931_read_1MSA_data.state.gold
Normal file
Binary file not shown.
BIN
fpga/tests/tb_data/pcf7931_read_1MSA_data.time
Normal file
BIN
fpga/tests/tb_data/pcf7931_read_1MSA_data.time
Normal file
Binary file not shown.
BIN
fpga/tests/tb_data/pcf7931_read_1MSA_data.toggle.gold
Normal file
BIN
fpga/tests/tb_data/pcf7931_read_1MSA_data.toggle.gold
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.in
Normal file
1
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.in
Normal file
File diff suppressed because one or more lines are too long
1
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.low.gold
Normal file
1
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.low.gold
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.max.gold
Normal file
BIN
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.max.gold
Normal file
Binary file not shown.
1
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.min.gold
Normal file
1
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.min.gold
Normal file
File diff suppressed because one or more lines are too long
BIN
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.state.gold
Normal file
BIN
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.state.gold
Normal file
Binary file not shown.
BIN
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.time
Normal file
BIN
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.time
Normal file
Binary file not shown.
BIN
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.toggle.gold
Normal file
BIN
fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.toggle.gold
Normal file
Binary file not shown.
111
fpga/tests/tb_lf_edge_detect.v
Normal file
111
fpga/tests/tb_lf_edge_detect.v
Normal file
|
@ -0,0 +1,111 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// testbench for lf_edge_detect
|
||||
`include "lf_edge_detect.v"
|
||||
|
||||
`define FIN "tb_tmp/data.filtered.gold"
|
||||
`define FOUT_MIN "tb_tmp/data.min"
|
||||
`define FOUT_MAX "tb_tmp/data.max"
|
||||
`define FOUT_STATE "tb_tmp/data.state"
|
||||
`define FOUT_TOGGLE "tb_tmp/data.toggle"
|
||||
`define FOUT_HIGH "tb_tmp/data.high"
|
||||
`define FOUT_HIGHZ "tb_tmp/data.highz"
|
||||
`define FOUT_LOWZ "tb_tmp/data.lowz"
|
||||
`define FOUT_LOW "tb_tmp/data.low"
|
||||
|
||||
module lf_edge_detect_tb;
|
||||
|
||||
integer fin, fout_state, fout_toggle;
|
||||
integer fout_high, fout_highz, fout_lowz, fout_low, fout_min, fout_max;
|
||||
integer r;
|
||||
|
||||
reg clk = 0;
|
||||
reg [7:0] adc_d;
|
||||
wire adc_clk;
|
||||
wire data_rdy;
|
||||
wire edge_state;
|
||||
wire edge_toggle;
|
||||
|
||||
wire [7:0] high_threshold;
|
||||
wire [7:0] highz_threshold;
|
||||
wire [7:0] lowz_threshold;
|
||||
wire [7:0] low_threshold;
|
||||
wire [7:0] max;
|
||||
wire [7:0] min;
|
||||
|
||||
initial
|
||||
begin
|
||||
clk = 0;
|
||||
fin = $fopen(`FIN, "r");
|
||||
if (!fin) begin
|
||||
$display("ERROR: can't open the data file");
|
||||
$finish;
|
||||
end
|
||||
fout_min = $fopen(`FOUT_MIN, "w+");
|
||||
fout_max = $fopen(`FOUT_MAX, "w+");
|
||||
fout_state = $fopen(`FOUT_STATE, "w+");
|
||||
fout_toggle = $fopen(`FOUT_TOGGLE, "w+");
|
||||
fout_high = $fopen(`FOUT_HIGH, "w+");
|
||||
fout_highz = $fopen(`FOUT_HIGHZ, "w+");
|
||||
fout_lowz = $fopen(`FOUT_LOWZ, "w+");
|
||||
fout_low = $fopen(`FOUT_LOW, "w+");
|
||||
if (!$feof(fin))
|
||||
adc_d = $fgetc(fin); // read the first value
|
||||
end
|
||||
|
||||
always
|
||||
# 1 clk = !clk;
|
||||
|
||||
// input
|
||||
initial
|
||||
begin
|
||||
while (!$feof(fin)) begin
|
||||
@(negedge clk) adc_d <= $fgetc(fin);
|
||||
end
|
||||
|
||||
if ($feof(fin))
|
||||
begin
|
||||
# 3 $fclose(fin);
|
||||
$fclose(fout_state);
|
||||
$fclose(fout_toggle);
|
||||
$fclose(fout_high);
|
||||
$fclose(fout_highz);
|
||||
$fclose(fout_lowz);
|
||||
$fclose(fout_low);
|
||||
$fclose(fout_min);
|
||||
$fclose(fout_max);
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
initial
|
||||
begin
|
||||
// $monitor("%d\t S: %b, E: %b", $time, edge_state, edge_toggle);
|
||||
end
|
||||
|
||||
// output
|
||||
always @(negedge clk)
|
||||
if ($time > 2) begin
|
||||
r = $fputc(min, fout_min);
|
||||
r = $fputc(max, fout_max);
|
||||
r = $fputc(edge_state, fout_state);
|
||||
r = $fputc(edge_toggle, fout_toggle);
|
||||
r = $fputc(high_threshold, fout_high);
|
||||
r = $fputc(highz_threshold, fout_highz);
|
||||
r = $fputc(lowz_threshold, fout_lowz);
|
||||
r = $fputc(low_threshold, fout_low);
|
||||
end
|
||||
|
||||
// module to test
|
||||
lf_edge_detect detect(clk, adc_d, 8'd127,
|
||||
max, min,
|
||||
high_threshold, highz_threshold,
|
||||
lowz_threshold, low_threshold,
|
||||
edge_state, edge_toggle);
|
||||
|
||||
endmodule
|
55
fpga/tests/tb_lp20khz_1MSa_iir_filter.v
Normal file
55
fpga/tests/tb_lp20khz_1MSa_iir_filter.v
Normal file
|
@ -0,0 +1,55 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// testbench for lp20khz_1MSa_iir_filter
|
||||
`include "lp20khz_1MSa_iir_filter.v"
|
||||
|
||||
`define FIN "tb_tmp/data.in"
|
||||
`define FOUT "tb_tmp/data.filtered"
|
||||
|
||||
module lp20khz_1MSa_iir_filter_tb;
|
||||
|
||||
integer fin, fout, r;
|
||||
|
||||
reg clk;
|
||||
reg [7:0] adc_d;
|
||||
wire data_rdy;
|
||||
wire [7:0] adc_filtered;
|
||||
|
||||
initial
|
||||
begin
|
||||
clk = 0;
|
||||
fin = $fopen(`FIN, "r");
|
||||
if (!fin) begin
|
||||
$display("ERROR: can't open the data file");
|
||||
$finish;
|
||||
end
|
||||
fout = $fopen(`FOUT, "w+");
|
||||
if (!$feof(fin))
|
||||
adc_d = $fgetc(fin); // read the first value
|
||||
end
|
||||
|
||||
always
|
||||
# 1 clk = !clk;
|
||||
|
||||
always @(posedge clk)
|
||||
if (data_rdy) begin
|
||||
if ($time > 1)
|
||||
r = $fputc(adc_filtered, fout);
|
||||
if (!$feof(fin))
|
||||
adc_d <= $fgetc(fin);
|
||||
else begin
|
||||
$fclose(fin);
|
||||
$fclose(fout);
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
// module to test
|
||||
lp20khz_1MSa_iir_filter filter(clk, adc_d, data_rdy, adc_filtered);
|
||||
|
||||
endmodule
|
74
fpga/tests/tb_min_max_tracker.v
Normal file
74
fpga/tests/tb_min_max_tracker.v
Normal file
|
@ -0,0 +1,74 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// testbench for min_max_tracker
|
||||
`include "min_max_tracker.v"
|
||||
|
||||
`define FIN "tb_tmp/data.filtered.gold"
|
||||
`define FOUT_MIN "tb_tmp/data.min"
|
||||
`define FOUT_MAX "tb_tmp/data.max"
|
||||
|
||||
module min_max_tracker_tb;
|
||||
|
||||
integer fin;
|
||||
integer fout_min, fout_max;
|
||||
integer r;
|
||||
|
||||
reg clk;
|
||||
reg [7:0] adc_d;
|
||||
wire [7:0] min;
|
||||
wire [7:0] max;
|
||||
|
||||
initial
|
||||
begin
|
||||
clk = 0;
|
||||
fin = $fopen(`FIN, "r");
|
||||
if (!fin) begin
|
||||
$display("ERROR: can't open the data file");
|
||||
$finish;
|
||||
end
|
||||
fout_min = $fopen(`FOUT_MIN, "w+");
|
||||
fout_max = $fopen(`FOUT_MAX, "w+");
|
||||
if (!$feof(fin))
|
||||
adc_d = $fgetc(fin); // read the first value
|
||||
end
|
||||
|
||||
always
|
||||
# 1 clk = !clk;
|
||||
|
||||
// input
|
||||
initial
|
||||
begin
|
||||
while (!$feof(fin)) begin
|
||||
@(negedge clk) adc_d <= $fgetc(fin);
|
||||
end
|
||||
|
||||
if ($feof(fin))
|
||||
begin
|
||||
# 3 $fclose(fin);
|
||||
$fclose(fout_min);
|
||||
$fclose(fout_max);
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
initial
|
||||
begin
|
||||
// $monitor("%d\t min: %x, max: %x", $time, min, max);
|
||||
end
|
||||
|
||||
// output
|
||||
always @(negedge clk)
|
||||
if ($time > 2) begin
|
||||
r = $fputc(min, fout_min);
|
||||
r = $fputc(max, fout_max);
|
||||
end
|
||||
|
||||
// module to test
|
||||
min_max_tracker tracker(clk, adc_d, 8'd127, min, max);
|
||||
|
||||
endmodule
|
Loading…
Add table
Add a link
Reference in a new issue