FPGA-Module Integration in RedPitaya FPGA Code

Applications, development tools, FPGA, C, WEB
Post Reply
georgwild
Posts: 8
Joined: Fri May 06, 2016 2:22 pm

FPGA-Module Integration in RedPitaya FPGA Code

Post by georgwild » Mon Dec 26, 2016 5:31 pm

Hey guys,

I have read several post about this topic here in the forum but none of them can really answer my questions.

I would like to use the Fast Analogue Input and the Fast Analogue Output for my FIR-Filter Module.
The code version I am using is release-v0.94.

Right now I have the signals connected like this in the 'red_pitaya_top.v' file:

Code: Select all

fir_filter filter1(
  .adc_clk_i       (  adc_clk                   ),
  .adc_rstn_i      (  adc_rstn                  ),
  .adc_i           (  adc_a                     ),
  .dac_o           (  asg_a                     )          
);
I also removed the Oscilloscope and the ASG modules from the design to resolve some errors.

I tested the code above and I can not measure any output signal whatsoever. :?

Now to my questions:
  1. Is the way I integrate my module in the RedPitaya fpga code correct?
  2. Do I need to remove any standard modules or any standard code if I want to use the Fast Input/Output for my module?
  3. Are there any control signals that I need to generate/handle in my module?
  4. Is there anything else I need to look out for, when integrating my module?
I would really appreciate your help.

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: FPGA-Module Integration in RedPitaya FPGA Code

Post by Nils Roos » Tue Dec 27, 2016 6:17 pm

Is the way I integrate my module in the RedPitaya fpga code correct?
What you show seems ok. adc_a and asg_a are the right signal busses to connect to. You could also add a third term to the output summation (instead of repurposing asg_*) where you insert your filtered sample stream.
Do I need to remove any standard modules or any standard code if I want to use the Fast Input/Output for my module?
Only if there are insufficient resources in the fpga to implement your filter alongside the existing logic.
It's slightly sloppy to just remove the scope and asg module without implementing default termination for their sys_bus and axi connections, but that should not impair the functionality of your filter.
Are there any control signals that I need to generate/handle in my module?
If you are only interested in the ADC and DAC data streams, you don't need to do anything more. The clocks and control signals required for the analog front-end are generated in red_pitaya_top and the pll module. If you wanted to have your filter's parameters configurable from the CPU, you'd have to do more.
Is there anything else I need to look out for, when integrating my module?
It's always a good idea to examine the results of synthesis and implementation when developing new modules. Do you find your filter with all expected external connections in the generated schematics after synthesis? Are there unexpected warnings about your components being optimized away due to constant inputs or similar?

georgwild
Posts: 8
Joined: Fri May 06, 2016 2:22 pm

Re: FPGA-Module Integration in RedPitaya FPGA Code

Post by georgwild » Sat Dec 31, 2016 4:10 pm

Thank you for your fast reply!

I changed my design according to your answer, however there are still some problems with it.
You could also add a third term to the output summation (instead of repurposing asg_*) where you insert your filtered sample stream.
As you said instead of repurposing asg_a I added a third term to the output summation but I can not measure any output signal. (It was also not working before when I was using asg_a for my output.)

I also tried to set the output of my module to 14'h3000 which should be a positive DC Voltage, but there was still no output signal measurable.
It's always a good idea to examine the results of synthesis and implementation when developing new modules. Do you find your filter with all expected external connections in the generated schematics after synthesis? Are there unexpected warnings about your components being optimized away due to constant inputs or similar?
My module is still there with all of its connections after Synthesis and Implementation and there are no warnings about it.

So the problem I have is that I can not generate any output signal. The hardware is fine, I checked it with the ScopePro app. I just don't know what I am doing wrong.

georgwild
Posts: 8
Joined: Fri May 06, 2016 2:22 pm

Re: FPGA-Module Integration in RedPitaya FPGA Code

Post by georgwild » Sun Jan 08, 2017 7:43 pm

Because I still don't know why this is not working (and I really need this to work) I am going to upload the source code here. Maybe someone can help.

These are the changes I made to the 'red_pitaya_top.v' module.
  1. I created a new signed wire just next to the declarations of the wires for the 'asg' and 'pid' module output. (line 281)

    Code: Select all

    //FIR-Filter
    wire  signed [14-1:0] fir_a;
    
  2. Then I added this term to the output summation of the dac. (line 362)

    Code: Select all

    assign dac_a_sum = asg_a + pid_a + fir_a;
    
  3. And I included my filter module after the Housekeeping module and before the oscilloscope. (line 422)

    Code: Select all

    //---------------------------------------------------------------------------------
    //  FIR-Filter Application
    
    fir_filter test_filter(
      .adc_clk_i       (  adc_clk                   ),
      .adc_rstn_i      (  adc_rstn                  ),
      .adc_i           (  adc_a                     ),
      .dac_o           (  fir_a                     )          
    );
    
Here is the whole 'red_pitaya_top.v' in case this is helpful.

Code: Select all

