pavel-demin / red-pitaya-notes

Notes on the Red Pitaya Open Source Instrument
http://pavel-demin.github.io/red-pitaya-notes/
MIT License
337 stars 209 forks source link

Issues about ADC-Recorder-Trigger project #448

Closed carlos-e-teixeira closed 7 years ago

carlos-e-teixeira commented 7 years ago

Hi Pavel! I hope you're doing well!

I'm trying to fully understand your application: ADC-Recorder-Trigger.

We have discussed (on Nils Roos' forum) about the configuration of SLCR registers (for changing FPGA's clock) and it's is already clear for me.

Now, I'm trying to understand the block design and I have some issues. Just to check if I'm in the right way, I'm going try to explain what I understood.

The 'GPIO Reader' block reads 8 bits of data from the IO port (exp_p_tri_io) and sends it to the 'Stream Combiner' block via its master port (M_AXIS). The 'Stream Combiner' block also receives data from the 'Red Pitaya ADC' block. According to its Verilog file, the master port M_AXIS of the 'Red Pitaya ADC' block provides an 32bits-array (m_axis_tdata) containing signals of both channels of the ADC, because the most-significant bit of each channel is repeated twice, so we have (2+14)+(2+14) = 32 bits. Thus, we have a total of 40bits which will be sent by the 'Stream Combiner' to the 'Clock Converter' block, because we have two different clocks: the ADC's clock (running at 125 MHz) and the PS' clock (running at 143MHz).

  1. First issue: Inside the 'Combiner' block, why did you set the TDATA Width to 4 (bytes)? It should not be 5 (bytes), since we have 40 bits as input?

Well... After that, the M_AXIS port of the 'Clock Converter' block should provide the same 40bits-array (contaning 32 bits corresponding to the signals coming from the ADC plus 8 bits corresponding to the IO port 'exp_p_tri_io') clocked now at 143MHz to the 'Broadcaster' block. This block receives this array and separates it into three signals (M00_AXIS, M01_AXIS and M02_AXIS).

  1. Second issue: At this point, you have configured the 'Broadcaster' block all the variables 't_data_remap' like this (using the less-verbose-command 'cell'):

I thought the variable 'M02_TDATA_REMAT' corresponding to the IO port should not be 'tdata[39:32]', totalizing 8 bits.

  1. Third issue: I do not understand why the 'Stream Variable' blocks (rate_0 and rate_1) are being using in series with the two 'CIC compiler' blocks. What are their role? Could I connect directly the 'Brodcaster' block to the 'Stream Combiner block' comb_1?

Sorry for this long text, but I have done a lot of efforts to understand this project and to make my own application, but without any success yet. I started to study about Zynq-based devices (such as Red Pitaya) few time ago and I noted that there are still a lot of concepts to learn it. There are hundreds of documentations, forums and tutorials, but none of them is easy to understand!

I keep working on it until I understand!

Thank you so much for the attention and the help!

Sorry for any english mistakes! Best regards!

pavel-demin commented 7 years ago

I'd suggest to open the .xpr file in Vivado and to look at the graphical representation of the block design. It sometimes helps to better understand all the connections.

First issue: Inside the 'Combiner' block, why did you set the TDATA Width to 4 (bytes)? It should not be 5 (bytes), since we have 40 bits as input?

TDATA_NUM_BYTES is the width of the input channels. The output width is 2 * 4 = 8 bytes. To get the 40 bits, the channels coming from adc_0 and gpio_0 should be combined and it's what comb_0 does.

I thought the variable 'M02_TDATA_REMAT' corresponding to the IO port should not be 'tdata[39:32]', totalizing 8 bits.

