Jump to content
  • 0

Problem with UART data transfer of XADC acquired signal (Nexys A7)


photoM

Question

Hi,

I am trying to use a Nexys A7 to capture an analog signal that I then want to transfer to my computer using a UART bridge. My problem is that the XADC/UART combination only works if I transfer the bits [15:8] of the XADC output data, for anything else, for example: [14:7], my UART transfer rate reduces and the entire thing starts behaving very strange

I used the XADC IP Source to set up the XADC(DRP, Continuous Mode, Single Channel, 100KSPS via VAUXP3/VAUXN3; I unchecked all the alarm and calibration things for now) and I am able to read analog data that I input via the respective pins: I can display it on the 16 LEDs and I can also transfer bits 15:8 to my computer and I see the correct signal.

I am running the serial transfer very fast (baud rate of 5e6) as I want to transfer a lot of data but things seem to be working both with CPP or Labview based serial communication. If I use the code below I get stable transfer for the simulated signal. I am using the data ready signal from the XADC "XADC_ready" to initiate the UART transfer so the code is linked to the somewhat "black-box" of the XADC IP source.

If I send the two 8 bit values below to the UART "w_RX_Byte" everything works fine and I am able to read a stable signal on the computer. If I substitute the simulated data for XADC_data[15:8], the 8 most significant bits from the XADC, the transfer works equally well and I don't have any problems. However, as soon as I use any other bits from XADC_data (for example [14:7] or [7:0]) the entire transfer breaks down. Unfortunately, I don't understand why/how. I try to read 4000 bytes with the computer which works well for [15:8] but for all other options the transfer fails to capture the correct number: sometimes I obtain 0 bytes, sometimes 2000 and rarely 4000. I am inputting a 100-200 mV sine-function and it looks like as if the transfer rate is coupled to the frequency of that function (not the case if I read 15:8 which allows me to nicely capture the sine-function but only the 8 most significant bits of it)..

I would be very grateful if someone had an idea 🙂 

Sending the data: (works for: simulated or XADC_data[15:8]; does not work for XADC_data[x:x-7] for x !=15)

always @(posedge CLK100MHZ) //should have done this with a state machine!
   begin
    if (XADC_ready && wait_data == 0) //when XADC is ready and "idle" go ahead and send the first 8 bit
        begin
            w_RX_Byte <= 8'b11110001; //XADC_data[15:8];
            w_RX_DV <= 1'b1;
            wait_data <= wait_data +1;
        end
     else
        begin
            if (w_TX_DONE) //first UART tranfer complete
                begin
                    if (wait_data == 1) //send the second 8 bit
                        begin
                            wait_data <= wait_data +1;
                            w_RX_Byte <= 8'b00110001; // works for: XADC_data[15:8] but I would like to send XADC_data[7:0]; 
                            w_RX_DV <= 1'b1;
                       end
                    else    //go back to idle
                        wait_data <= 0;       
                end
            else
                w_RX_DV <= 1'b0;
        end
   end

XADC "black box code" in top.v:

xadc_onechannel xadc_onechanneltest  (
   .di_in(0),              // input wire [15 : 0] di_in
   .daddr_in(xadc_address),        // input wire [6 : 0] daddr_in
   .den_in(XADC_enable),            // input wire den_in
   .dwe_in(0),            // input wire dwe_in
   .drdy_out(XADC_ready),        // output wire drdy_out
   .do_out(XADC_data),            // output wire [15 : 0] do_out
   .dclk_in(CLK100MHZ),          // input wire dclk_in
   .reset_in(0),        // input wire reset_in
   .vp_in(vp_in),              // input wire vp_in
   .vn_in(vn_in),              // input wire vn_in
   .vauxp3(vauxp3),          // input wire vauxp2
   .vauxn3(vauxn3),          // input wire vauxn2
   .channel_out(),  // output wire [4 : 0] channel_out
   .eoc_out(XADC_enable),          // output wire eoc_out
   .alarm_out(),      // output wire alarm_out
   .eos_out(),          // output wire eos_out
   .busy_out()        // output wire busy_out
 );

UART transmitter in top.v:

 UART_TX #(
        .CLKS_PER_BIT(c_CLKS_PER_BIT)   //ensure baud rate is set correctly
        )    
    UART_TX(
        .i_Clk(CLK100MHZ),
        .i_TX_DV(w_RX_DV),                        
        .i_TX_BYTE(w_RX_Byte),
        .o_TX_SERIAL(w_TX_SERIAL),
        .o_TX_ACTIVE(w_TX_ACTIVE),
        .o_TX_DONE(w_TX_DONE)
    );
    
assign o_UART_TX = w_TX_ACTIVE ? w_TX_SERIAL : 1'b1;    //UART_TX "sends" information; if TRANSMITTER active, send the bit otherwise send 1

top.v declarations:

module top
#(
     parameter xadc_address = 8'h13,
     parameter c_CLKS_PER_BIT = 20         //I am running 5MS/s
)
(
    input CLK100MHZ,
    //XADC related
    input vauxn3,
    input vauxp3,
    input vn_in,
    input vp_in,        
    //UART related
    input i_UART_RX,
    output o_UART_TX
    
//    output reg [15:0] LED
    );
     //This is for XADC
     wire XADC_enable;       //bounce back and forth with XADC to know when to read again
     wire XADC_ready;        //tells us when data is ready
     wire [15:0] XADC_data;  //holds 16 bit data from XADC
     
     //This is for UART protcol
     wire w_TX_SERIAL;                      //Serial Data connection from Transmitter
     wire w_TX_ACTIVE;                      //Active information of Transmitter connection
     wire w_TX_DONE;

     integer wait_data = 0;
     //This is for testing the fast UART
     integer w_RX_DV = 0;						    //Receiver's Data Valid connection
     reg [7:0] w_RX_Byte = 8'b00000000;             //Receiver's Data Byte connection

