Author Topic: Fast ADC interface with FPGA  (Read 3270 times)

0 Members and 1 Guest are viewing this topic.

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Fast ADC interface with FPGA
« on: August 16, 2022, 03:30:34 pm »
I have to interface a fast ADC with an FPGA and then do the data processing. The FPGA used will be Zynq Ultrascale+ RFSoC ZU29DR. I have been given the information that ADC_clk = 4x FPGA_clk. ADC output data is 12/16-bits. The data processing will be multiply-accumulate over a number of samples.

Code: [Select]
I = I + adc_data * cos;
Q = Q + adc_data * sin;

There is a data sample output at every clock of ADC. So, it will be something like:

Code: [Select]
I[0] = I[0] + adc_data[0] * cos[0];
Q[0] = Q[0] + adc_data[0] * sin[0];
I[1] = I[1] + adc_data[1] * cos[1];
Q[1] = Q[1] + adc_data[1] * sin[1];

And so on.

I have a DDS CORDIC-LUT module that can be instantiated to generate 4 sin, cos values parallelly based on the phase word. What I'm not sure about is how to multiply with adc_data as adc generates faster than what the FPGA can accept.

I have come up with the below timing diagram and architecture. Any input will be appreciated.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: Fast ADC interface with FPGA
« Reply #1 on: August 16, 2022, 09:45:13 pm »
That timing diagram looks a little odd to me - there is eight data values per FPGA clock cycle, not four.

Not sure what the question is (if any), but you will need to use SERDES to separate out the four samples.

See attached diagram for what you need to construct for each bit (the PLL gets shared by all bits).

You will need to get very friendly with:
- the simulator (to check it works before trying in H/W)
- The clocking resources on your FPGA - you have to write your design to map onto the FPGA's dedicated structures. To not do so will result in failure.
- Documentation for the SERDES block on your FPGA - they are simple to use, but have so many options, and it can be tricky to reset them correctly.

The other option is to clock the edge of the design twice as fast, and then use the much simpler DDR registers to capture the data.

This might be of use (even though Ultrascale I/O hardware is different): https://github.com/hamsternz/Artix-7-HDMI-processing/blob/master/src/deserialiser_1_to_10.vhd

« Last Edit: August 16, 2022, 09:55:57 pm by hamster_nz »
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: knight

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: Fast ADC interface with FPGA
« Reply #2 on: August 16, 2022, 09:53:19 pm »
Oh, and if latency isn't an issue you can use the sample input as the initial CORDIC vector, so when you calculate SIN & COS you will actually get  X*SIN(phase)*CORDIC_GAIN and X*COS(phase)*CORDIC_GAIN, removing the need for any multipliers.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: KE5FX, knight

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Fast ADC interface with FPGA
« Reply #3 on: August 17, 2022, 01:22:20 am »
Quote
That timing diagram looks a little odd to me - there is eight data values per FPGA clock cycle, not four.
That is because we are generating sin, cos pair, hence 8 values per cycle.

Quote
Not sure what the question is (if any), but you will need to use SERDES to separate out the four samples.
Unfortunately, I cannot use SERDES. Is there other interface option available?

 

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Fast ADC interface with FPGA
« Reply #4 on: August 17, 2022, 01:23:33 am »
Oh, and if latency isn't an issue you can use the sample input as the initial CORDIC vector, so when you calculate SIN & COS you will actually get  X*SIN(phase)*CORDIC_GAIN and X*COS(phase)*CORDIC_GAIN, removing the need for any multipliers.
Sounds good :-+
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: Fast ADC interface with FPGA
« Reply #5 on: August 17, 2022, 02:10:22 am »
Quote
That timing diagram looks a little odd to me - there is eight data values per FPGA clock cycle, not four.
That is because we are generating sin, cos pair, hence 8 values per cycle.

Quote
Not sure what the question is (if any), but you will need to use SERDES to separate out the four samples.
Unfortunately, I cannot use SERDES. Is there other interface option available?

Your FPGA internal signals (sine and cosines) should only change on one of the FPGA clock edges (either on the rising or falling, but not both). Have a look at the attached trace and see if that is what you want to happen at the edge of your design (before the multipliers).

What is preventing you from using SERDES? The FPGA supports SERDES, and without it there is no sensible synthesizable way to input or output data at 4x the FPGA logic's clock rate.

Are they other restrictions that you are not telling us about? It's really frustrating to put the time in to provide a sensible answer, only to be told "sorry - wrong answer - I'm not allowed to do that, try again".
« Last Edit: August 17, 2022, 02:12:47 am by hamster_nz »
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: knight

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Fast ADC interface with FPGA
« Reply #6 on: August 17, 2022, 02:45:56 am »

Quote
Your FPGA internal signals (sine and cosines) should only change on one of the FPGA clock edges (either on the rising or falling, but not both). Have a look at the attached trace and see if that is what you want to happen at the edge of your design (before the multipliers).
Yes, that is what I need, and at the same clock, the data will be multiplied by sin and cos.