Yes, it's another possibility. Only you'll have to align the result to 16 bits: {8'b00000000,tdata[39:32]}. Anyway, trig_0 is connected to the first 8 bits and the last 8 bits aren't connected.

I do not understand why the 'Stream Variable' blocks (rate_0 and rate_1) are being using in series with the two 'CIC compiler' blocks. What are their role?

rate_0 and rate_1 are connected to cic_0/S_AXIS_CONFIG and cic_1/S_AXIS_CONFIG. They are used to set the decimation rate of the CIC filters.

Could I connect directly the 'Brodcaster' block to the 'Stream Combiner block' comb_1?

If your project doesn't require the decimating CIC filters, then fir_0 should be also removed. Then it'll be possible to connect bcast_0 to comb_1 and then comb_1 to scope_0.

carlos-e-teixeira commented 7 years ago

Dear Pavel!

Thank you so much for this explanation! I start to understand now!

As you've said, 'rate_0' and 'rate_1' are being used to set the decimation rate of the CIC filters. I noted that in the 'adc-recorder-trigger.c' file, there is a comment saying the decimation value must be from 5 to 3125, and, also, the combined decimation (CIC + FIR) will be twice greater. Therefore, I imagine that the minimal decimation would be 5*2 = 10. So, using this configuration of the block design, I think it is not possible to get samples clocked at 125 MHz, is it?

If your project doesn't require the decimating CIC filters, then fir_0 should be also removed. Then it'll be possible to connect bcast_0 to comb_1 and then comb_1 to scope_0.

Could I remove only the 'FIR Compiler', and set the decimation factor for both CIC filters to 1 (i.e., no decimation) in order to have data sampling at fully 125MHz? I know that you've said if my project doesn't require them, both CIC filters and 'FIR Compiler' blocks should be removed. However, sometimes I would like to have some decimation, and sometimes I wouldn't. In other words, I would like to keep some decimating filter, but still having the possibility of set it to 1. Is it possible?

A last question... Concerning the 'Stream Trigger', I'm still a little confused. The trigger signal for the scope comes from the 'slice_2' block, doesn't it? The oscilloscope starts running after the signal coming from the PS-side through the 'cfg' pointer. If so, what is the purpose of the 'Stream Trigger' block? I don't undersand the purpose of the 'trigger mask' either.

Thank you again in advance!

Sorry for any inconvenience!

pavel-demin commented 7 years ago

Could I remove only the 'FIR Compiler', and set the decimation factor for both CIC filters to 1 (i.e., no decimation) in order to have data sampling at fully 125MHz?

Since I don't know the exact requirements of your project, I can't give any reasonable answer to this question. I could only suggest to have a look at the following application note for more information about this combination of CIC and FIR filters: https://www.altera.com/literature/an/an455.pdf

Then it's up to you to decide what filters are required for your project.

The trigger signal for the scope comes from the 'slice_2' block, doesn't it? The oscilloscope starts running after the signal coming from the PS-side through the 'cfg' pointer.

No, it's the run signal that comes from the CPU. The trigger signal comes from the GPIO pins.

The logic of a typical oscilloscope with a mid-display trigger is described at the following link: https://fpga4fun.com/digitalscope_hdl3.html

If so, what is the purpose of the 'Stream Trigger' block?

It detects the edges of the pulses coming to the GPIO pins and generates a trigger pulse for the oscilloscope module,

I don't understand the purpose of the 'trigger mask' either.

The trigger mask is used to select the GPIO pins used for the trigger.

For better understanding of the trigger and oscilloscope modules, please have a look at their source codes: https://github.com/pavel-demin/red-pitaya-notes/blob/master/cores/axis_trigger_v1_0/axis_trigger.v https://github.com/pavel-demin/red-pitaya-notes/blob/master/cores/axis_oscilloscope_v1_0/axis_oscilloscope.v

carlos-e-teixeira commented 7 years ago

Hi Pavel!

Thank you again! I'll check the documentation about CIC and FIR filters!

The trigger mask is used to select the GPIO pins used for the trigger.

It means that, if I set the mask trigger to 8'b00000001, the pin responsible for the trigger will be the 'exp_p_tri_io[0]', won't it?! Great! Thus I can set a randon combination of GPIO pins for triggering! Great job!

The logic of a typical oscilloscope with a mid-display trigger is described at the following link: https://fpga4fun.com/digitalscope_hdl3.html

I'll check it also!

Thank you again!

Best regards!

carlos-e-teixeira commented 7 years ago

Hi Pavel, it's me again!

About the 'adc-recorder-trigger.c' file, I understood that this line start = *((uint32_t *)(sts + 0)) >> 1; gets the value stored in the address pointed by the pointer 'sts', ignoring the first bit (least-significant bit), by performing a right-shift operation of one bit. After taking a look at the oscilloscope module, I noted that this least-signifcant bit corresponds to the 'int_enbl_reg' reg variable, so it should be ignored indeed. Is it okay?

In the next line start = (start - 1024) & 0x007FFFC0; the value 1024 corresponds to the number of samples before trigger previously set in the line *((uint32_t *)(cfg + 8)) = 1024- 1;, So, in order to transform it in a variable, I should modify both lines, resulting in

*((uint32_t *)(cfg + 8)) = myPrevSamples - 1;
...
start = (start - myPrevSamples) & 0x007FFFC0;

I did the same for the total number of samples, changing it to a variable. So I had to modify the corresponding two lines as well.

*((uint32_t *)(cfg + 12)) = myTotalSamples - 1; 
...
for(i = 0; i < myTotalSamples; ++i)
{
...  // the code inside this loop was kept.
}

The problem is that I could not to read properly data from the RAM. Should I create another variable in order to have a code variable-dependent? I think I'm having problems with the value of the variable start, but I don't know why.

I'm almost there! Thank you in advance for your time and help!

Sorry also for any inconvenience!

Best regards!

pavel-demin commented 7 years ago

I did the same for the total number of samples, changing it to a variable. The problem is that I could not to read properly data from the RAM.

The total number of samples should be a power of 2.

carlos-e-teixeira commented 7 years ago

Hi Pavel! I hope you're fine!

I'm trying to make a little change in the application ADC-Recorder-Trigger. I noted that after starting the oscilloscope, there is a while loop waiting for the external trigger, as shown below:

  /* start oscilloscope */
  *((uint16_t *)(cfg + 0)) |= 2;
  *((uint16_t *)(cfg + 0)) &= ~2;

  /* wait when oscilloscope stops */
  while(*((uint32_t *)(sts + 0)) & 1)
  {
    usleep(1000);
  }

In my case, I would like to send a trigger signal from the PS-side to the PL-side, instead of waiting for an external trigger.

In order to perform that, I have already changed the internal blocks in Vivado. Now, the trigger signal comes from the 160-bits configuration register (bits 151 downTo 144). The block "GPIO Reader" was replaced by a block called "Port Reader", created by myself based on your block "GPIO Reader". Basically, this block reads the corresponding 8bits slice (151 downTo 144), and sends it to to the block 'Stream Combiner' via its streaming master port (M_AXIS), such as the GPIO Reader does.

Aiming to send the trigger signal, I've also included a line in the code, as shown above:

  /* start oscilloscope */
  *((uint16_t *)(cfg + 0)) |= 2;
  *((uint16_t *)(cfg + 0)) &= ~2;

  /* send trigger signal */
  *((uint16_t *)(cfg + 18)) &= ~1;      // It produces a positive edge
  *((uint16_t *)(cfg + 18)) |= 1;       // on the first bit of the corresponding block "slice"

  /* wait when oscilloscope stops */
  while(*((uint32_t *)(sts + 0)) & 1)
  {
    usleep(1000);
  }

However, the trigger signal is not detected properly. Actually, it is never detected. Otherwise, when I put the new two lines inside the loop while, I'm able to trigger the oscilloscope and acquire the desired signal.

  /* wait when oscilloscope stops */
  while(*((uint32_t *)(sts + 0)) & 1)
  {
    /* send trigger signal */
    *((uint16_t *)(cfg + 18)) &= ~1;        // It produces a positive edge
    *((uint16_t *)(cfg + 18)) |= 1;     // on the first bit of the corresponding block "slice"
  }

The problem here is that I'm sending many trigger signals and because of that, I'm not able to know when the acquisition is started, which is quite necessary in my case. PS.: In my application, this trigger signal also initiates a counter, which is stopped when the first signal arrives, like a time-of-flight sensor.

Would you have any suggestions to send a trigger signal more accurately?

I really appreciate your attention! Thank you in advance! Best regards!

pavel-demin commented 7 years ago

The block "GPIO Reader" was replaced by a block called "Port Reader", created by myself based on your block "GPIO Reader". Basically, this block reads the corresponding 8bits slice (151 downTo 144), and sends it to to the block 'Stream Combiner' via its streaming master port (M_AXIS), such as the GPIO Reader does.

I'd suggest to remove the Port Reader block and to connect the trigger bit directly to scope_0/trg_flag.

carlos-e-teixeira commented 7 years ago

Thank you so much, Pavel!

So... Does it mean the "AXI4-Stream Trigger" block called "trig_0" (and its corresponding slices blocks for edge, level and mask adjustments) will also be removed?

Thank you in advance! I really appreciate your attention!

pavel-demin commented 7 years ago

Does it mean the "AXI4-Stream Trigger" block called "trig_0" (and its corresponding slices blocks for edge, level and mask adjustments) will also be removed?

If this block isn't used, then yes, it can be removed.

If you don't need an external trigger, then may be you could check the adc_recorder project: https://github.com/pavel-demin/red-pitaya-notes/tree/master/projects/adc_recorder

carlos-e-teixeira commented 7 years ago

Thank you so much, Mr. Pavel!

eric58000 commented 7 years ago

Hi Pavel! Thanks a thousand times for sharing your job you made on Red Pitaya !

I'm trying to more understand your application : ADC-Recorder-Trigger.

In this project, there is two different clocks :

The decimating CIC filters and fir_0 are into the PS-side of this project. The clock is 143 MHz for this PS-side.

So my question is : is it correct to configure CIC filters and fir_0 with a clock frequency of 125 MHz (and perhaps an input sample frequency of 125 MHz too) ? I am a little bit lost by this question of clock conversion...

Is it a good or a bad idea to move fifo_0 (AXI4-Stream Clock Converter) between conv_0 and writer_0 blocks ?

Sorry for any english mistakes I should make ! Best regards ! Eric.

pavel-demin commented 7 years ago

Hi Eric,

While looking for a solution for this issue, I've found how to remove the 143 MHz PS clock from my FPGA configurations. About a month ago, I've updated all the FPGA configurations with this pull request. Now, all the FPGA configurations are clocked with the 125 MHz ADC clock and they don't have clock converters.

So, I'd suggest to try the latest version of the adc_recorder_trigger project. With this version, your questions could be answered as follows:

is it correct to configure CIC filters and fir_0 with a clock frequency of 125 MHz (and perhaps an input sample frequency of 125 MHz too)?

Yes, it is correct.

Is it a good or a bad idea to move fifo_0 (AXI4-Stream Clock Converter) between conv_0 and writer_0 blocks?

There is no clock converter in the latest version. All the modules are now in the same clock domain.

Best regards,

Pavel

eric58000 commented 7 years ago

Thanks a lot Pavel