/**
 * $Id: red_pitaya_top.v 1271 2014-02-25 12:32:34Z matej.oblak $
 *
 * @brief Red Pitaya TOP module. It connects external pins and PS part with 
 *        other application modules. 
 *
 * @Author Matej Oblak
 *
 * (c) Red Pitaya  http://www.redpitaya.com
 *
 * This part of code is written in Verilog hardware description language (HDL).
 * Please visit http://en.wikipedia.org/wiki/Verilog
 * for more details on the language used herein.
 */


/**
 * GENERAL DESCRIPTION:
 *
 * Top module connects PS part with rest of Red Pitaya applications.  
 *
 *
 *                   /-------\      
 *   PS DDR <------> |  PS   |      AXI <-> custom bus
 *   PS MIO <------> |   /   | <------------+
 *   PS CLK -------> |  ARM  |              |
 *                   \-------/              |
 *                                          |
 *                            /-------\     |
 *                         -> | SCOPE | <---+
 *                         |  \-------/     |
 *                         |                |
 *            /--------\   |   /-----\      |
 *   ADC ---> |        | --+-> |     |      |
 *            | ANALOG |       | PID | <----+
 *   DAC <--- |        | <---- |     |      |
 *            \--------/   ^   \-----/      |
 *                         |                |
 *                         |  /-------\     |
 *                         -- |  ASG  | <---+ 
 *                            \-------/     |
 *                                          |
 *             /--------\                   |
 *    RX ----> |        |                   |
 *   SATA      | DAISY  | <-----------------+
 *    TX <---- |        | 
 *             \--------/ 
 *               |    |
 *               |    |
 *               (FREE)
 *
 *
 * Inside analog module, ADC data is translated from unsigned neg-slope into
 * two's complement. Similar is done on DAC data.
 *
 * Scope module stores data from ADC into RAM, arbitrary signal generator (ASG)
 * sends data from RAM to DAC. MIMO PID uses ADC ADC as input and DAC as its output.
 *
 * Daisy chain connects with other boards with fast serial link. Data which is
 * send and received is at the moment undefined. This is left for the user.
 * 
 */

module red_pitaya_top (
   // PS connections
   inout  [54-1: 0] FIXED_IO_mio       ,
   inout            FIXED_IO_ps_clk    ,
   inout            FIXED_IO_ps_porb   ,
   inout            FIXED_IO_ps_srstb  ,
   inout            FIXED_IO_ddr_vrn   ,
   inout            FIXED_IO_ddr_vrp   ,
   // DDR
   inout  [15-1: 0] DDR_addr           ,
   inout  [ 3-1: 0] DDR_ba             ,
   inout            DDR_cas_n          ,
   inout            DDR_ck_n           ,
   inout            DDR_ck_p           ,
   inout            DDR_cke            ,
   inout            DDR_cs_n           ,
   inout  [ 4-1: 0] DDR_dm             ,
   inout  [32-1: 0] DDR_dq             ,
   inout  [ 4-1: 0] DDR_dqs_n          ,
   inout  [ 4-1: 0] DDR_dqs_p          ,
   inout            DDR_odt            ,
   inout            DDR_ras_n          ,
   inout            DDR_reset_n        ,
   inout            DDR_we_n           ,

   // Red Pitaya periphery
  
   // ADC
   input  [16-1: 2] adc_dat_a_i        ,  // ADC CH1
   input  [16-1: 2] adc_dat_b_i        ,  // ADC CH2
   input            adc_clk_p_i        ,  // ADC data clock
   input            adc_clk_n_i        ,  // ADC data clock
   output [ 2-1: 0] adc_clk_o          ,  // optional ADC clock source
   output           adc_cdcs_o         ,  // ADC clock duty cycle stabilizer
   // DAC
   output [14-1: 0] dac_dat_o          ,  // DAC combined data
   output           dac_wrt_o          ,  // DAC write
   output           dac_sel_o          ,  // DAC channel select
   output           dac_clk_o          ,  // DAC clock
   output           dac_rst_o          ,  // DAC reset
   // PWM DAC
   output [ 4-1: 0] dac_pwm_o          ,  // serial PWM DAC
   // XADC
   input  [ 5-1: 0] vinp_i             ,  // voltages p
   input  [ 5-1: 0] vinn_i             ,  // voltages n
   // Expansion connector
   inout  [ 8-1: 0] exp_p_io           ,
   inout  [ 8-1: 0] exp_n_io           ,
   // SATA connector
   output [ 2-1: 0] daisy_p_o          ,  // line 1 is clock capable
   output [ 2-1: 0] daisy_n_o          ,
   input  [ 2-1: 0] daisy_p_i          ,  // line 1 is clock capable
   input  [ 2-1: 0] daisy_n_i          ,
   // LED
   output [ 8-1: 0] led_o       
);

//---------------------------------------------------------------------------------
//
//  Connections to PS

wire  [  4-1: 0] fclk               ; //[0]-125MHz, [1]-250MHz, [2]-50MHz, [3]-200MHz
wire  [  4-1: 0] frstn              ;

wire             ps_sys_clk         ;
wire             ps_sys_rstn        ;
wire  [ 32-1: 0] ps_sys_addr        ;
wire  [ 32-1: 0] ps_sys_wdata       ;
wire  [  4-1: 0] ps_sys_sel         ;
wire             ps_sys_wen         ;
wire             ps_sys_ren         ;
wire  [ 32-1: 0] ps_sys_rdata       ;
wire             ps_sys_err         ;
wire             ps_sys_ack         ;