Quote
What is preventing you from using SERDES? The FPGA supports SERDES, and without it there is no sensible synthesizable way to input or output data at 4x the FPGA logic's clock rate.
Actually, I don't know how to use the SERDES IP. The datasheet doesn't tell us how. Have a look.
ISERDES and OSERDES
Many applications combine high-speed, bit-serial I/O with slower parallel operation inside the device. This
requires a serializer and deserializer (SerDes) inside the I/O logic. Each I/O pin possesses an IOSERDES
(ISERDES and OSERDES) capable of performing serial-to-parallel or parallel-to-serial conversions with
programmable widths of 2, 4, or 8 bits. These I/O logic features enable high-performance interfaces, such
as Gigabit Ethernet/1000BaseX/SGMII, to be moved from the transceivers to the SelectIO interface.

Quote
Are they other restrictions that you are not telling us about? It's really frustrating to put the time in to provide a sensible answer, only to be told "sorry - wrong answer - I'm not allowed to do that, try again".
I'm sorry if I'm not clear enough. I'm trying to create the right block (with 1 ADC input).
I just know the ratio that fast(adc) clock = 4 or 8x slow(fpga) clock
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: Fast ADC interface with FPGA
« Reply #7 on: August 17, 2022, 03:15:29 am »
Oh, yes, that's different!

I would consider using a four-sample-long shift register on the high speed side, and then latch it in the slow clock domain. As long as the fast and slow clocks have a known phase relationship (i.e. sourced from the same PLL) you shouldn't have any timing problems with that, as the tools will be able to verify the timing works - so no FIFO or shared memory block is needed (or even synchronizers!).

For a 12-bit sample you will need a 48-bit shift register.

For the fast clock domain it is nothing but:
Code: [Select]
if rising_edge(fast_clk) then
   shift_reg <= shift_reg(35 downto 0) & new_sample
end if;

and for the slow domain
Code: [Select]
if rising_edge(slow_clk) then
   sample3 <= shift_reg(47 downto 36); -- Oldest sample
   sample2 <= shift_reg(35 downto 24);
   sample1 <= shift_reg(23 downto 12);
   sample0 <= shift_reg(11 downto  0); -- Most recent sample
end if;
Then you can do your math on the four sample values.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: knight

Offline Someone

  • Super Contributor
  • ***
  • Posts: 4961
  • Country: au
    • send complaints here
Re: Fast ADC interface with FPGA
« Reply #8 on: August 17, 2022, 03:17:34 am »
What is preventing you from using SERDES? The FPGA supports SERDES, and without it there is no sensible synthesizable way to input or output data at 4x the FPGA logic's clock rate.

Are they other restrictions that you are not telling us about? It's really frustrating to put the time in to provide a sensible answer, only to be told "sorry - wrong answer - I'm not allowed to do that, try again".
This is already a split thread:
https://www.eevblog.com/forum/fpga/how-to-use-fifo-to-process-fast-adc-data/

But the data arriving interleaved on the ADC clock (unsure if word or bit interleaved from description so far) obviously has a clock the FPGA is handling somehow....
 
The following users thanked this post: hamster_nz

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Fast ADC interface with FPGA
« Reply #9 on: August 17, 2022, 04:33:30 am »
Oh, yes, that's different!

I would consider using a four-sample-long shift register on the high speed side, and then latch it in the slow clock domain. As long as the fast and slow clocks have a known phase relationship (i.e. sourced from the same PLL) you shouldn't have any timing problems with that, as the tools will be able to verify the timing works - so no FIFO or shared memory block is needed (or even synchronizers!).

For a 12-bit sample you will need a 48-bit shift register.

For the fast clock domain it is nothing but:
Code: [Select]
if rising_edge(fast_clk) then
   shift_reg <= shift_reg(35 downto 0) & new_sample
end if;

and for the slow domain
Code: [Select]
if rising_edge(slow_clk) then
   sample3 <= shift_reg(47 downto 36); -- Oldest sample
   sample2 <= shift_reg(35 downto 24);
   sample1 <= shift_reg(23 downto 12);
   sample0 <= shift_reg(11 downto  0); -- Most recent sample
end if;
Then you can do your math on the four sample values.
Thanks bro, I will try to code it.  :-+
 

Online radiolistener

  • Super Contributor
  • ***
  • Posts: 4015
  • Country: ua
Re: Fast ADC interface with FPGA
« Reply #10 on: August 17, 2022, 07:41:29 am »
since your ADC works at x4 clock frequency, you can use ADC ready signal as a clock for processing ADC data lines at x4 clock rate. Then transfer data into slow FPGA clock domain...
 
The following users thanked this post: knight

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Fast ADC interface with FPGA
« Reply #11 on: August 17, 2022, 01:05:52 pm »
Oh, yes, that's different!

I would consider using a four-sample-long shift register on the high speed side, and then latch it in the slow clock domain. As long as the fast and slow clocks have a known phase relationship (i.e. sourced from the same PLL) you shouldn't have any timing problems with that, as the tools will be able to verify the timing works - so no FIFO or shared memory block is needed (or even synchronizers!).

For a 12-bit sample you will need a 48-bit shift register.

For the fast clock domain it is nothing but:
Code: [Select]
if rising_edge(fast_clk) then
   shift_reg <= shift_reg(35 downto 0) & new_sample
end if;

I tried to code this in verilog but the shift register is always 0 when viewed in the testbench.

Code: [Select]
always @(posedge adc_clk or negedge rst)
        begin
            if (~rst)
                shift_reg <= 0;  //even if this is 1, no change
            else
                shift_reg <= shift_reg[35:0] & adc_data_in;
        end
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: Fast ADC interface with FPGA
« Reply #12 on: August 17, 2022, 09:13:03 pm »
& in VHDL is the concatenation operator, & in Verilog is binary AND operator.

I think you want something like:
Code: [Select]
shift_reg <= { shift_reg[35:0], adc_data_in };
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 
The following users thanked this post: knight

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Fast ADC interface with FPGA
« Reply #13 on: August 18, 2022, 03:22:11 am »
& in VHDL is the concatenation operator, & in Verilog is binary AND operator.

I think you want something like:
Code: [Select]
shift_reg <= { shift_reg[35:0], adc_data_in };
Thanks! It's correct. VHDL is a weird language to use "and" as concatenation operator. :D
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 15321
  • Country: fr
Re: Fast ADC interface with FPGA
« Reply #14 on: August 18, 2022, 04:50:24 pm »
& in VHDL is the concatenation operator, & in Verilog is binary AND operator.

I think you want something like:
Code: [Select]
shift_reg <= { shift_reg[35:0], adc_data_in };
Thanks! It's correct. VHDL is a weird language to use "and" as concatenation operator. :D

VHDL is based on Ada which uses "and" as a "and" operator. Now which is weird? ;D
 

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Fast ADC interface with FPGA
« Reply #15 on: August 28, 2022, 01:58:58 pm »
I tried to code the proposed architecture in Verilog HDL and got some results, as attached in the picture below. However, there seems to be some minor issue which I cannot find, the sample count doesn't go upto 65536 which it is supposed to. It stops at 65528 and then goes to 0. I'm including the Vivado project rar file so that it is easier for people to run it. The issue is somewhere in the "raw_sp.v" file. Any inputs will be highly appreciated. Thanks. :-+
 

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Fast ADC interface with FPGA
« Reply #16 on: September 13, 2022, 01:05:10 am »
Oh, yes, that's different!

I would consider using a four-sample-long shift register on the high speed side, and then latch it in the slow clock domain. As long as the fast and slow clocks have a known phase relationship (i.e. sourced from the same PLL) you shouldn't have any timing problems with that, as the tools will be able to verify the timing works - so no FIFO or shared memory block is needed (or even synchronizers!).

For a 12-bit sample you will need a 48-bit shift register.

For the fast clock domain it is nothing but:
Code: [Select]
if rising_edge(fast_clk) then
   shift_reg <= shift_reg(35 downto 0) & new_sample
end if;

and for the slow domain
Code: [Select]
if rising_edge(slow_clk) then
   sample3 <= shift_reg(47 downto 36); -- Oldest sample
   sample2 <= shift_reg(35 downto 24);
   sample1 <= shift_reg(23 downto 12);
   sample0 <= shift_reg(11 downto  0); -- Most recent sample
end if;
Then you can do your math on the four sample values.
The above logic seems to be doing clock domain crossing. Wouldn't it need some kind of FIFO to work?
 

Online ejeffrey

  • Super Contributor
  • ***
  • Posts: 3893
  • Country: us
Re: Fast ADC interface with FPGA
« Reply #17 on: September 13, 2022, 04:46:11 am »
The above logic seems to be doing clock domain crossing. Wouldn't it need some kind of FIFO to work?

If fast_clk and slow_clk are synchronous with a defined and fixed phase (say one generated from a multiple output PLL) then they are effectively the same clock domain and the timing analyzer will be able to determine if the setup/hold limits are violated.

This is somewhat unusual and someone reading the code might well think that there is a true clock-domain crossing done incorrectly, so it is worth clearly documenting your expectations and of course make sure you set up the timing constraints properly.
 
The following users thanked this post: knight

Offline knightTopic starter

  • Regular Contributor
  • *
  • Posts: 50
  • Country: sg
Re: Fast ADC interface with FPGA
« Reply #18 on: September 13, 2022, 08:51:16 am »
Quote
If fast_clk and slow_clk are synchronous with a defined and fixed phase (say one generated from a multiple output PLL) then they are effectively the same clock domain and the timing analyzer will be able to determine if the setup/hold limits are violated.
Thank you very much for your reply. I'm using Zynq Ultrascale+ RFSoC. How does one find out if clocks are synchronous/generated from same PLL?
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf