Post Go back to editing

Custom Reference Design | Zedboard | AD4630/4030

Category: Hardware
Product Number: Zedboard | AD4630/4030

After some time developing an application on the Zedboard using the Python framework and a Matlab connection to visualize the data acquired by the AD4030 board, I wanted to go a little further.

The idea is to modify the reference design, i.e. add/modify blocks in the Vivado IP Integrator. Previously I have modified and developed other of these blocks for other SoC boards although they had a slightly different architecture since in this case I need to start from this reference to be able to use the acquisition board with its drivers to be able to use it later without too much complication and to be able to use the work already done by you.

If I understand the concept correctly, in Vivado we can visualize the 'axi_pwm_gen' which is in charge of sending the configuration commands to the acquisition block as I have read in this Wiki. In the post they also talk about the ext_sync signal that according to my understanding can be used to start the acquisition at a certain instant with an external trigger.

Therefore, in a first approach I had thought to add a very simple block that reads for example the press of one of the buttons of the PL (BTND - R16) and at that moment performs a HIGH to LOW transition in the 'external_sync' input of the 'axi_pwm_gen' block. I leave you a pictures and continue explaining below:



In the images you can see the block I had thought of using ('external_trigger_0'). The block has an 'external_pin' (std_logic) input that connects to an external port or input with the same name. In turn the block has an output 'trigger_out' (std_logic) which will be held at '1' after reset and will wait until it sees a stimulus on the button (value of '1') from which it will change the output value to '0'.

This output will be connected to the 'ext_sync' input of the 'axi_pwm_gen' block.

In addition to this, in constraints file I added a line indicating the assignment of this PL button (BTND) to the new port ('external_pin') like this:

set property -dict {PACKAGE_PIN R16 IOSTANDARD LVCMOS25} [get_ports {external_pin}]

For the design to run correctly the synthesis and implementation I had to change the previous assignment for pin R16 (in this case to gpio_bd[1]) and assign an unused PIN to that port.

In addition, I also added the external port as an input on the top module of the design so that it would be recognized.

Finally, I generated the bitstream without failures and exported the XSA. Although the block I have added follows the AXI protocol, in principle I have not used this functionality, I simply generated it this way for a future more advanced implementation in which the block could read commands from the PS.
Because of this, as I think it is not necessary to modify the .dtb file since I don't want to use it from the PS, right now it only has functionality in the PL so I have generated the new BOOT.BIN file as stated in this other Wiki.

What I expected after these modifications was to see that when I tried to capture the data without pressing the button I would not receive anything or I would receive random values or 0s by initializing the buffer. On the other hand, after pressing the button I expected to see a correct reception of the ADC data. However, when I try to receive the data from the buffer, the program freezes and I can't receive anything.

Thank you very much for your time if you read the whole post, I will be very grateful to receive any kind of help or feedback. And anything extra that is necessary for understanding, just let me know please.

PD:

 

For the verification of this data reception I am using in the first instance what I have seen in this post. Specifically the following code snippet:

root@analog:/sys/bus/iio/devices/iio:device0# echo 1 > scan_elements/in_voltage0_differential0_en
root@analog:/sys/bus/iio/devices/iio:device0# echo 1 > scan_elements/in_voltage1_differential1_en
root@analog:/sys/bus/iio/devices/iio:device0# echo 400 > buffer/length
root@analog:/sys/bus/iio/devices/iio:device0# echo 1 > buffer/enable
root@analog:/sys/bus/iio/devices/iio:device0# hexdump -n 400 /dev/iio\:device0
0000000 e942 000d 0011 0000 afaf 000d 0029 0000
0000010 753b 000d fff5 00ff 39fa 000d 0018 0000
0000020 013e 000d 0017 0000 c776 000c fff4 00ff
0000030 8e84 000c 0017 0000 55d4 000c 0052 0000
0000040 1dab 000c 000b 0000 e5b9 000b 0049 0000
0000050 ab19 000b 0013 0000 6f56 000b 0035 0000
0000060 3470 000b 0020 0000 f9a1 000a 0037 0000
0000070 bcc1 000a 0003 0000 7f89 000a 000d 0000
0000080 4458 000a 0003 0000 0978 000a 000d 0000
0000090 cea9 0009 0041 0000 9551 0009 fff2 00ff
00000a0 5b80 0009 fff1 00ff 210c 0009 0015 0000
00000b0 e486 0008 ffe8 00ff a8d1 0008 ffec 00ff
00000c0 6e13 0008 004e 0000 33a0 0008 001a 0000
00000d0 f7df 0007 fffd 00ff bba2 0007 fffd 00ff
00000e0 7ead 0007 fffe 00ff 43e0 0007 0041 0000
00000f0 08a8 0007 0023 0000 cc9c 0006 ffed 00ff
0000100 9031 0006 001c 0000 5370 0006 fff6 00ff
0000110 1721 0006 0040 0000 dcec 0005 ffe5 00ff
0000120 9ffc 0005 000d 0000 61f3 0005 0016 0000
0000130 247d 0005 0023 0000 e55d 0004 0006 0000
0000140 a725 0004 000e 0000 6d7b 0004 0045 0000
0000150 32e4 0004 ffaa 00ff f77e 0003 ffca 00ff
0000160 bc75 0003 0036 0000 809d 0003 0019 0000
0000170 4582 0003 ffe1 00ff 0921 0003 ffdf 00ff
0000180 c9a5 0002 ffd1 00ff 8a1c 0002 0015 0000
0000190
root@analog:/sys/bus/iio/devices/iio:device0/# echo 0 > buffer/enable