// AXI masters
wire             axi1_clk    , axi0_clk    ;
wire             axi1_rstn   , axi0_rstn   ;
wire  [ 32-1: 0] axi1_waddr  , axi0_waddr  ;
wire  [ 64-1: 0] axi1_wdata  , axi0_wdata  ;
wire  [  8-1: 0] axi1_wsel   , axi0_wsel   ;
wire             axi1_wvalid , axi0_wvalid ;
wire  [  4-1: 0] axi1_wlen   , axi0_wlen   ;
wire             axi1_wfixed , axi0_wfixed ;
wire             axi1_werr   , axi0_werr   ;
wire             axi1_wrdy   , axi0_wrdy   ;

red_pitaya_ps i_ps (
  .FIXED_IO_mio       (  FIXED_IO_mio                ),
  .FIXED_IO_ps_clk    (  FIXED_IO_ps_clk             ),
  .FIXED_IO_ps_porb   (  FIXED_IO_ps_porb            ),
  .FIXED_IO_ps_srstb  (  FIXED_IO_ps_srstb           ),
  .FIXED_IO_ddr_vrn   (  FIXED_IO_ddr_vrn            ),
  .FIXED_IO_ddr_vrp   (  FIXED_IO_ddr_vrp            ),
  // DDR
  .DDR_addr      (DDR_addr    ),
  .DDR_ba        (DDR_ba      ),
  .DDR_cas_n     (DDR_cas_n   ),
  .DDR_ck_n      (DDR_ck_n    ),
  .DDR_ck_p      (DDR_ck_p    ),
  .DDR_cke       (DDR_cke     ),
  .DDR_cs_n      (DDR_cs_n    ),
  .DDR_dm        (DDR_dm      ),
  .DDR_dq        (DDR_dq      ),
  .DDR_dqs_n     (DDR_dqs_n   ),
  .DDR_dqs_p     (DDR_dqs_p   ),
  .DDR_odt       (DDR_odt     ),
  .DDR_ras_n     (DDR_ras_n   ),
  .DDR_reset_n   (DDR_reset_n ),
  .DDR_we_n      (DDR_we_n    ),

  .fclk_clk_o    (fclk        ),
  .fclk_rstn_o   (frstn       ),
  // ADC analog inputs
  .vinp_i        (vinp_i      ),  // voltages p
  .vinn_i        (vinn_i      ),  // voltages n
   // system read/write channel
  .sys_clk_o     (ps_sys_clk  ),  // system clock
  .sys_rstn_o    (ps_sys_rstn ),  // system reset - active low
  .sys_addr_o    (ps_sys_addr ),  // system read/write address
  .sys_wdata_o   (ps_sys_wdata),  // system write data
  .sys_sel_o     (ps_sys_sel  ),  // system write byte select
  .sys_wen_o     (ps_sys_wen  ),  // system write enable
  .sys_ren_o     (ps_sys_ren  ),  // system read enable
  .sys_rdata_i   (ps_sys_rdata),  // system read data
  .sys_err_i     (ps_sys_err  ),  // system error indicator
  .sys_ack_i     (ps_sys_ack  ),  // system acknowledge signal
  // AXI masters
  .axi1_clk_i    (axi1_clk    ),  .axi0_clk_i    (axi0_clk    ),  // global clock
  .axi1_rstn_i   (axi1_rstn   ),  .axi0_rstn_i   (axi0_rstn   ),  // global reset
  .axi1_waddr_i  (axi1_waddr  ),  .axi0_waddr_i  (axi0_waddr  ),  // system write address
  .axi1_wdata_i  (axi1_wdata  ),  .axi0_wdata_i  (axi0_wdata  ),  // system write data
  .axi1_wsel_i   (axi1_wsel   ),  .axi0_wsel_i   (axi0_wsel   ),  // system write byte select
  .axi1_wvalid_i (axi1_wvalid ),  .axi0_wvalid_i (axi0_wvalid ),  // system write data valid
  .axi1_wlen_i   (axi1_wlen   ),  .axi0_wlen_i   (axi0_wlen   ),  // system write burst length
  .axi1_wfixed_i (axi1_wfixed ),  .axi0_wfixed_i (axi0_wfixed ),  // system write burst type (fixed / incremental)
  .axi1_werr_o   (axi1_werr   ),  .axi0_werr_o   (axi0_werr   ),  // system write error
  .axi1_wrdy_o   (axi1_wrdy   ),  .axi0_wrdy_o   (axi0_wrdy   )   // system write ready
);

////////////////////////////////////////////////////////////////////////////////
// system bus decoder & multiplexer (it breaks memory addresses into 8 regions)
////////////////////////////////////////////////////////////////////////////////