UART transmitter code:

module UART_TX
#
(
parameter CLKS_PER_BIT = 20		
)
(
input i_Clk,
input i_TX_DV,						//Data Valid
input [7:0] i_TX_BYTE,				//Parallel Data
output reg o_TX_SERIAL,				//Serial Data
output o_TX_ACTIVE,					//Information for TRANSMITTER being active
output o_TX_DONE					//Information for Transmitting process being done
);

parameter [2:0] IDLE = 3'b000;			//Default State 
parameter [2:0] START_BIT = 3'b001;		//Start bit's State 
parameter [2:0] DATA_BITS = 3'b010;		//Data's State
parameter [2:0] STOP_BIT = 3'b011;		//Stop bit's State
parameter [2:0] CLEANUP = 3'b100;		//This state is for returning to the Default State after 1 clock cycle

reg [2:0] r_STATE = 0;					//State Variable
reg [9:0] r_Clock_Count = 0;			//Counter for sampling data
reg [2:0] r_BIT_INDEX = 0;				//Index counter variable for receiving data
reg [7:0] r_TX_BYTE = 0;				//Variable which will be transmitted data as byte domain
reg r_TX_ACTIVE = 0;					//Registered information for TRANSMITTER being active
reg r_TX_DONE = 0;						//Registered information for Transmitting process being done


//Opposite algorithm of UART Receiver

always@(posedge i_Clk)
	begin
		case(r_STATE)
			IDLE:
				begin
					r_Clock_Count <= 0;
					r_BIT_INDEX <= 0;
					r_TX_DONE <= 1'b0;
					o_TX_SERIAL <= 1'b1;
					
					if(i_TX_DV == 1'b1)
						begin
							r_TX_ACTIVE <= 1'b1;
							r_TX_BYTE <= i_TX_BYTE;
							r_STATE <= START_BIT;
						end
					else
						r_STATE <= IDLE;
				end
			START_BIT:
				begin
					o_TX_SERIAL <= 1'b0;
					
					if(r_Clock_Count < CLKS_PER_BIT -1)
						begin
							r_Clock_Count <= r_Clock_Count + 1;
							r_STATE <= START_BIT;	
						end
					else
						begin
							r_Clock_Count <= 0;
							r_STATE <= DATA_BITS;
						end
				end
			DATA_BITS:
				begin
					o_TX_SERIAL <= r_TX_BYTE[r_BIT_INDEX];
					
					if(r_Clock_Count < CLKS_PER_BIT -1)
						begin
							r_Clock_Count <= r_Clock_Count + 1;
							r_STATE <= DATA_BITS;
						end
					else
						begin
							r_Clock_Count <= 0;
							if(r_BIT_INDEX < 7)
								begin
									r_BIT_INDEX <= r_BIT_INDEX + 1;
									r_STATE <= DATA_BITS;
								end
							else
								begin
									r_BIT_INDEX <= 0;
									r_STATE <= STOP_BIT;
								end
						end
				end
			STOP_BIT:
				begin
					o_TX_SERIAL <= 1'b1;
						if(r_Clock_Count < CLKS_PER_BIT -1)
							begin
								r_Clock_Count <= r_Clock_Count + 1;
								r_STATE <= STOP_BIT;
							end
						else
							begin
								r_Clock_Count <= 0;
								r_STATE <= CLEANUP;
								r_TX_DONE <= 1'b1;
								r_TX_ACTIVE <= 1'b0;
							end
				end
			CLEANUP:
				begin
					r_STATE <= IDLE;
					r_TX_DONE <= 1'b1;
				end
			default:
				r_STATE <= IDLE;
		endcase
	end
	
assign o_TX_ACTIVE = r_TX_ACTIVE;
assign o_TX_DONE = r_TX_DONE;

endmodule

 	

 

Link to comment
Share on other sites

1 answer to this question

Recommended Posts

  • 0
Let's discuss your 5000000 baud rate. If your FTDI USB UART Bridge device uses the VCP driver then your maximum baud rate is limited. Also, OS "FIFO" resources are limited. Have you considered as to whether or not your HDL design requires a FIFO? If you use the D2XX driver then you can use the D2XX API to get higher baud rates using C or C++. In general there are no standard applications that use the D2XX driver and support 8 or 12 Mbaud. You will still need to use hardware flow control in your PC software ( as well as a FIFO in your HDL design to transfer large amounts of data ). FTDI "H" devices support the 8 and 12 Mbaud rates as special cases. Below those rates there is a limited selection of exact baud rates available. FTDI application notes aren't always that helpful but AN_120 might be of interest.

UART stands for Universal Asynchronous Receiver Transmitter. As the baud period gets smaller there are a number of problems to deal with. For one, the achievable baud rates become less fine grained. Also, the allowable deviation between master clock rates becomes tighter. Usually, the way to deal with these issues is to increase the clock frequency. You can easily do this in an FPGA, but the internal clock frequency of the bridge device is fixed.

Without delving into your implementation, you might consider deciding on a more carefully selected baud rate, and perhaps HDL UART clock frequency.

Before fixing the communication problem it might be a good idea to think about what your project requirements are. Do you need to capture live data with low latency and process sample on the fly in your PC application? Do you need to capture a long sequence of data for post-analysis? Starting off with a good specification will inform your data interface design choices. This means having a formal, or even informal, system design that is appropriate for your project goals in place before trying to implement it. Having a PC application in the processing loop is a very different thing than having an FPGA data capture design that transfer data to a PC application. Edited by zygot
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...