Although it is true, that the version of used for the Kuiper Linux image, the same elements do not appear to me under the directory "/sys/bus/iio/devices/iio:device0/scan_elements/". In the example, it looks like the following appears:

root@analog:/sys/bus/iio/devices/iio:device0/# ls buffer
data_available	enable	length	length_align_bytes  watermark
root@analog:/sys/bus/iio/devices/iio:device0# ls scan_elements/
in_voltage0_differential0_en	  in_voltage0_differential0_type  in_voltage1_differential1_index
in_voltage0_differential0_index  in_voltage1_differential1_en    in_voltage1_differential1_type

Something similar appears to me, as you can see here:



However, I modified the example a bit by running the following:
echo 1 > scan_elements/in_voltage0_en
echo 400 > buffer/length
echo 1 > buffer/enable
hexdump -n 400 /dev/iio\:device0




.
[edited by: jlanzuela at 8:32 AM (GMT -4) on 20 Oct 2023]
  • Some extra information that you leave me in the post is that I also previously tested the added block with an even simpler logic in which the block directly ejects a 0 at the output without waiting for any stimulus from the button.

    In this case, the design works perfectly which makes me think that the problem is related to a misuse of the external port 'external_pin' or its declaration in the constraints... If anyone can relate to the problem or has experience with this, I would greatly appreciate it.

    Thank you very much again.

    - Jorge

  • Hi,

    Just letting you know that someone was assigned to your thread and well assist you as soon as possible.

    Best regards,
    Iulia

  • Hello Jorge,

     Sorry for the late reply. Can you share the log file, please? The problem could be that the trigger pin is not toggled in the AD4630 configuration phase, which means that the SPI Engine Offload module will not send the configuration commands to the SPI Engine execution based on the SPI Engine offload Wiki page. I will take a closer look in the following days.

    Thanks,

    Paul

  • Hi,

    Some heads up from me on this.
    If the pwm_gen does not generate pulses/requests to the spi_engine, no data will be captured, this is clear to everyone. But this means that the DMA will not get valid data(valid signal from the spi engine). This means that the DMA will not move DATA into memory(the buffer). No interrupts... If the buffer does not get filled in some time (a timeout parameter) this will result in an error or maybe freeze. So, when reading data, in this scenario, one must set a timeout. By default the timeout is 0. More info here.

    This is why you don't get any zeros or junk data and the app freezes.

    My recommendations
    Let the spi_engine capture data at its desirable rates. don't stop/pause the cnv_generator. Instead add an IP or TRL module between SPI engine and DMA. It can be a multiplexer, send zeros before the trigger and data after the trigger. This will give you the desired behavior.

    Even better.
    You are probably interested in capturing samples on a event, case in which you should activate the DMA start sync feature and connect the trigger to that signal. In this case, although the DMA has valid data form SPI_engine, It will not transfer it until your trigger is asserted. Timeout must be set in this case, no junks data, only some samples of interest.
    Have a look at:
    https://github.com/analogdevicesinc/hdl/blob/master/projects/m2k/common/m2k_bd.tcl#L114
    https://github.com/analogdevicesinc/hdl/blob/master/projects/m2k/common/m2k_bd.tcl#L239

    Andrei


  • Hello  . First of all I wanted to thank you for the quick help you are giving me.

    I have done the first of your solutions (I think successfully), however I think the implementation I am looking for is more focused on the second one you propose. Before I show you what I have come up with, I wanted to ask about that 'timeout' you are talking about as I am not sure what you are referring to, I can't seem to locate it in the ADI AXI DMAC IP.

    I have created my own IP and placed it between the 'data_reorder' (after the SPI_engine) and the DMA block. I am using an external signal as a trigger, in this case it is a rectangular signal that goes high when I want the acquisition to start. At the moment, once this trigger arrives, a counter has been implemented that drives a multiplexer to send the spi_engine signal or 0s. That signal, it stays at 1 for 10000 samples at this time.

    In addition, I am using the s_axis_user[0:0] signal from the ADI AXI DMAC block to signal the start of the acquisition and I am also using the s_axis_last signal to signal the end. The problem is that in the ADI IIO Osciloscope application, everything seems to work fine but sometimes when acquiring the acquisition freezes and never gets to acquire, however if you stop it and re-acquire it works, so it works but with bugs.

    Any idea what is going on, could the implementation be the right one, or if not, can you guide me a bit?

    I attach here some screenshots of the design and some code.

    Thank you very much!

    Images:

    external_trigger IP:

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity external_trigger_v1_0 is
    	generic (
    		-- Users to add parameters here
            DEVICE 		: std_logic_vector(7 downto 0) := x"38";
    		-- User parameters ends
    		-- Do not modify the parameters beyond this line
    
    
    		-- Parameters of Axi Slave Bus Interface S00_AXI
    		C_S00_AXI_DATA_WIDTH	: integer	:= 32;
    		C_S00_AXI_ADDR_WIDTH	: integer	:= 4
    		
    	);
    	port (
    		-- Users to add ports here
    		
            external_pin    : in std_logic;
            trigger_out     : out std_logic;
            Sel_T           : in std_logic;
            
            MCLK		: in	std_logic;
    		nRST		: in	std_logic;
    		SDA_IN		: in	std_logic;
    		SCL_IN		: in	std_logic;
    		SDA_OUT		: out	std_logic;
    		SCL_OUT		: out	std_logic;
    		ADDRESS		: out	std_logic_vector(7 downto 0);
    		DATA_OUT	: out	std_logic_vector(7 downto 0);
    		DATA_IN		: in	std_logic_vector(7 downto 0);
    		WR			: out	std_logic;
    		RD			: out	std_logic;
            READ_DONE   : out   std_logic; 
            test        : in    std_logic;
            	
    		-- User ports ends
    		-- Do not modify the ports beyond this line
    
    
    		-- Ports of Axi Slave Bus Interface S00_AXI
    		s00_axi_aclk	: in std_logic;
    		s00_axi_aresetn	: in std_logic;
    		s00_axi_awaddr	: in std_logic_vector(C_S00_AXI_ADDR_WIDTH-1 downto 0);
    		s00_axi_awprot	: in std_logic_vector(2 downto 0);
    		s00_axi_awvalid	: in std_logic;
    		s00_axi_awready	: out std_logic;
    		s00_axi_wdata	: in std_logic_vector(C_S00_AXI_DATA_WIDTH-1 downto 0);
    		s00_axi_wstrb	: in std_logic_vector((C_S00_AXI_DATA_WIDTH/8)-1 downto 0);
    		s00_axi_wvalid	: in std_logic;
    		s00_axi_wready	: out std_logic;
    		s00_axi_bresp	: out std_logic_vector(1 downto 0);
    		s00_axi_bvalid	: out std_logic;
    		s00_axi_bready	: in std_logic;
    		s00_axi_araddr	: in std_logic_vector(C_S00_AXI_ADDR_WIDTH-1 downto 0);
    		s00_axi_arprot	: in std_logic_vector(2 downto 0);
    		s00_axi_arvalid	: in std_logic;
    		s00_axi_arready	: out std_logic;
    		s00_axi_rdata	: out std_logic_vector(C_S00_AXI_DATA_WIDTH-1 downto 0);
    		s00_axi_rresp	: out std_logic_vector(1 downto 0);
    		s00_axi_rvalid	: out std_logic;
    		s00_axi_rready	: in std_logic
    	);
    end external_trigger_v1_0;
    
    architecture arch_imp of external_trigger_v1_0 is
    
    	-- component declaration
    	component external_trigger_v1_0_S00_AXI is
    		generic (
    		C_S_AXI_DATA_WIDTH	: integer	:= 32;
    		C_S_AXI_ADDR_WIDTH	: integer	:= 4
    		);
    		port (
    		S_AXI_ACLK	: in std_logic;
    		S_AXI_ARESETN	: in std_logic;
    		S_AXI_AWADDR	: in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
    		S_AXI_AWPROT	: in std_logic_vector(2 downto 0);
    		S_AXI_AWVALID	: in std_logic;
    		S_AXI_AWREADY	: out std_logic;
    		S_AXI_WDATA	: in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
    		S_AXI_WSTRB	: in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0);
    		S_AXI_WVALID	: in std_logic;
    		S_AXI_WREADY	: out std_logic;
    		S_AXI_BRESP	: out std_logic_vector(1 downto 0);
    		S_AXI_BVALID	: out std_logic;
    		S_AXI_BREADY	: in std_logic;
    		S_AXI_ARADDR	: in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
    		S_AXI_ARPROT	: in std_logic_vector(2 downto 0);
    		S_AXI_ARVALID	: in std_logic;
    		S_AXI_ARREADY	: out std_logic;
    		S_AXI_RDATA	: out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
    		S_AXI_RRESP	: out std_logic_vector(1 downto 0);
    		S_AXI_RVALID	: out std_logic;
    		S_AXI_RREADY	: in std_logic
    		);
    	end component external_trigger_v1_0_S00_AXI;
    
    signal trigger, trigg_mem : std_logic;
    signal cnt: unsigned(31 downto 0);
    signal rising_trigger: std_logic;
    signal external_pin_in, new_in, last_in: std_logic;
    
    type tstate is ( S_IDLE, S_START, S_SHIFTIN, S_RW, S_SENDACK, S_SENDACK2, S_SENDNACK,
    		S_ADDRESS, S_WRITE, S_SHIFTOUT, S_READ, S_WAITACK
    	);
    
    	type toperation is (OP_READ, OP_WRITE);
    	
    	signal state : tstate;
    	signal next_state : tstate;
    	signal operation : toperation;
    
    	signal rising_scl, falling_scl : std_logic;
    	signal address_i : std_logic_vector(7 downto 0);
    	signal next_address : std_logic_vector(7 downto 0);
    	signal counter : integer range 0 to 7;
    	signal start_cond : std_logic;
    	signal stop_cond  : std_logic;
    	signal sda_q, sda_qq, sda_qqq : std_logic;
    	signal scl_q, scl_qq, scl_qqq : std_logic;
    	signal shiftreg : std_logic_vector(7 downto 0);
    	signal sda: std_logic;
    	signal address_incr : std_logic;
    	signal rd_d : std_logic;
        signal read_data_done : std_logic;
        signal N_samples: unsigned(18 downto 0) := to_unsigned(500000,19); 
    
    begin
    
    -- Instantiation of Axi Bus Interface S00_AXI
    external_trigger_v1_0_S00_AXI_inst : external_trigger_v1_0_S00_AXI
    	generic map (
    		C_S_AXI_DATA_WIDTH	=> C_S00_AXI_DATA_WIDTH,
    		C_S_AXI_ADDR_WIDTH	=> C_S00_AXI_ADDR_WIDTH
    	)
    	port map (
    		S_AXI_ACLK	=> s00_axi_aclk,
    		S_AXI_ARESETN	=> s00_axi_aresetn,
    		S_AXI_AWADDR	=> s00_axi_awaddr,
    		S_AXI_AWPROT	=> s00_axi_awprot,
    		S_AXI_AWVALID	=> s00_axi_awvalid,
    		S_AXI_AWREADY	=> s00_axi_awready,
    		S_AXI_WDATA	=> s00_axi_wdata,
    		S_AXI_WSTRB	=> s00_axi_wstrb,
    		S_AXI_WVALID	=> s00_axi_wvalid,
    		S_AXI_WREADY	=> s00_axi_wready,
    		S_AXI_BRESP	=> s00_axi_bresp,
    		S_AXI_BVALID	=> s00_axi_bvalid,
    		S_AXI_BREADY	=> s00_axi_bready,
    		S_AXI_ARADDR	=> s00_axi_araddr,
    		S_AXI_ARPROT	=> s00_axi_arprot,
    		S_AXI_ARVALID	=> s00_axi_arvalid,
    		S_AXI_ARREADY	=> s00_axi_arready,
    		S_AXI_RDATA	=> s00_axi_rdata,
    		S_AXI_RRESP	=> s00_axi_rresp,
    		S_AXI_RVALID	=> s00_axi_rvalid,
    		S_AXI_RREADY	=> s00_axi_rready
    	);
    
    	-- Add user logic here
    	
    	trigger_out <= trigger;
    	
    	process(s00_axi_aclk, s00_axi_aresetn, external_pin)
    	begin
    	   if(s00_axi_aresetn = '0') then
    	       trigger <= '1';
    	   elsif(rising_edge(s00_axi_aclk)) then
    	   if(Sel_T = '1') then
                if(rising_trigger = '1' and trigg_mem = '1') then
                    trigger <= '0';
                else
                    if(cnt > N_samples) then                
                       trigger <= '1';
                    end if;
                end if;
           else
                trigger <= '0';
           end if;    
           end if;
    	end process;
    	
    	process(s00_axi_aclk, s00_axi_aresetn, rising_trigger)
    	begin
    	   if(s00_axi_aresetn = '0') then
    	       cnt <= (others => '0');
    	   elsif(rising_edge(s00_axi_aclk)) then
    	       if(rising_trigger = '1' and trigg_mem = '1') then
    	           cnt <= (others => '0'); 
    	       else
    	           cnt <= cnt+1;
               end if;
    	   end if;
    	end process;
    	
    	rising_trigger <= new_in and not last_in;
    	
    	process(s00_axi_aclk, s00_axi_aresetn)
    	begin
    	   if(s00_axi_aresetn = '0') then
    	       external_pin_in <= '0';
    	       new_in <=  '0';
    	       last_in <= '0';
    	   elsif(rising_edge(s00_axi_aclk)) then
                external_pin_in <= external_pin;
                new_in <= external_pin_in;
                last_in <= new_in;
    	   end if;
    	end process;
    	
    	process(s00_axi_aclk, s00_axi_aresetn)
    	begin
    	   if(s00_axi_aresetn = '0') then
    	       trigg_mem <= '0';
    	   elsif(rising_edge(s00_axi_aclk)) then
               trigg_mem <= trigger;
    	   end if;
    	end process;
    	
    -- #i2c state machine	
    	ADDRESS <= address_i;
    	next_address <= (others=>'0') when (address_i = x"FF") else
    		std_logic_vector(to_unsigned(to_integer(unsigned( address_i )) + 1, 8));
    	
    	S_RSY: process(MCLK,nRST)
    	begin
    		if (nRST = '0') then
    			sda_q <= '1';
    			sda_qq <= '1';
    			sda_qqq <= '1';
    			scl_q <= '1';
    			scl_qq <= '1';
    			scl_qqq <= '1';
    		elsif (MCLK'event and MCLK='1') then
    			sda_q <= SDA_IN;
    			sda_qq <= sda_q;
    			sda_qqq <= sda_qq;
    			scl_q <= SCL_IN;
    			scl_qq <= scl_q;
    			scl_qqq <= scl_qq;
    		end if;
    	end process S_RSY;
    
    	rising_scl <= scl_qq and not scl_qqq;
    	falling_scl <= not scl_qq and scl_qqq;
    		
    	START_BIT: process(MCLK,nRST)
    	begin
    		if (nRST = '0') then
    			start_cond <= '0';
    		elsif (MCLK'event and MCLK='1') then
    			if (sda_qqq = '1' and sda_qq = '0' and scl_qq = '1') then
    				start_cond <= '1';
    			else	
    				start_cond <= '0';
    			end if;
    		end if;
    	end process START_BIT;
    	
    	STOP_BIT: process(MCLK,nRST)
    	begin
    		if (nRST = '0') then
    			stop_cond <= '0';
    		elsif (MCLK'event and MCLK='1') then
    			if (sda_qqq = '0' and sda_qq = '1' and scl_qq = '1') then
    				stop_cond <= '1';
    			else	
    				stop_cond <= '0';
    			end if;
    		end if;
    	end process STOP_BIT;
    	
    	sda <= sda_qq;
    	
    	RD_DELAY: process(MCLK, nRST)
    	begin
    		if (nRST = '0') then
    			RD <= '0';
    		elsif (MCLK'event and MCLK='1') then
    			RD <= rd_d;
    		end if;
    	end process RD_DELAY;
    
    	OTO: process(MCLK, nRST)
    	begin
    		if (nRST = '0') then
    			state <= S_IDLE;
    			SDA_OUT <= '1';
    			SCL_OUT <= '1';
    			WR <= '0';
    			rd_d <= '0';
    			address_i <= (others=>'0');
    			DATA_OUT <= (others=>'0');
    			shiftreg <= (others=>'0');
                read_data_done <= '0';
    		elsif (MCLK'event and MCLK='1') then
    			if (stop_cond = '1') then
    				state <= S_IDLE;
    				SDA_OUT <= '1';
    				SCL_OUT <= '1';
    				operation <= OP_READ;
    				WR <= '0';
    				rd_d <= '0';
    				address_incr <= '0';
    			elsif(start_cond = '1') then
    				state <= S_START;
    				SDA_OUT <= '1';
    				SCL_OUT <= '1';
    				operation <= OP_READ;
    				WR <= '0';
    				rd_d <= '0';
    				address_incr <= '0';
    			elsif(state = S_IDLE) then
    				state <= S_IDLE;
    				SDA_OUT <= '1';
    				SCL_OUT <= '1';
    				operation <= OP_READ;
    				WR <= '0';
    				rd_d <= '0';
    				address_incr <= '0';
    			elsif(state = S_START) then
    				shiftreg <= (others=>'0');
    				state <= S_SHIFTIN;
    				next_state <= S_RW;
    				counter <= 6;
    			elsif(state = S_SHIFTIN) then
    				if (rising_scl = '1') then
    					shiftreg(7 downto 1) <= shiftreg(6 downto 0);
    					shiftreg(0) <= sda;
    					if (counter = 0) then
    						state <= next_state;
    						counter <= 7;
    					else
    						counter <= counter - 1;
    					end if;
    				end if;
    			elsif(state = S_RW) then
    				if (rising_scl = '1') then
    					if (shiftreg = DEVICE) then
    						state <= S_SENDACK;
    						if (sda = '1') then
    							operation <= OP_READ;
    							-- next_state <= S_READ; -- no needed
    							rd_d <= '1';
    						else
    							operation <= OP_WRITE;
    							next_state <= S_ADDRESS;
    							address_incr <= '0';
    						end if;
    					else
    						state <= S_SENDNACK;
    					end if;
    				end if;
    			elsif(state = S_SENDACK) then
    				WR <= '0';
    				rd_d <= '0';
    				if (falling_scl = '1') then
    					SDA_OUT <= '0';
    					counter <= 7;
    					if (operation= OP_WRITE) then
    						state <= S_SENDACK2;
    					else -- OP_READ
    						state <= S_SHIFTOUT;
    						shiftreg <= DATA_IN;
                            read_data_done <= '1';
    					end if;
    				end if;
    			elsif(state = S_SENDACK2) then
    				if (falling_scl = '1') then
    					SDA_OUT <= '1';
    					state <= S_SHIFTIN;
    					shiftreg <= (others=>'0');
    					if (address_incr = '1') then
    						address_i <= next_address;
    					end if;
    				end if;
    			elsif(state = S_SENDNACK) then
    				if (falling_scl = '1') then
    					SDA_OUT <= '1';
    					state <= S_IDLE;
    				end if;
    			elsif(state = S_ADDRESS) then
    				address_i <= shiftreg;
    				next_state <= S_WRITE;
    				state <= S_SENDACK;
    				address_incr <= '0';
    			elsif(state = S_WRITE) then
    				DATA_OUT <= shiftreg;
    				next_state <= S_WRITE;
    				state <= S_SENDACK;
    				WR <= '1';
    				address_incr <= '1';
    			elsif(state = S_SHIFTOUT) then
                    read_data_done <= '0';
    				if (falling_scl = '1') then
    					SDA_OUT <= shiftreg(7);
    					shiftreg(7 downto 1) <= shiftreg(6 downto 0);
    					shiftreg(0) <= '1';
    					if (counter = 0) then
    						state <= S_READ;
    						address_i <= next_address;
    						rd_d <= '1';
    					else
    						counter <= counter - 1;
    					end if;
    				end if;
    			elsif(state = S_READ) then
    				rd_d <= '0';
    				if (falling_scl = '1') then
    					SDA_OUT <= '1';
    					state <= S_WAITACK;
    				end if;
    			elsif(state = S_WAITACK) then
    				if (rising_scl = '1') then
    					if (sda = '0') then
    						state <= S_SHIFTOUT;
    						counter <= 7;
    						shiftreg <= DATA_IN;
                            read_data_done <= '1';
    					else
    						state <= S_IDLE;
    					end if;
    				end if;
    			end if;
    		end if;
    	end process OTO;
    					
        READ_DONE <= read_data_done;
    
    	-- User logic ends
    
    end arch_imp;
    

    z_multiplex IP:

    ----------------------------------------------------------------------------------
    -- Company:
    -- Engineer:
    --
    -- Create Date: 10/30/2023 11:18:09 AM
    -- Design Name:
    -- Module Name: z_multiplex - Behavioral
    -- Project Name:
    -- Target Devices:
    -- Tool Versions:
    -- Description:
    --
    -- Dependencies:
    --
    -- Revision:
    -- Revision 0.01 - File Created
    -- Additional Comments:
    --
    ----------------------------------------------------------------------------------


    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;

    -- Uncomment the following library declaration if using
    -- arithmetic functions with Signed or Unsigned values
    --use IEEE.NUMERIC_STD.ALL;

    -- Uncomment the following library declaration if instantiating
    -- any Xilinx leaf cells in this code.
    --library UNISIM;
    --use UNISIM.VComponents.all;

    entity z_multiplex is
        Port ( s_axis_tdata : in STD_LOGIC_VECTOR (63 downto 0);
               s_axis_tvalid : in STD_LOGIC;
               s_axis_tready : out STD_LOGIC;
               m_axis_tdata : out STD_LOGIC_VECTOR (63 downto 0);
               m_axis_tready : in STD_LOGIC;
               m_axis_tvalid : out STD_LOGIC;
               m_axis_tuser : out STD_LOGIC_VECTOR (0 downto 0);
               m_axis_tlast : out STD_LOGIC;
               axis_aclk : in STD_LOGIC;
               axis_aresetn : in STD_LOGIC;
               trigger : in STD_LOGIC);
    end z_multiplex;

    architecture Behavioral of z_multiplex is

    signal rising_trigger : std_logic;
    signal last_in_rising : std_logic;

    signal falling_trigger : std_logic;
    signal last_in_falling : std_logic;

    begin

    s_axis_tready <= m_axis_tready;
    m_axis_tvalid <= s_axis_tvalid;

    ------------------------------------------------------------------------------------------------------

    process(axis_aclk, axis_aresetn)
    begin
        if(axis_aresetn = '0') then
        elsif(rising_edge(axis_aclk)) then
        end if;
    end process;

    -----------------------------------------------------------------------------------------------------

    process(trigger)
    begin
        if(trigger = '0') then
            m_axis_tdata <= s_axis_tdata;
        else
            m_axis_tdata <= (others => '0');
        end if;
    end process;

    ----------------------------------------------------------------------------------------------------

    falling_trigger <= last_in_falling and not trigger;

    process(axis_aclk, axis_aresetn)
    begin
       if(axis_aresetn = '0') then
            last_in_falling <= '0';
       elsif(rising_edge(axis_aclk)) then
            last_in_falling <= trigger;
       end if;
    end process;

    process(falling_trigger)
    begin
        if(falling_trigger = '1') then
            m_axis_tuser(0) <= '1';

        else
            m_axis_tuser(0) <= '0';
        end if;
    end process;

    ---------------------------------------------------------------------------------------------------

    rising_trigger <= trigger and not last_in_rising;

    process(axis_aclk, axis_aresetn)
    begin
       if(axis_aresetn = '0') then
            last_in_rising <= '0';
       elsif(rising_edge(axis_aclk)) then
            last_in_rising <= trigger;
       end if;
    end process;

    process(rising_trigger)
    begin
        if(rising_trigger = '1') then
            m_axis_tlast <= '1';
        else
            m_axis_tlast <= '0';
        end if;
    end process;

    end Behavioral;

  • Hello again!

    I will try to give a little more information as I think my last one doesn't have too clear information. Also, I will tell you my progress to see if you can help me.

    To recap, I'm trying to triggedly acquire a signal with the AD4030-24 module that is attached to the zedboard. For this, I am going to use an external signal with a square shape. When this signal has a rising edge, you have to start the acquisition for X samples (in this case I am trying to do it for 0.5s).

    The acquisition module is configured to acquire at 2 MSPS while the communications clock (axis_aclk) has a frequency of 100 MHz.

    Now, following some of your recommendations and making some advances on the design I have something like what I am going to explain next.
    I have introduced 4 blocks on the design (maybe the names are not the most appropriate, sorry if they can lead to confusion):

    A.- External trigger
    B.- Axis Boradcaster
    C.- Trigger multiplexer
    D.- Z Multiplexer

    Block A is a block with AXI protocol (so that in the future it can have some extra functionality and communication with the PS). But, now it simply waits to get a rising edge on the external trigger signal ('external_pin'), then it sets an output signal called 'trigger_out' to 0 for 50 million samples (100 MHz / 2 MSPS = 50). In this way, this signal will be low for the desired acquisition time.

    Block B (AXIS Broadcaster) has been introduced after the 'data_reorder' block in order to have the possibility to use the trigged acquisition function or the continuous one that previously existed in the original design. One of the broadcaster outputs is routed directly to block C and one to block D.

    Block C is simply a multiplexer that is responsible for choosing between two inputs. The first of these will be one of the broadcaster's outputs and the other will come from a custom block (the D block). In this way, using a switch it will be possible to choose one operating mode or the other.

    Finally, block D is responsible for collecting one of the broadcaster outputs and using the 'trigger_out' signal coming from block A will be responsible for routing the data to block C with the 'tvalid' signal at 1 while 'trigger_out' has a value of 0, i.e. during the 50 million samples after a rising edge in the trigger signal. In addition this block also sets the m_axis_tuser[0:0] signal to 1 for one clock cycle when the trigger arrives and the m_axis_tlast signal to 1 for one clock cycle when the 50 million samples are finished. This allows to control the ADI AXI DMA Controller block, to perform a synchronized transfer according to my understanding.
    - The ADI AXI DMA Controller block is in AXI Streaming mode with the Transfer Sync checkbox enabled. -

    What's the problem?

    Using the 'trigger' mode I am seeing an unwanted behavior in the IIO Oscilloscope program. When entering a 1 kHz signal and trying to acquire 1 million samples (0.5s at 2 MSPS) I observe 10 periods when I really should be observing about 500. My surprise came when I zoomed in on the signal and saw that at each level change, each different sample stays with the same value for 50 samples, that is, each of the values of my signal stays for 50 samples at the same amplitude level. Thinking about it carefully, I saw that it made all the sense in the world due to the difference in clocks between the acquisition board (2 MSPS) and the communications clock (100 MHz). The m_axis_tvalid signal that I modify in my D block is kept at 1 for the whole time that I have the trigger signal low (all 50 million samples) therefore, as the acquisition is slower than the communication in the PL, for each new sample the DMA collects 50.

    When I realized I tried to use a counter, in such a way that the tvalid signal would only be at 1 every 50 clock cycles, but in this case the application freezes and I am never able to acquire samples.

    Any additional information please let me know as well as any further explanation you need to make.

    Thank you very much for your attention and your time.
    Regards,
    Jorge.

     

  • Hello ,

    I think another way to solve the problem could be to count the number of valid rising edges until you transfer the number of samples you need, which will help you control the fifo_wr_sync signal. In general, the primary approach in this case is to keep the valid path unbroken and control the flow based on enable signals. 

    Please let me know if there is any additional information that you need.

    Thanks,

    Paul

  • Hi  

    The truth is that I don't quite understand the solution you are proposing.

    I am using the AXI Streaming method for the ADI AXI DMA Controller, so there is no 'fifo_wr_sync' signal.
    On the other hand, I understand that what you mean by counting the number of valid rising edges is a bit the method that I had thought as correct, since this way I matched the ADC clock with the communications clock but I don't know why I have not been able to get it to work this way.

    Are there any details regarding the ADI AXI DMA Controller block that I don't know about any 'timeouts'? I don't understand why by setting the m_axis_tvalid signal high 1 out of every 50 clock cycles the communication is blocked and frozen.

    Jorge.

     

  • Hello ,

    From what I know there is a timeout in the Linux drivers but I'm not 100% sure who's responsible for it. Can you please share the block design of the final project or maybe a Github branch where I could find the project sources so I can reproduce the setup? 

    Thanks,

    Paul

  • Hi  ,

    Do you have any news?

    Best regards,
    Iulia