wire              sys_clk   = ps_sys_clk  ;
wire              sys_rstn  = ps_sys_rstn ;
wire  [  32-1: 0] sys_addr  = ps_sys_addr ;
wire  [  32-1: 0] sys_wdata = ps_sys_wdata;
wire  [   4-1: 0] sys_sel   = ps_sys_sel  ;
wire  [8   -1: 0] sys_wen   ;
wire  [8   -1: 0] sys_ren   ;
wire  [8*32-1: 0] sys_rdata ;
wire  [8* 1-1: 0] sys_err   ;
wire  [8* 1-1: 0] sys_ack   ;
wire  [8   -1: 0] sys_cs    ;

assign sys_cs = 8'h01 << sys_addr[22:20];

assign sys_wen = sys_cs & {8{ps_sys_wen}};
assign sys_ren = sys_cs & {8{ps_sys_ren}};

assign ps_sys_rdata = sys_rdata[sys_addr[22:20]*32+:32];

assign ps_sys_err   = |(sys_cs & sys_err);
assign ps_sys_ack   = |(sys_cs & sys_ack);

// unused system bus slave ports

assign sys_rdata[5*32+:32] = 32'h0; 
assign sys_err  [5       ] =  1'b0;
assign sys_ack  [5       ] =  1'b1;

assign sys_rdata[6*32+:32] = 32'h0; 
assign sys_err  [6       ] =  1'b0;
assign sys_ack  [6       ] =  1'b1;

assign sys_rdata[7*32+:32] = 32'h0; 
assign sys_err  [7       ] =  1'b0;
assign sys_ack  [7       ] =  1'b1;

////////////////////////////////////////////////////////////////////////////////
// local signals
////////////////////////////////////////////////////////////////////////////////

// PLL signals
wire                  adc_clk_in;
wire                  pll_adc_clk;
wire                  pll_dac_clk_1x;
wire                  pll_dac_clk_2x;
wire                  pll_dac_clk_2p;
wire                  pll_ser_clk;
wire                  pll_pwm_clk;
wire                  pll_locked;

// fast serial signals
wire                  ser_clk ;

// PWM clock and reset
wire                  pwm_clk ;
reg                   pwm_rstn;

// ADC signals
wire                  adc_clk;
reg                   adc_rstn;
reg          [14-1:0] adc_dat_a, adc_dat_b;
wire  signed [14-1:0] adc_a    , adc_b    ;

// DAC signals
wire                  dac_clk_1x;
wire                  dac_clk_2x;
wire                  dac_clk_2p;
reg                   dac_rst;
reg          [14-1:0] dac_dat_a, dac_dat_b;
wire         [14-1:0] dac_a    , dac_b    ;
wire  signed [15-1:0] dac_a_sum, dac_b_sum;

//FIR-Filter
wire  signed [14-1:0] fir_a;

// ASG
wire  signed [14-1:0] asg_a    , asg_b    ;

// PID
wire  signed [14-1:0] pid_a    , pid_b    ;

// configuration
wire                  digital_loop;

////////////////////////////////////////////////////////////////////////////////
// PLL (clock and reaset)
////////////////////////////////////////////////////////////////////////////////

// diferential clock input
IBUFDS i_clk (.I (adc_clk_p_i), .IB (adc_clk_n_i), .O (adc_clk_in));  // differential clock input

red_pitaya_pll pll (
  // inputs
  .clk         (adc_clk_in),  // clock
  .rstn        (frstn[0]  ),  // reset - active low
  // output clocks
  .clk_adc     (pll_adc_clk   ),  // ADC clock
  .clk_dac_1x  (pll_dac_clk_1x),  // DAC clock 125MHz
  .clk_dac_2x  (pll_dac_clk_2x),  // DAC clock 250MHz
  .clk_dac_2p  (pll_dac_clk_2p),  // DAC clock 250MHz -45DGR
  .clk_ser     (pll_ser_clk   ),  // fast serial clock
  .clk_pwm     (pll_pwm_clk   ),  // PWM clock
  // status outputs
  .pll_locked  (pll_locked)
);

BUFG bufg_adc_clk    (.O (adc_clk   ), .I (pll_adc_clk   ));
BUFG bufg_dac_clk_1x (.O (dac_clk_1x), .I (pll_dac_clk_1x));
BUFG bufg_dac_clk_2x (.O (dac_clk_2x), .I (pll_dac_clk_2x));
BUFG bufg_dac_clk_2p (.O (dac_clk_2p), .I (pll_dac_clk_2p));
BUFG bufg_ser_clk    (.O (ser_clk   ), .I (pll_ser_clk   ));
BUFG bufg_pwm_clk    (.O (pwm_clk   ), .I (pll_pwm_clk   ));

// ADC reset (active low) 
always @(posedge adc_clk)
adc_rstn <=  frstn[0] &  pll_locked;

// DAC reset (active high)
always @(posedge dac_clk_1x)
dac_rst  <= ~frstn[0] | ~pll_locked;

// PWM reset (active low)
always @(posedge pwm_clk)
pwm_rstn <=  frstn[0] &  pll_locked;

////////////////////////////////////////////////////////////////////////////////
// ADC IO
////////////////////////////////////////////////////////////////////////////////

