Commit bdeeddd1 authored by Jack Hickish's avatar Jack Hickish Committed by GitHub
Browse files

Merge pull request #15 from ianmalcolm/high_resolution_adc

High resolution adc
parents f2f6bd05 bf039e82
No related merge requests found
Showing with 182 additions and 17 deletions
+182 -17
......@@ -128,8 +128,8 @@ architecture ADC_MMCM_arc of ADC_MMCM is
signal mmcm_locked : std_logic;
signal mmcm_reset : std_logic;
constant CLK_MUL : REAL := 5.0;
constant CLK_DIV : Integer := 2;
constant CLK_MUL : REAL := 8.0;
constant CLK_DIV : Integer := 4;
constant CLK0_DIV : Real := CLK_MUL/Real(CLK_DIV);
constant CLK1_DIV : Integer := Integer(CLK0_DIV*(Real(ADC_RESOLUTION)/4.0)*2.0);
constant CLK2_DIV : Integer := Integer(CLK0_DIV*(Real(ADC_RESOLUTION)/4.0));
......@@ -177,7 +177,7 @@ architecture ADC_MMCM_arc of ADC_MMCM is
CLKOUT2_PHASE => 0.000,
CLKOUT2_DUTY_CYCLE => 0.500,
CLKOUT2_USE_FINE_PS => false,
CLKOUT3_DIVIDE => 5, -- Fout = (M * Fin) / (D * 4) = Fin / 2 (when D=2, M=5)
CLKOUT3_DIVIDE => CLK2_DIV, -- Fout = (M * Fin) / (D * 4) = Fin / 2 (when D=2, M=5)
CLKOUT3_PHASE => 90.000,
CLKOUT3_DUTY_CYCLE => 0.500,
CLKOUT3_USE_FINE_PS => false,
......
......@@ -197,10 +197,10 @@ architecture adc_unit_arc of adc_unit is
p_data(ADC_DATA_WIDTH*1+ADC_RESOLUTION-2 downto ADC_DATA_WIDTH*1) <= adc_iserdes_data(ADC_RESOLUTION*2-2 downto ADC_RESOLUTION*1);
p_data(ADC_DATA_WIDTH*0+ADC_RESOLUTION-2 downto ADC_DATA_WIDTH*0) <= adc_iserdes_data(ADC_RESOLUTION*1-2 downto ADC_RESOLUTION*0);
-- Output signed number
p_data(ADC_DATA_WIDTH*4-1) <= not adc_iserdes_data(ADC_RESOLUTION*4-1);
p_data(ADC_DATA_WIDTH*3-1) <= not adc_iserdes_data(ADC_RESOLUTION*3-1);
p_data(ADC_DATA_WIDTH*2-1) <= not adc_iserdes_data(ADC_RESOLUTION*2-1);
p_data(ADC_DATA_WIDTH*1-1) <= not adc_iserdes_data(ADC_RESOLUTION*1-1);
p_data(ADC_DATA_WIDTH*4-1 downto ADC_DATA_WIDTH*3+ADC_RESOLUTION-1) <= (others => not adc_iserdes_data(ADC_RESOLUTION*4-1));
p_data(ADC_DATA_WIDTH*3-1 downto ADC_DATA_WIDTH*2+ADC_RESOLUTION-1) <= (others => not adc_iserdes_data(ADC_RESOLUTION*3-1));
p_data(ADC_DATA_WIDTH*2-1 downto ADC_DATA_WIDTH*1+ADC_RESOLUTION-1) <= (others => not adc_iserdes_data(ADC_RESOLUTION*2-1));
p_data(ADC_DATA_WIDTH*1-1 downto ADC_DATA_WIDTH*0+ADC_RESOLUTION-1) <= (others => not adc_iserdes_data(ADC_RESOLUTION*1-1));
end if;
end process;
......
`timescale 1ns/1ps
// This testbench is for understanding the interface between
// adc16_interface and wb_bram.
module testbench;
// Change LOG_USER_WIDTH to see simulations under
// differnt bit-width of adc_channel/user_din
// LOG_USER_WIDTH = 5 ==> 08-bit adc_channel x 4 or 032-bit user_din
// LOG_USER_WIDTH = 6 ==> 16-bit adc_channel x 4 or 064-bit user_din
// LOG_USER_WIDTH = 7 ==> 32-bit adc_channel x 4 or 128-bit user_din
parameter LOG_USER_WIDTH = 5;
parameter USER_ADDR_BITS = 10;
parameter N_REGISTERS = 1;
localparam USER_WIDTH = 1 << (LOG_USER_WIDTH-2);
reg wb_clk_i;
reg wb_rst_i;
reg [31:0] wb_adr_i;
reg [3:0] wb_sel_i;
reg [31:0] wb_dat_i;
reg wb_we_i;
reg wb_cyc_i;
reg wb_stb_i;
wire [31:0] wb_dat_o;
wire wb_err_o;
wire wb_ack_o;
reg user_clk;
reg [USER_ADDR_BITS-1:0] user_addr;
reg [USER_WIDTH-1:0] a1;
reg [USER_WIDTH-1:0] a2;
reg [USER_WIDTH-1:0] a3;
reg [USER_WIDTH-1:0] a4;
reg user_we;
integer i;
// Clock gen
initial begin
// 200MHz
wb_clk_i = 1'b0;
forever wb_clk_i = #2.5 ~wb_clk_i;
end
initial begin
// 100MHz
user_clk = 1'b0;
forever user_clk = #5 ~user_clk;
end
initial begin
wb_rst_i = 1'b1;
wb_adr_i = 32'h0;
wb_sel_i = 4'h0;
wb_dat_i = 32'h0;
wb_we_i = 0;
wb_cyc_i = 0;
wb_stb_i = 0;
user_addr = 10'h0;
a1 = 'h0;
a2 = 'h0;
a3 = 'h0;
a4 = 'h0;
user_we = 0;
#5 wb_rst_i = 1'b0;
@(negedge user_clk);
user_addr = 10'h0;
a1 = 'h11001101;
a2 = 'h22002202;
a3 = 'h33003303;
a4 = 'h44004404;
user_we = 1;
$strobe("@ %0t: \t user_addr:%h, a1:%h, a2:%h, a3:%h, a4:%h", $time, user_addr, a1, a2, a3, a4 );
@(negedge user_clk);
user_addr = 10'h1;
a1 = 'h55005505;
a2 = 'h66006606;
a3 = 'h77007707;
a4 = 'h88008808;
user_we = 1;
$strobe("@ %0t: \t user_addr:%h, a1:%h, a2:%h, a3:%h, a4:%h", $time, user_addr, a1, a2, a3, a4 );
@(negedge user_clk);
user_addr = 10'h0;
a1 = 'h0;
a2 = 'h0;
a3 = 'h0;
a4 = 'h0;
user_we = 0;
@(negedge user_clk);
for (i=0; i<2**(LOG_USER_WIDTH-2); i=i+4) begin
@(negedge wb_clk_i);
wb_adr_i = i;
wb_we_i = 0;
wb_sel_i = 4'hf;
wb_cyc_i = 1;
wb_stb_i = 1;
@(wb_ack_o);
$strobe("@ %0t: \t wb_adr_i:%h, wb_dat_o:%h", $time, wb_adr_i, wb_dat_o);
@(negedge wb_clk_i);
wb_adr_i = 32'h0;
wb_we_i = 0;
wb_sel_i = 4'h0;
wb_cyc_i = 0;
wb_stb_i = 0;
end
repeat(10) @(negedge wb_clk_i);
$finish;
end
wb_bram #(
.LOG_USER_WIDTH(LOG_USER_WIDTH),
.USER_ADDR_BITS(USER_ADDR_BITS),
.N_REGISTERS(N_REGISTERS)
) dut (
.wb_clk_i(wb_clk_i),
.wb_rst_i(wb_rst_i),
.wb_dat_o(wb_dat_o),
.wb_err_o(wb_err_o),
.wb_ack_o(wb_ack_o),
.wb_adr_i(wb_adr_i),
.wb_sel_i(wb_sel_i),
.wb_dat_i(wb_dat_i),
.wb_we_i (wb_we_i),
.wb_cyc_i(wb_cyc_i),
.wb_stb_i(wb_stb_i),
.user_clk(user_clk),
.user_addr(user_addr),
.user_din({a1,a2,a3,a4}),
.user_we(user_we),
.user_dout()
);
endmodule // testbench
No preview for this file type
......@@ -2,7 +2,7 @@ from yellow_block import YellowBlock
from verilog import VerilogModule
from constraints import PortConstraint, ClockConstraint, RawConstraint
from yellow_block_typecodes import *
import math
import math, numpy as np
class snap_adc(YellowBlock):
def initialize(self):
......@@ -14,13 +14,6 @@ class snap_adc(YellowBlock):
self.zdok_rev = 2 # no frame clocks (see adc16)
self.n_inputs = self.snap_inputs / 3 #number of inputs per chip
if self.adc_interleaving_mode == "1 channel mode":
self.adc_interleaving_mode = 1
elif self.adc_interleaving_mode == "2 channel mode":
self.adc_interleaving_mode = 2
elif self.adc_interleaving_mode == "4 channel mode":
self.adc_interleaving_mode = 4
# self.adc_resolution, possible values are 8, 10, 12, 14, 16
# Currently only 8, 12, 16 are supported
if self.adc_resolution <=8:
......@@ -32,7 +25,7 @@ class snap_adc(YellowBlock):
self.LOG_USER_WIDTH = int(math.log(self.adc_data_width*4,2))
# An HMCAD1511 has 8 ADC cores and DDR transmission
self.line_clock_freq = self.sample_rate/(8.0/self.adc_interleaving_mode)*self.adc_resolution/2.0
self.line_clock_freq = self.sample_rate/(8.0/self.n_inputs)*self.adc_resolution/2.0
self.add_source('adc16_interface')
self.add_source('wb_adc16_controller')
......@@ -170,10 +163,33 @@ class snap_adc(YellowBlock):
wbram.add_wb_interface(regname='adc16_wb_ram%d'%k, mode='rw', nbytes=(self.adc_data_width/8)*4*2**10, typecode=TYPECODE_SWREG)
wbram.add_port('user_clk','adc0_clk', parent_sig=False)
wbram.add_port('user_addr','adc16_snap_addr', width=10)
wbram.add_port('user_din','{%s1, %s2, %s3, %s4}'%(din,din,din,din), parent_sig=False)
#wbram.add_port('user_din','{%s1, %s2, %s3, %s4}'%(din,din,din,din), parent_sig=False)
wbram.add_port('user_din',self.reorder_ports([din+'1',din+'2',din+'3',din+'4']), parent_sig=False)
wbram.add_port('user_we','adc16_snap_we')
wbram.add_port('user_dout','')
def reorder_ports(self,port_list, wb_bitwidth=32):
""" Reorder output ports of ADCs to arrange sampling data in correct order in wb_bram
wb_bitwidth stands for the bit width of data in/out port of wishbone bus
E.g.
reorder_ports(['a1','a2','a3','a4'])
when self.adc_data_width == 8, return {a1,a2,a3,a4}
when self.adc_data_width == 16, return {a3,a4,a1,a2}
when self.adc_data_width == 32, return {a4,a3,a2,a1}
"""
if not isinstance(port_list,list):
raise ValueError("Parameter error")
elif any([not isinstance(port,str) for port in port_list]):
raise ValueError("Parameter error")
r = wb_bitwidth / self.adc_data_width
port_list = np.array(port_list).reshape(-1, r)
port_list = port_list[::-1,:].reshape(-1).tolist()
return '{' + ','.join(port_list) + '}'
def gen_constraints(self):
cons = []
# ADC SPI interface
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment