SURF  1.0
Ad9249ReadoutGroup.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : Ad9249ReadoutGroup.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2016-05-26
5 -- Last update: 2017-03-07
6 -------------------------------------------------------------------------------
7 -- Description:
8 -- ADC Readout Controller
9 -- Receives ADC Data from an AD9592 chip.
10 -- Designed specifically for Xilinx 7 series FPGAs
11 -------------------------------------------------------------------------------
12 -- This file is part of 'SLAC Firmware Standard Library'.
13 -- It is subject to the license terms in the LICENSE.txt file found in the
14 -- top-level directory of this distribution and at:
15 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
16 -- No part of 'SLAC Firmware Standard Library', including this file,
17 -- may be copied, modified, propagated, or distributed except according to
18 -- the terms contained in the LICENSE.txt file.
19 -------------------------------------------------------------------------------
20 
21 library ieee;
22 use ieee.std_logic_1164.all;
23 use ieee.std_logic_arith.all;
24 use ieee.std_logic_unsigned.all;
25 
26 library UNISIM;
27 use UNISIM.vcomponents.all;
28 
29 use work.StdRtlPkg.all;
30 use work.AxiLitePkg.all;
31 use work.AxiStreamPkg.all;
32 use work.Ad9249Pkg.all;
33 
34 --! @see entity
35  --! @ingroup devices_AnalogDevices_ad9249
37  generic (
38  TPD_G : time := 1 ns;
39  NUM_CHANNELS_G : natural range 1 to 8 := 8;
40  IODELAY_GROUP_G : string := "DEFAULT_GROUP";
41  IDELAYCTRL_FREQ_G : real := 200.0;
42  DEFAULT_DELAY_G : slv(4 downto 0) := (others => '0');
43  ADC_INVERT_CH_G : slv(7 downto 0) := "00000000");
44  port (
45  -- Master system clock, 125Mhz
46  axilClk : in sl;
47  axilRst : in sl;
48 
49  -- Axi Interface
54 
55  -- Reset for adc deserializer
56  adcClkRst : in sl;
57 
58  -- Serial Data from ADC
60 
61  -- Deserialized ADC Data
64  (others => axiStreamMasterInit((false, 2, 8, 0, TKEEP_NORMAL_C, 0, TUSER_NORMAL_C))));
65 end Ad9249ReadoutGroup;
66 
67 -- Define architecture
68 architecture rtl of Ad9249ReadoutGroup is
69 
70  -------------------------------------------------------------------------------------------------
71  -- AXIL Registers
72  -------------------------------------------------------------------------------------------------
73  type AxilRegType is record
76  delay : slv(4 downto 0);
77  dataDelaySet : slv(NUM_CHANNELS_G-1 downto 0);
78  frameDelaySet : sl;
79  readoutDebug0 : slv16Array(NUM_CHANNELS_G-1 downto 0);
80  readoutDebug1 : slv16Array(NUM_CHANNELS_G-1 downto 0);
81  lockedCountRst : sl;
82  end record;
83 
84  constant AXIL_REG_INIT_C : AxilRegType := (
87  delay => DEFAULT_DELAY_G,
88  dataDelaySet => (others => '1'),
89  frameDelaySet => '1',
90  readoutDebug0 => (others => (others => '0')),
91  readoutDebug1 => (others => (others => '0')),
92  lockedCountRst => '0');
93 
94  signal lockedSync : sl;
95  signal lockedFallCount : slv(15 downto 0);
96 
97  signal axilR : AxilRegType := AXIL_REG_INIT_C;
98  signal axilRin : AxilRegType;
99 
100  -------------------------------------------------------------------------------------------------
101  -- ADC Readout Clocked Registers
102  -------------------------------------------------------------------------------------------------
103  type AdcRegType is record
104  slip : sl;
105  count : slv(5 downto 0);
106  locked : sl;
107  fifoWrData : Slv16Array(NUM_CHANNELS_G-1 downto 0);
108  end record;
109 
110  constant ADC_REG_INIT_C : AdcRegType := (
111  slip => '0',
112  count => (others => '0'),
113  locked => '0',
114  fifoWrData => (others => (others => '0')));
115 
116  signal adcR : AdcRegType := ADC_REG_INIT_C;
117  signal adcRin : AdcRegType;
118 
119 
120  -- Local Signals
121  signal tmpAdcClk : sl;
122  signal adcBitClkIo : sl;
123  signal adcBitClkIoInv : sl;
124  signal adcBitClkR : sl;
125  signal adcBitRst : sl;
126 
127  signal adcFramePad : sl;
128  signal adcFrame : slv(13 downto 0);
129  signal adcFrameSync : slv(13 downto 0);
130  signal adcDataPadOut : slv(NUM_CHANNELS_G-1 downto 0);
131  signal adcDataPad : slv(NUM_CHANNELS_G-1 downto 0);
132  signal adcData : Slv14Array(NUM_CHANNELS_G-1 downto 0);
133 
134  signal curDelayFrame : slv(4 downto 0);
135  signal curDelayData : slv5Array(NUM_CHANNELS_G-1 downto 0);
136 
137  signal fifoDataValid : sl;
138  signal fifoDataOut : slv(NUM_CHANNELS_G*16-1 downto 0);
139  signal fifoDataIn : slv(NUM_CHANNELS_G*16-1 downto 0);
140  signal fifoDataTmp : slv16Array(NUM_CHANNELS_G-1 downto 0);
141 
142  signal debugDataValid : sl;
143  signal debugDataOut : slv(NUM_CHANNELS_G*16-1 downto 0);
144  signal debugDataTmp : slv16Array(NUM_CHANNELS_G-1 downto 0);
145 
146 begin
147  -------------------------------------------------------------------------------------------------
148  -- Synchronize adcR.locked across to axil clock domain and count falling edges on it
149  -------------------------------------------------------------------------------------------------
150 
151  SynchronizerOneShotCnt_1 : entity work.SynchronizerOneShotCnt
152  generic map (
153  TPD_G => TPD_G,
154  IN_POLARITY_G => '0',
155  OUT_POLARITY_G => '0',
156  CNT_RST_EDGE_G => true,
157  CNT_WIDTH_G => 16)
158  port map (
159  dataIn => adcR.locked,
160  rollOverEn => '0',
161  cntRst => axilR.lockedCountRst,
162  dataOut => open,
163  cntOut => lockedFallCount,
164  wrClk => adcBitClkR,
165  wrRst => '0',
166  rdClk => axilClk,
167  rdRst => axilRst);
168 
169  Synchronizer_1 : entity work.Synchronizer
170  generic map (
171  TPD_G => TPD_G,
172  STAGES_G => 2)
173  port map (
174  clk => axilClk,
175  rst => axilRst,
176  dataIn => adcR.locked,
177  dataOut => lockedSync);
178 
179  SynchronizerVec_1 : entity work.SynchronizerVector
180  generic map (
181  TPD_G => TPD_G,
182  STAGES_G => 2,
183  WIDTH_G => 14)
184  port map (
185  clk => axilClk,
186  rst => axilRst,
187  dataIn => adcFrame,
188  dataOut => adcFrameSync);
189 
190  -------------------------------------------------------------------------------------------------
191  -- AXIL Interface
192  -------------------------------------------------------------------------------------------------
193  axilComb : process (adcFrameSync, axilR, axilReadMaster, axilRst, axilWriteMaster, curDelayData,
194  curDelayFrame, debugDataTmp, debugDataValid, lockedFallCount, lockedSync) is
195  variable v : AxilRegType;
196  variable axilEp : AxiLiteEndpointType;
197  begin
198  v := axilR;
199 
200  v.dataDelaySet := (others => '0');
201  v.frameDelaySet := '0';
202  v.axilReadSlave.rdata := (others => '0');
203 
204  -- Store last two samples read from ADC
205  if (debugDataValid = '1') then
206  v.readoutDebug0 := debugDataTmp;
207  v.readoutDebug1 := axilR.readoutDebug0;
208  end if;
209 
210  axiSlaveWaitTxn(axilEp, axilWriteMaster, axilReadMaster, v.axilWriteSlave, v.axilReadSlave);
211 
212  -- Up to 8 delay registers
213  -- Write delay values to IDELAY primatives
214  -- All writes go to same r.delay register,
215  -- dataDelaySet(i) or frameDelaySet enables the primative write
216  for i in 0 to NUM_CHANNELS_G-1 loop
217  axiSlaveRegister(axilEp, X"00"+toSlv((i*4), 8), 0, v.delay);
218  axiSlaveRegister(axilEp, X"00"+toSlv((i*4), 8), 5, v.dataDelaySet(i), '1');
219  end loop;
220  axiSlaveRegister(axilEp, X"20", 0, v.delay);
221  axiSlaveRegister(axilEp, X"20", 5, v.frameDelaySet, '1');
222 
223  -- Override read from r.delay and use curDealy output from delay primative instead
224  for i in 0 to NUM_CHANNELS_G-1 loop
225  axiSlaveRegisterR(axilEp, X"00"+toSlv((i*4), 8), 0, curDelayData(i));
226  end loop;
227  axiSlaveRegisterR(axilEp, X"20", 0, curDelayFrame);
228 
229 
230  -- Debug output to see how many times the shift has needed a relock
231  axiSlaveRegisterR(axilEp, X"30", 0, lockedFallCount);
232  axiSlaveRegisterR(axilEp, X"30", 16, lockedSync);
233  axiSlaveRegisterR(axilEp, X"34", 0, adcFrameSync);
234  axiSlaveRegister(axilEp, X"38", 0, v.lockedCountRst);
235 
236  -- Debug registers. Output the last 2 words received
237  for i in 0 to NUM_CHANNELS_G-1 loop
238  axiSlaveRegisterR(axilEp, X"80"+toSlv((i*4), 8), 0, axilR.readoutDebug0(i));
239  axiSlaveRegisterR(axilEp, X"80"+toSlv((i*4), 8), 16, axilR.readoutDebug1(i));
240  end loop;
241 
242  axiSlaveDefault(axilEp, v.axilWriteSlave, v.axilReadSlave, AXI_RESP_DECERR_C);
243 
244  if (axilRst = '1') then
245  v := AXIL_REG_INIT_C;
246  end if;
247 
248  axilRin <= v;
250  axilReadSlave <= axilR.axilReadSlave;
251 
252  end process;
253 
254  axilSeq : process (axilClk) is
255  begin
256  if (rising_edge(axilClk)) then
257  axilR <= axilRin after TPD_G;
258  end if;
259  end process axilSeq;
260 
261 
262 
263  -------------------------------------------------------------------------------------------------
264  -- Create Clocks
265  -------------------------------------------------------------------------------------------------
266 
267  AdcClk_I_Ibufds : IBUFDS
268  generic map (
269  DIFF_TERM => true,
270  IOSTANDARD => "LVDS_25")
271  port map (
272  I => adcSerial.dClkP,
273  IB => adcSerial.dClkN,
274  O => tmpAdcClk);
275 
276  -- IO Clock
277  U_BUFIO : BUFIO
278  port map (
279  I => tmpAdcClk,
280  O => adcBitClkIo);
281 
282  adcBitClkIoInv <= not adcBitClkIo;
283 
284  -- Regional clock
285  U_AdcBitClkR : BUFR
286  generic map (
287  SIM_DEVICE => "7SERIES",
288  BUFR_DIVIDE => "7")
289  port map (
290  I => tmpAdcClk,
291  O => adcBitClkR,
292  CE => '1',
293  CLR => '0');
294 
295  -- Regional clock reset
296  ADC_BITCLK_RST_SYNC : entity work.RstSync
297  generic map (
298  TPD_G => TPD_G,
299  RELEASE_DELAY_G => 5)
300  port map (
301  clk => adcBitClkR,
302  asyncRst => adcClkRst,
303  syncRst => adcBitRst);
304 
305 
306  -------------------------------------------------------------------------------------------------
307  -- Deserializers
308  -------------------------------------------------------------------------------------------------
309 
310  -- Frame signal input
311  U_FrameIn : IBUFDS
312  generic map (
313  DIFF_TERM => true)
314  port map (
315  I => adcSerial.fClkP,
316  IB => adcSerial.fClkN,
317  O => adcFramePad);
318 
319  U_FRAME_DESERIALIZER : entity work.Ad9249Deserializer
320  generic map (
321  TPD_G => TPD_G,
324  port map (
325  clkIo => adcBitClkIo,
326  clkIoInv => adcBitClkIoInv,
327  clkR => adcBitClkR,
328  rst => adcBitRst,
329  slip => adcR.slip,
330  sysClk => axilClk,
331  curDelay => curDelayFrame,
332  setDelay => axilR.delay,
333  setValid => axilR.frameDelaySet,
334  iData => adcFramePad,
335  oData => adcFrame);
336 
337  --------------------------------
338  -- Data Input, 8 channels
339  --------------------------------
340  GenData : for i in NUM_CHANNELS_G-1 downto 0 generate
341 
342  -- Frame signal input
343  U_DataIn : IBUFDS
344  generic map (
345  DIFF_TERM => true)
346  port map (
347  I => adcSerial.chP(i),
348  IB => adcSerial.chN(i),
349  O => adcDataPadOut(i));
350 
351  -- Optionally invert the pad input
352  adcDataPad(i) <= adcDataPadOut(i) when ADC_INVERT_CH_G(i) = '0' else not adcDataPadOut(i);
353 
354  U_DATA_DESERIALIZER : entity work.Ad9249Deserializer
355  generic map (
356  TPD_G => TPD_G,
359  port map (
360  clkIo => adcBitClkIo,
361  clkIoInv => adcBitClkIoInv,
362  clkR => adcBitClkR,
363  rst => adcBitRst,
364  slip => adcR.slip,
365  sysClk => axilClk,
366  curDelay => curDelayData(i),
367  setDelay => axilR.delay,
368  setValid => axilR.dataDelaySet(i),
369  iData => adcDataPad(i),
370  oData => adcData(i));
371  end generate;
372 
373  -------------------------------------------------------------------------------------------------
374  -- ADC Bit Clocked Logic
375  -------------------------------------------------------------------------------------------------
376  adcComb : process (adcData, adcFrame, adcR) is
377  variable v : AdcRegType;
378  begin
379  v := adcR;
380 
381  ----------------------------------------------------------------------------------------------
382  -- Slip bits until correct alignment seen
383  ----------------------------------------------------------------------------------------------
384  v.slip := '0';
385 
386  if (adcR.count = 0) then
387  if (adcFrame = "11111110000000") then
388  v.locked := '1';
389  else
390  v.locked := '0';
391  v.slip := '1';
392  v.count := adcR.count + 1;
393  end if;
394  end if;
395 
396  if (adcR.count /= 0) then
397  v.count := adcR.count + 1;
398  end if;
399 
400  ----------------------------------------------------------------------------------------------
401  -- Look for Frame rising edges and write data to fifos
402  ----------------------------------------------------------------------------------------------
403  for i in NUM_CHANNELS_G-1 downto 0 loop
404  if (adcR.locked = '1' and adcFrame = "11111110000000") then
405  -- Locked, output adc data
406  v.fifoWrData(i) := "00" & adcData(i);
407  else
408  -- Not locked
409  v.fifoWrData(i) := (others => '1'); --"10" & "00000000000000";
410  end if;
411  end loop;
412 
413  adcRin <= v;
414 
415  end process adcComb;
416 
417  adcSeq : process (adcBitClkR, adcBitRst) is
418  begin
419  if (adcBitRst = '1') then
420  adcR <= ADC_REG_INIT_C after TPD_G;
421  elsif (rising_edge(adcBitClkR)) then
422  adcR <= adcRin after TPD_G;
423  end if;
424  end process adcSeq;
425 
426  -- Flatten fifoWrData onto fifoDataIn for FIFO
427  -- Regroup fifoDataOut by channel into fifoDataTmp
428  -- Format fifoDataTmp into AxiStream channels
429  glue : for i in NUM_CHANNELS_G-1 downto 0 generate
430  fifoDataIn(i*16+15 downto i*16) <= adcR.fifoWrData(i);
431  fifoDataTmp(i) <= fifoDataOut(i*16+15 downto i*16);
432  debugDataTmp(i) <= debugDataOut(i*16+15 downto i*16);
433  adcStreams(i).tdata(15 downto 0) <= fifoDataTmp(i);
434  adcStreams(i).tDest <= toSlv(i, 8);
435  adcStreams(i).tValid <= fifoDataValid;
436  end generate;
437 
438  -- Single fifo to synchronize adc data to the Stream clock
439  U_DataFifo : entity work.SynchronizerFifo
440  generic map (
441  TPD_G => TPD_G,
442  BRAM_EN_G => false,
443  DATA_WIDTH_G => NUM_CHANNELS_G*16,
444  ADDR_WIDTH_G => 4,
445  INIT_G => "0")
446  port map (
447  rst => adcBitRst,
448  wr_clk => adcBitClkR,
449  wr_en => '1', --Always write data
450  din => fifoDataIn,
451  rd_clk => adcStreamClk,
452  rd_en => fifoDataValid,
453  valid => fifoDataValid,
454  dout => fifoDataOut);
455 
456  U_DataFifoDebug : entity work.SynchronizerFifo
457  generic map (
458  TPD_G => TPD_G,
459  BRAM_EN_G => false,
460  DATA_WIDTH_G => NUM_CHANNELS_G*16,
461  ADDR_WIDTH_G => 4,
462  INIT_G => "0")
463  port map (
464  rst => adcBitRst,
465  wr_clk => adcBitClkR,
466  wr_en => '1', --Always write data
467  din => fifoDataIn,
468  rd_clk => axilClk,
469  rd_en => debugDataValid,
470  valid => debugDataValid,
471  dout => debugDataOut);
472 
473 
474 end rtl;
475 
out syncRstsl
Definition: RstSync.vhd:36
AxiLiteWriteMasterType
Definition: AxiLitePkg.vhd:111
std_logic sl
Definition: StdRtlPkg.vhd:28
in rstsl :=not RST_POLARITY_G
in dinslv( DATA_WIDTH_G- 1 downto 0)
IDELAYCTRL_FREQ_Greal := 200.0
IDELAYCTRL_FREQ_Greal := 200.0
ADDR_WIDTH_Ginteger range 2 to 48:= 4
STAGES_Gpositive := 2
slv( 31 downto 0) rdata
Definition: AxiLitePkg.vhd:89
in adcSerialAd9249SerialGroupType
NUM_CHANNELS_Gnatural range 1 to 8:= 8
BRAM_EN_Gboolean := false
in dataInslv( WIDTH_G- 1 downto 0)
in asyncRstsl
Definition: RstSync.vhd:35
IODELAY_GROUP_Gstring := "DEFAULT_GROUP"
out dataOutsl
out doutslv( DATA_WIDTH_G- 1 downto 0)
in clksl
Definition: RstSync.vhd:34
out cntOutslv( CNT_WIDTH_G- 1 downto 0)
array(natural range <> ) of slv( 13 downto 0) Slv14Array
Definition: StdRtlPkg.vhd:397
in axilReadMasterAxiLiteReadMasterType
RELEASE_DELAY_Ginteger range 3 to positive'high:= 3
Definition: RstSync.vhd:31
slv( 1 downto 0) := "11" AXI_RESP_DECERR_C
Definition: AxiLitePkg.vhd:49
ADC_INVERT_CH_Gslv( 7 downto 0) := "00000000"
AxiLiteReadMasterType
Definition: AxiLitePkg.vhd:59
in axilWriteMasterAxiLiteWriteMasterType
out axilWriteSlaveAxiLiteWriteSlaveType
TPD_Gtime := 1 ns
Definition: RstSync.vhd:27
TPD_Gtime := 1 ns
out axilReadSlaveAxiLiteReadSlaveType
_library_ ieeeieee
Definition: Ad9249Pkg.vhd:18
AxiLiteReadSlaveType :=(arready => '0',rdata =>( others => '0'),rresp =>( others => '0'),rvalid => '0') AXI_LITE_READ_SLAVE_INIT_C
Definition: AxiLitePkg.vhd:95
out dataOutslv( WIDTH_G- 1 downto 0)
array(natural range <> ) of AxiStreamMasterType AxiStreamMasterArray
DEFAULT_DELAY_Gslv( 4 downto 0) :=( others => '0')
in wrRstsl :=not RST_POLARITY_G
array(natural range <> ) of slv( 15 downto 0) Slv16Array
Definition: StdRtlPkg.vhd:395
out curDelayslv( 4 downto 0)
in cntRstsl :=not RST_POLARITY_G
slv( 7 downto 0) tDest
AxiLiteReadSlaveType
Definition: AxiLitePkg.vhd:85
out adcStreamsAxiStreamMasterArray( NUM_CHANNELS_G- 1 downto 0) :=( others => axiStreamMasterInit(( false, 2, 8, 0, TKEEP_NORMAL_C, 0, TUSER_NORMAL_C)))
in rstsl :=not RST_POLARITY_G
out oDataslv( 13 downto 0)
in setDelayslv( 4 downto 0)
in rdRstsl :=not RST_POLARITY_G
AxiLiteWriteSlaveType :=(awready => '0',wready => '0',bresp =>( others => '0'),bvalid => '0') AXI_LITE_WRITE_SLAVE_INIT_C
Definition: AxiLitePkg.vhd:156
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 16
std_logic_vector slv
Definition: StdRtlPkg.vhd:29
Ad9249SerialGroupType
Definition: Ad9249Pkg.vhd:29