// generating ADC clock is disabled
assign adc_clk_o = 2'b10;
//ODDR i_adc_clk_p ( .Q(adc_clk_o[0]), .D1(1'b1), .D2(1'b0), .C(fclk[0]), .CE(1'b1), .R(1'b0), .S(1'b0));
//ODDR i_adc_clk_n ( .Q(adc_clk_o[1]), .D1(1'b0), .D2(1'b1), .C(fclk[0]), .CE(1'b1), .R(1'b0), .S(1'b0));

// ADC clock duty cycle stabilizer is enabled
assign adc_cdcs_o = 1'b1 ;

// IO block registers should be used here
// lowest 2 bits reserved for 16bit ADC
always @(posedge adc_clk)
begin
  adc_dat_a <= adc_dat_a_i[16-1:2];
  adc_dat_b <= adc_dat_b_i[16-1:2];
end
    
// transform into 2's complement (negative slope)
assign adc_a = digital_loop ? dac_a : {adc_dat_a[14-1], ~adc_dat_a[14-2:0]};
assign adc_b = digital_loop ? dac_b : {adc_dat_b[14-1], ~adc_dat_b[14-2:0]};

////////////////////////////////////////////////////////////////////////////////
// DAC IO
////////////////////////////////////////////////////////////////////////////////

// Sumation of ASG and PID signal perform saturation before sending to DAC 
assign dac_a_sum = asg_a + pid_a + fir_a;
assign dac_b_sum = asg_b + pid_b;

// saturation
assign dac_a = (^dac_a_sum[15-1:15-2]) ? {dac_a_sum[15-1], {13{~dac_a_sum[15-1]}}} : dac_a_sum[14-1:0];
assign dac_b = (^dac_b_sum[15-1:15-2]) ? {dac_b_sum[15-1], {13{~dac_b_sum[15-1]}}} : dac_b_sum[14-1:0];

// output registers + signed to unsigned (also to negative slope)
always @(posedge dac_clk_1x)
begin
  dac_dat_a <= {dac_a[14-1], ~dac_a[14-2:0]};
  dac_dat_b <= {dac_b[14-1], ~dac_b[14-2:0]};
end

// DDR outputs
ODDR oddr_dac_clk          (.Q(dac_clk_o), .D1(1'b0     ), .D2(1'b1     ), .C(dac_clk_2p), .CE(1'b1), .R(1'b0   ), .S(1'b0));
ODDR oddr_dac_wrt          (.Q(dac_wrt_o), .D1(1'b0     ), .D2(1'b1     ), .C(dac_clk_2x), .CE(1'b1), .R(1'b0   ), .S(1'b0));
ODDR oddr_dac_sel          (.Q(dac_sel_o), .D1(1'b1     ), .D2(1'b0     ), .C(dac_clk_1x), .CE(1'b1), .R(dac_rst), .S(1'b0));
ODDR oddr_dac_rst          (.Q(dac_rst_o), .D1(dac_rst  ), .D2(dac_rst  ), .C(dac_clk_1x), .CE(1'b1), .R(1'b0   ), .S(1'b0));
ODDR oddr_dac_dat [14-1:0] (.Q(dac_dat_o), .D1(dac_dat_b), .D2(dac_dat_a), .C(dac_clk_1x), .CE(1'b1), .R(dac_rst), .S(1'b0));

//---------------------------------------------------------------------------------
//  House Keeping

wire  [  8-1: 0] exp_p_in , exp_n_in ;
wire  [  8-1: 0] exp_p_out, exp_n_out;
wire  [  8-1: 0] exp_p_dir, exp_n_dir;

red_pitaya_hk i_hk (
  // system signals
  .clk_i           (  adc_clk                    ),  // clock
  .rstn_i          (  adc_rstn                   ),  // reset - active low
  // LED
  .led_o           (  led_o                      ),  // LED output
  // global configuration
  .digital_loop    (  digital_loop               ),
  // Expansion connector
  .exp_p_dat_i     (  exp_p_in                   ),  // input data
  .exp_p_dat_o     (  exp_p_out                  ),  // output data
  .exp_p_dir_o     (  exp_p_dir                  ),  // 1-output enable
  .exp_n_dat_i     (  exp_n_in                   ),
  .exp_n_dat_o     (  exp_n_out                  ),
  .exp_n_dir_o     (  exp_n_dir                  ),
   // System bus
  .sys_addr        (  sys_addr                   ),  // address
  .sys_wdata       (  sys_wdata                  ),  // write data
  .sys_sel         (  sys_sel                    ),  // write byte select
  .sys_wen         (  sys_wen[0]                 ),  // write enable
  .sys_ren         (  sys_ren[0]                 ),  // read enable
  .sys_rdata       (  sys_rdata[ 0*32+31: 0*32]  ),  // read data
  .sys_err         (  sys_err[0]                 ),  // error indicator
  .sys_ack         (  sys_ack[0]                 )   // acknowledge signal
);

IOBUF i_iobufp [8-1:0] (.O(exp_p_in), .IO(exp_p_io), .I(exp_p_out), .T(~exp_p_dir) );
IOBUF i_iobufn [8-1:0] (.O(exp_n_in), .IO(exp_n_io), .I(exp_n_out), .T(~exp_n_dir) );

//---------------------------------------------------------------------------------
//  FIR-Filter Application

fir_filter test_filter(
  .adc_clk_i       (  adc_clk                   ),
  .adc_rstn_i      (  adc_rstn                  ),
  .adc_i           (  adc_a                     ),
  .dac_o           (  fir_a                     )          
);


//---------------------------------------------------------------------------------
//  Oscilloscope application

wire trig_asg_out ;

red_pitaya_scope i_scope (
  // ADC
  .adc_a_i         (  adc_a                      ),  // CH 1
  .adc_b_i         (  adc_b                      ),  // CH 2
  .adc_clk_i       (  adc_clk                    ),  // clock
  .adc_rstn_i      (  adc_rstn                   ),  // reset - active low
  .trig_ext_i      (  exp_p_in[0]                ),  // external trigger
  .trig_asg_i      (  trig_asg_out               ),  // ASG trigger
  // AXI0 master                 // AXI1 master
  .axi0_clk_o    (axi0_clk   ),  .axi1_clk_o    (axi1_clk   ),
  .axi0_rstn_o   (axi0_rstn  ),  .axi1_rstn_o   (axi1_rstn  ),
  .axi0_waddr_o  (axi0_waddr ),  .axi1_waddr_o  (axi1_waddr ),
  .axi0_wdata_o  (axi0_wdata ),  .axi1_wdata_o  (axi1_wdata ),
  .axi0_wsel_o   (axi0_wsel  ),  .axi1_wsel_o   (axi1_wsel  ),
  .axi0_wvalid_o (axi0_wvalid),  .axi1_wvalid_o (axi1_wvalid),
  .axi0_wlen_o   (axi0_wlen  ),  .axi1_wlen_o   (axi1_wlen  ),
  .axi0_wfixed_o (axi0_wfixed),  .axi1_wfixed_o (axi1_wfixed),
  .axi0_werr_i   (axi0_werr  ),  .axi1_werr_i   (axi1_werr  ),
  .axi0_wrdy_i   (axi0_wrdy  ),  .axi1_wrdy_i   (axi1_wrdy  ),
  // System bus
  .sys_addr        (  sys_addr                   ),  // address
  .sys_wdata       (  sys_wdata                  ),  // write data
  .sys_sel         (  sys_sel                    ),  // write byte select
  .sys_wen         (  sys_wen[1]                 ),  // write enable
  .sys_ren         (  sys_ren[1]                 ),  // read enable
  .sys_rdata       (  sys_rdata[ 1*32+31: 1*32]  ),  // read data
  .sys_err         (  sys_err[1]                 ),  // error indicator
  .sys_ack         (  sys_ack[1]                 )   // acknowledge signal
);

//---------------------------------------------------------------------------------
//  DAC arbitrary signal generator

red_pitaya_asg i_asg (
   // DAC
  .dac_a_o         (  asg_a                      ),  // CH 1
  .dac_b_o         (  asg_b                      ),  // CH 2
  .dac_clk_i       (  adc_clk                    ),  // clock
  .dac_rstn_i      (  adc_rstn                   ),  // reset - active low
  .trig_a_i        (  exp_p_in[0]                ),
  .trig_b_i        (  exp_p_in[0]                ),
  .trig_out_o      (  trig_asg_out               ),
  // System bus
  .sys_addr        (  sys_addr                   ),  // address
  .sys_wdata       (  sys_wdata                  ),  // write data
  .sys_sel         (  sys_sel                    ),  // write byte select
  .sys_wen         (  sys_wen[2]                 ),  // write enable
  .sys_ren         (  sys_ren[2]                 ),  // read enable
  .sys_rdata       (  sys_rdata[ 2*32+31: 2*32]  ),  // read data
  .sys_err         (  sys_err[2]                 ),  // error indicator
  .sys_ack         (  sys_ack[2]                 )   // acknowledge signal
);

//---------------------------------------------------------------------------------
//  MIMO PID controller

red_pitaya_pid i_pid (
   // signals
  .clk_i           (  adc_clk                    ),  // clock
  .rstn_i          (  adc_rstn                   ),  // reset - active low
  .dat_a_i         (  adc_a                      ),  // in 1
  .dat_b_i         (  adc_b                      ),  // in 2
  .dat_a_o         (  pid_a                      ),  // out 1
  .dat_b_o         (  pid_b                      ),  // out 2
  // System bus
  .sys_addr        (  sys_addr                   ),  // address
  .sys_wdata       (  sys_wdata                  ),  // write data
  .sys_sel         (  sys_sel                    ),  // write byte select
  .sys_wen         (  sys_wen[3]                 ),  // write enable
  .sys_ren         (  sys_ren[3]                 ),  // read enable
  .sys_rdata       (  sys_rdata[ 3*32+31: 3*32]  ),  // read data
  .sys_err         (  sys_err[3]                 ),  // error indicator
  .sys_ack         (  sys_ack[3]                 )   // acknowledge signal
);

//---------------------------------------------------------------------------------
//  Analog mixed signals
//  XADC and slow PWM DAC control

wire  [ 24-1: 0] pwm_cfg_a;
wire  [ 24-1: 0] pwm_cfg_b;
wire  [ 24-1: 0] pwm_cfg_c;
wire  [ 24-1: 0] pwm_cfg_d;

red_pitaya_ams i_ams (
   // power test
  .clk_i           (  adc_clk                    ),  // clock
  .rstn_i          (  adc_rstn                   ),  // reset - active low
  // PWM configuration
  .dac_a_o         (  pwm_cfg_a                  ),
  .dac_b_o         (  pwm_cfg_b                  ),
  .dac_c_o         (  pwm_cfg_c                  ),
  .dac_d_o         (  pwm_cfg_d                  ),
   // System bus
  .sys_addr        (  sys_addr                   ),  // address
  .sys_wdata       (  sys_wdata                  ),  // write data
  .sys_sel         (  sys_sel                    ),  // write byte select
  .sys_wen         (  sys_wen[4]                 ),  // write enable
  .sys_ren         (  sys_ren[4]                 ),  // read enable
  .sys_rdata       (  sys_rdata[ 4*32+31: 4*32]  ),  // read data
  .sys_err         (  sys_err[4]                 ),  // error indicator
  .sys_ack         (  sys_ack[4]                 )   // acknowledge signal
);

red_pitaya_pwm pwm [4-1:0] (
  // system signals
  .clk   (pwm_clk ),
  .rstn  (pwm_rstn),
  // configuration
  .cfg   ({pwm_cfg_d, pwm_cfg_c, pwm_cfg_b, pwm_cfg_a}),
  // PWM outputs
  .pwm_o (dac_pwm_o),
  .pwm_s ()
);

//---------------------------------------------------------------------------------
//  Daisy chain
//  simple communication module

assign daisy_p_o = 1'bz;
assign daisy_n_o = 1'bz;

endmodule
This is my filter code. The filter coefficients implemented here describe a low-pass filter. I simulated it in multisim and it works fine, but maybe something is wrong here.

Code: Select all

module fir_filter(
    input  wire            adc_clk_i,
    input  wire            adc_rstn_i,
    input  wire  [14-1: 0] adc_i,
    output wire  [14-1: 0] dac_o
);

//---------------------------------------------------------------------------------
//Input buffer for coefficients (For use with system bus)
reg [25-1: 0] b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10;

always @(posedge adc_clk_i) begin
    b0 <=  25'h8312;
    b1 <=  25'h10624;
    b2 <=  25'h3126E;
    b3 <=  25'h51EB8;
    b4 <=  25'h72B02;
    b5 <=  25'h83126;
    b6 <=  25'h72B02;
    b7 <=  25'h51EB8;
    b8 <=  25'h3126E;
    b9 <=  25'h10624;
    b10 <= 25'h8312;
end

//---------------------------------------------------------------------------------
//Input buffer for ADC data and for creating time delays 

reg [14-1: 0] buff_u0, buff_u1, buff_u2, buff_u3, buff_u4, buff_u5, buff_u6,
              buff_u7, buff_u8, buff_u9, buff_u10;

always @(posedge adc_clk_i) begin
    if (~adc_rstn_i) begin
        buff_u10 <= 14'b0;
        buff_u9 <= 14'b0;
        buff_u8 <= 14'b0;
        buff_u7 <= 14'b0;
        buff_u6 <= 14'b0;
        buff_u5 <= 14'b0;
        buff_u4 <= 14'b0;
        buff_u3 <= 14'b0;
        buff_u2 <= 14'b0;
        buff_u1 <= 14'b0;
        buff_u0 <= 14'b0;
    end 
    else begin   
        buff_u10 <= buff_u9;
        buff_u9 <= buff_u8;
        buff_u8 <= buff_u7;
        buff_u7 <= buff_u6;
        buff_u6 <= buff_u5;
        buff_u5 <= buff_u4;
        buff_u4 <= buff_u3;
        buff_u3 <= buff_u2;
        buff_u2 <= buff_u1;
        buff_u1 <= buff_u0;
        buff_u0 <= adc_i;
    end
end

//---------------------------------------------------------------------------------
//Multiplication of buffer and coefficients

reg [39-1: 0] mult_b0, mult_b1, mult_b2, mult_b3, mult_b4, mult_b5, mult_b6, mult_b7,
              mult_b8, mult_b9, mult_b10;

always @(posedge adc_clk_i) begin
    mult_b0 <= ($signed(b0) * $signed(buff_u0));
    mult_b1 <= ($signed(b1) * $signed(buff_u1));
    mult_b2 <= ($signed(b2) * $signed(buff_u2));
    mult_b3 <= ($signed(b3) * $signed(buff_u3));
    mult_b4 <= ($signed(b4) * $signed(buff_u4));
    mult_b5 <= ($signed(b5) * $signed(buff_u5));
    mult_b6 <= ($signed(b6) * $signed(buff_u6));
    mult_b7 <= ($signed(b7) * $signed(buff_u7));
    mult_b8 <= ($signed(b8) * $signed(buff_u8));
    mult_b9 <= ($signed(b9) * $signed(buff_u9));
    mult_b10 <= ($signed(b10) * $signed(buff_u10));
end

//---------------------------------------------------------------------------------
//Summarize the results

reg [44-1: 0] sum_fir;

always @(posedge adc_clk_i) begin
    sum_fir <= $signed(mult_b0) + $signed(mult_b1) + $signed(mult_b2) + 
               $signed(mult_b3) + $signed(mult_b4) + $signed(mult_b5) + 
               $signed(mult_b6) + $signed(mult_b7) + $signed(mult_b8) + 
               $signed(mult_b9) + $signed(mult_b10); 
end

//Arithmetic Left Shift to get back to a width of 14-bit
assign dac_o = $signed(sum_fir) >>> 30;

endmodule //fir_filter
The problem is that I still can not measure any output signal at the HF-Output. Maybe there is some way to test the HF-Output with a simple module?

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: FPGA-Module Integration in RedPitaya FPGA Code

Post by Nils Roos » Wed Jan 11, 2017 2:18 pm

I've not had the opportunity to try it out on a Red PItaya yet, but the implementation of your filter module in Vivado shows severe timing issues (setup and hold violations of more than one full clock period). It is possible that this affects the stability of the whole logic design.

georgwild
Posts: 8
Joined: Fri May 06, 2016 2:22 pm

Re: FPGA-Module Integration in RedPitaya FPGA Code

Post by georgwild » Tue Jan 24, 2017 9:23 pm

I've now had a closer look at the design and there are definitely servere timing issues.

As I don't want to redesign the whole filter module, is it possible to lower the adc clock frequency in the 'red_pitaya_pll.sv' file to handle the timing issues, or would that create other problems within the FPGA?
Because after lowering the adc clock frequency the timing analysis looks identical to the one in the standard project.

I know that a lower clock frequency will result in a lower input bandwidth, but that is no problem.

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: FPGA-Module Integration in RedPitaya FPGA Code

Post by Nils Roos » Sat Jan 28, 2017 5:01 pm

Unless you rewired your Red Pitaya for external or FPGA clock generation, the ADC clock is fixed at 125MHz from the onboard crystal oscillator.
That means that the adc_dat_a_i bus would need to be equipped with some kind of clock domain crossing and/or rate conversion code instead of the current straight-forward buffering in red_pitaya_top:

Code: Select all

always @(posedge adc_clk)
begin
  adc_dat_a <= adc_dat_a_i[16-1:2];
  adc_dat_b <= adc_dat_b_i[16-1:2];
end
Provided you do that, I see no problem in lowering adc_clk.

Loes
Posts: 2
Joined: Wed Jul 29, 2020 8:54 am

Re: FPGA-Module Integration in RedPitaya FPGA Code

Post by Loes » Thu Jul 30, 2020 10:45 am

Hello,

Is it fine to resurrect this thread ?
My question is related.

I have created a new module in a similar way. However I would like to program it via a C program on the linux side.

I want to modify the output of the FIR module only on a 'gated" way. SO I want to define a delay after the trigger signal and a gate width.

I connected my new module to the system bus :

Code: Select all

  // System bus
  .sys_addr      (sys[5].addr ),
  .sys_wdata     (sys[5].wdata),
  .sys_wen       (sys[5].wen  ),
  .sys_ren       (sys[5].ren  ),
  .sys_rdata     (sys[5].rdata),
  .sys_err       (sys[5].err  ),
  .sys_ack       (sys[5].ack  )
Inside the module I made something like this :

Code: Select all

//---------------------------------------------------------------------------------
//  System bus connection

always @(posedge adc_clk_i)
if (adc_rstn_i == 1'b0) begin
   myparameter       <=  32'd0      ;
end else begin
   if (sys_wen) begin
      if (sys_addr[19:0]==20'h100)   myparameter       <= sys_wdata[32-1:0] ;
   end
end

wire sys_en;
assign sys_en = sys_wen | sys_ren;

always @(posedge adc_clk_i)
if (adc_rstn_i == 1'b0) begin
   sys_err <= 1'b0 ;
   sys_ack <= 1'b0 ;
end else begin
   sys_err <= 1'b0 ;

   casez (sys_addr[19:0])
     20'h00100 : begin sys_ack <= sys_en;          sys_rdata <= {myparameter}  ; end
       default : begin sys_ack <= sys_en;          sys_rdata <=  32'h0                  ; end
   endcase
end
And with such a construction the parameters of my module can be accessed :
read : monitor 0x40500100
write : monitor 0x40500100 0x[value]

The base is 0x405.... as the module index is 5.
note : I had to "unmute" this address range in red_pitaya_top.sv

I would eventually like to add function to this list : https://docs.rs/rp-sys/0.4.0/rp_sys/index.html
Such as rp_defineMYMOULEDelay or rp_defineMYMODULEGateWidth or other.

-- edit --
I found this topic that is actually helping me a lot for the FPGA side
viewtopic.php?t=1353
and toward the end of this PDF there is an example of parameter acquisition.
And this one discussing memory mapping :
viewtopic.php?t=1124

My question about how to make custom functions still stand, but most of my underlying questions were already answered.
I will re-edit if needed. :D

Post Reply
jadalnie klasyczne ekskluzywne meble wypoczynkowe do salonu ekskluzywne meble tapicerowane ekskluzywne meble do sypialni ekskluzywne meble włoskie

Who is online

Users browsing this forum: No registered users and 2 guests