Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17257 Discussions

How to write data in a file from FPGA

MG007
Beginner
8,263 Views

 Hello,

 

I am a beginner using Quartus and programming FPGA. I need to implement a binary search on FPGA and record the result of the search in a file (a 7 binary code each time). Below is the implementation I did using Quartus and it is synthesizable. 

I just need help on how to store the D_out, every time the data is ready (valid bit is high).

 

Screenshot 2023-10-18 at 9.25.28 PM.png

Labels (1)
0 Kudos
27 Replies
_AK6DN_
Valued Contributor II
6,864 Views

Store it in a file where? On what device/media? On your Windows PC filesystem? Or on an SDcard attached to your FPGA?

Probably the simplest solution is to dump the data out using a UART serial module and connect the serial pins thru the
appropriate level conversion logic to a USB serial converter plugged into your PC. Then you can capture the result on a terminal window.

0 Kudos
MG007
Beginner
6,816 Views

Thank you for the reply.

 

Storing data in anyway is useful for me. Any way that is easier works for me. 

Can you please explain a bit more about the solution you mentioned? What hardware and software I will need to do that?

0 Kudos
_AK6DN_
Valued Contributor II
6,808 Views

Until we know what your hardware platform it is hard to be specific.

What FPGA are you using? Is it on a standard development board, or on a custom board of your own design?

What version of Quartus on which platform (Windows, Linux, etc)?

0 Kudos
MG007
Beginner
6,782 Views

FPGA is developement board DE2-115. An I am using Quartus prime 21.1 on Windows. 

0 Kudos
_AK6DN_
Valued Contributor II
6,779 Views

DE2-115 is a very nice development board, I also happen to have one of those.

 

It has a standard 9p RS232 compatible serial port, so you could just connect that to a PC via a COM port or a SERIAL/USB adapter.

So you could just implement a UART module in the FPGA and write text/data to the serial port and capture it on a PC.

 

It also has an SDcard socket, but that will require much more effort to use in any effective way.

Same for the etherNet port connections on the board.

 

0 Kudos
MG007
Beginner
6,754 Views

Thanks for the reply.

So I only need to implement UART module in FPGA through Quartus and assign the pin of the module to Rs-232 and connect the R-232 to the PC?

0 Kudos
_AK6DN_
Valued Contributor II
6,747 Views

Correct.

In fact you probably only need a UART transmitter module to send data from the FPGA to the PC.

A UART transmitter is the conceptually simpler to implement compared to a UART receiver.

0 Kudos
MG007
Beginner
6,435 Views

I tried to implement a UART module in FPGA. The issue is capturing the data in the PC now I guess. How I can capture the data sent from the FPGA to PC? 

 

Thank you for your help.

0 Kudos
_AK6DN_
Valued Contributor II
6,424 Views

Have you installed any Windows serial terminal program. There are a few listed here ...

https://learn.adafruit.com/windows-tools-for-the-electrical-engineer/serial-terminal

PuTTY is pretty common, been around for a long time.

 

Personally I use a program called TeraTerm  https://en.wikipedia.org/wiki/Tera_Term
its been around for 30+ years now. Runs fine on Windows 10.

 

You probably want to send your data as printable ascii text (ie numbers) to make it
easy to capture and save, but raw binary would work also.

0 Kudos
MG007
Beginner
6,418 Views

Thank you for the reply. I will check the softwares recommended.

 

Thanks for the help!

0 Kudos
MG007
Beginner
6,381 Views

I think I am doing something wrong. 

I found this verilog code for UART transmitter online that I used. I wanted to test the transmitter so I set the input data to be controlled by switches on the fpga.  I used puTTy as you recommended and also Serial Port Monitor to get the serial data in PC but what I get is not correct.

 

Here is the code for transmitter:

module uart_tx
#(parameter CLKS_PER_BIT = 44)
(
input i_Clock,
input i_Tx_DV,
input [7:0] i_Tx_Byte,
output o_Tx_Active,
output reg o_Tx_Serial,
output o_Tx_Done
);

parameter s_IDLE = 3'b000;
parameter s_TX_START_BIT = 3'b001;
parameter s_TX_DATA_BITS = 3'b010;
parameter s_TX_STOP_BIT = 3'b011;
parameter s_CLEANUP = 3'b100;

reg [2:0] r_SM_Main = 0;
reg [7:0] r_Clock_Count = 0;
reg [2:0] r_Bit_Index = 0;
reg [7:0] r_Tx_Data = 0;
reg r_Tx_Done = 0;
reg r_Tx_Active = 0;

always @(posedge i_Clock)
begin

case (r_SM_Main)
s_IDLE :
begin
o_Tx_Serial <= 1'b1; // Drive Line High for Idle
r_Tx_Done <= 1'b0;
r_Clock_Count <= 0;
r_Bit_Index <= 0;

if (i_Tx_DV == 1'b1)
begin
r_Tx_Active <= 1'b1;
r_Tx_Data <= i_Tx_Byte;
r_SM_Main <= s_TX_START_BIT;
end
else
r_SM_Main <= s_IDLE;
end // case: s_IDLE


// Send out Start Bit. Start bit = 0
s_TX_START_BIT :
begin
o_Tx_Serial <= 1'b0;

// Wait CLKS_PER_BIT-1 clock cycles for start bit to finish
if (r_Clock_Count < CLKS_PER_BIT-1)
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_TX_START_BIT;
end
else
begin
r_Clock_Count <= 0;
r_SM_Main <= s_TX_DATA_BITS;
end
end // case: s_TX_START_BIT


// Wait CLKS_PER_BIT-1 clock cycles for data bits to finish
s_TX_DATA_BITS :
begin
o_Tx_Serial <= r_Tx_Data[r_Bit_Index];

if (r_Clock_Count < CLKS_PER_BIT-1)
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_TX_DATA_BITS;
end
else
begin
r_Clock_Count <= 0;

// Check if we have sent out all bits
if (r_Bit_Index < 7)
begin
r_Bit_Index <= r_Bit_Index + 1;
r_SM_Main <= s_TX_DATA_BITS;
end
else
begin
r_Bit_Index <= 0;
r_SM_Main <= s_TX_STOP_BIT;
end
end
end // case: s_TX_DATA_BITS


// Send out Stop bit. Stop bit = 1
s_TX_STOP_BIT :
begin
o_Tx_Serial <= 1'b1;

// Wait CLKS_PER_BIT-1 clock cycles for Stop bit to finish
if (r_Clock_Count < CLKS_PER_BIT-1)
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_TX_STOP_BIT;
end
else
begin
r_Tx_Done <= 1'b1;
r_Clock_Count <= 0;
r_SM_Main <= s_CLEANUP;
r_Tx_Active <= 1'b0;
end
end // case: s_Tx_STOP_BIT


// Stay here 1 clock
s_CLEANUP :
begin
r_Tx_Done <= 1'b1;
r_SM_Main <= s_IDLE;
end


default :
r_SM_Main <= s_IDLE;

endcase
end

assign o_Tx_Active = r_Tx_Active;
assign o_Tx_Done = r_Tx_Done;

endmodule

 

 

 

This is the Quartus modules and pins:

Screenshot 2023-11-02 at 8.14.02 PM.png

 This is what I get from using PuTTy:

Screenshot 2023-11-02 at 8.14.50 PM.png

What I get from Serial port Monitor:

Screenshot 2023-11-02 at 8.15.52 PM.png

 

0 Kudos
_AK6DN_
Valued Contributor II
6,371 Views

Well the verilog code tells me basically nothing.

What clock frequency are you using, what baud rate, how many data bits and stop bits have you configured?

The serial program needs to set the same parameters for the serial line as well (baud rate, number of data and stop bits).

You also will need to invert the data line, or not, to get the correct polarity based on your serial connection.

 

Configuring the UART code to send some fixed pattern (ie, like the letter 'A' or something) would be a start.

And viewing the serial line result on a simulator (like modelsim, etc) to validate the waveform.

 

Based on your experience you have jumped about five steps ahead when you need to take one step at a time.

 

As an example, here is a waveform output from a UART module I wrote years ago.

Once I validated the RXD and TXD waveform patterns and timing were right I could connect it up to a real serial interface.

 

And here is the testbench code I use to test my UART module ...

`timescale 1ns / 1ns

module test;

    parameter		SYSFREQ = 50000, // KHz
			BAUDRATE = 38400, // baud
			SYSPER = 1000000/SYSFREQ, // ns/clk
			BITPER = 1000000000/BAUDRATE, // ns/bit
			TPD = 1; // ns

    reg			sysclk;
    reg 		reset;

    wire 		txd;
    reg 		rxd;

    reg 		rxdd;

    wire [7:0] 		rxdata;
    wire 		rxferr;
    wire 		rxoerr;
    wire 		rxperr;
    wire 		rxerr;
    wire 		rxrdy;
    wire 		rxrd;

    reg [7:0] 		txdata;
    wire 		txrdy;
    wire 		txwr;

    parameter 		START = 1'b0,
			STOP = 1'b1;

    initial rxdd = 1'b1;
    always @(rxd)
	rxdd <= #(10.5*BITPER+48*SYSPER) rxd;

    wire 		delta = rxdd ^ txd;

    initial
	begin
	sysclk = 1;
	forever #(500000.0/SYSFREQ) sysclk = ~sysclk;
	end

    initial
	begin
	$timeformat(-6, 3, "us", 15);
	$dumpfile("test.vcd");
	$dumpvars(2,test);
	reset = 1'b1;
	#950;
	reset = 1'b0;
	end
	
    task rxchar;
	input [7:0] 	char;
	reg [9:0] 	bits;
	reg [3:0] 	i;
        begin
	rxd = 1'b1;
	bits = {STOP,char[7:0],START};
	for (i = 0; i <= 9; i = i+1) #BITPER rxd = bits[i];
	end
    endtask // rxchar

    initial
	begin
	rxd = 1'b1;
	#(2.0*BITPER);
	rxchar(8'b01111111);
	#(1.5*BITPER);
	rxchar(8'b10101010);
	#(2.5*BITPER);
	rxchar(8'b01010101);
	#(2.0*BITPER);
	rxchar(8'b10000000);
	#(1.5*BITPER);
	rxchar(8'b00000010);
	#(1.0*BITPER);
	rxchar(8'b00000000);
	rxchar(8'b01010101);
	rxchar(8'b01000101);
	rxchar(8'b01010101);
	rxchar(8'b01000101);
	rxchar(8'b01010101);
	rxchar(8'b00000000);
	#(3.0*BITPER);
	rxd = 1'b0;
	#(15.0*BITPER);
	rxd = 1'b1;
	#(2.0*BITPER);
	$write("\n\n");
	$finish;
	end

    reg 		txrdyd, rxrdyd, txgo;

    wire 		rxrdy_rising = rxrdy & ~rxrdyd;
    wire 		txrdy_falling = ~txrdy & txrdyd;

    always @(posedge sysclk)
	begin
	if (reset)
	    begin
	    txgo <= #TPD 0;
	    rxrdyd <= #TPD 0;
	    txrdyd <= #TPD 0;
	    txdata <= #TPD 0;
	    end
	else
	    begin
	    rxrdyd <= #TPD rxrdy;
	    txrdyd <= #TPD txrdy;
	    if (rxrdy_rising) txdata <= #TPD rxdata;
	    if (rxrdy_rising) txgo <= #TPD 1'b1; else if (txrdy_falling) txgo <= #TPD 1'b0;
	    end
	end

    always @(posedge sysclk)
	begin
	if (!reset)
	    begin
	    if (rxrdy_rising) $write("\n%t rxdata=%o\n", $time, rxdata);
	    if (txrdy_falling) $write("%t txdata=%o\n", $time, txdata);
	    end
	end

    assign 		rxrd = txgo;
    assign 		txwr = txgo;

    assign		rxerr = rxferr|rxoerr|rxperr;

    uart #(.TPD(TPD)) uart
	( .clk		(sysclk),
	  .reset	(reset),
	  .bauddiv      (16'd163),
	  .stopbits	(4'd1),
	  .databits	(4'd8),
	  .rxd		(rxd),
	  .rxrd		(rxrd),
 	  .rxrdy	(rxrdy),
 	  .rxferr	(rxferr),
 	  .rxoerr	(rxoerr),
 	  .rxperr	(rxperr),
 	  .rxdata	(rxdata),
	  .txd		(txd),
	  .txwr		(txwr),
	  .txrdy	(txrdy),
	  .txdata	(txdata)
	  );

endmodule // test

 

0 Kudos
MG007
Beginner
6,337 Views

I am using the clock on the FPGA which is 50 MHz, and baud rate of 115200. 

based on the code, there is one start bit and one stop bit. (start bit =0, start sending data, and stop bit=1, end of data).

Yes I need to test it in ModelSim first.

I thought it might be simple since it is only transmitter and I can test it on pga right away.

 

0 Kudos
MG007
Beginner
6,183 Views

I tested the code for UART transmission that I had in modelsim and it looks working fine! (I only tested the transmission, since I only need transmission)

 

I again tested it on FPGA with baud rate of 9600, clk of 50 M and CLKS_PER_BIT = 5208 (BITPER in your code), also with baud rate of 115200, clk of 50 M and CLKS_PER_BIT = 435, but I am still not monitoring the correct data from serial pin!

 

I set the data to be transmitted a constant value in the code for testing purposes. Based on DE2-115 datasheet set the serially out put transmitted data to PIN_G9. 

 

Is my pin assignment wrong ? or the parameters?

 

 

MG007_0-1699385570701.png

MG007_1-1699385625017.png

 

0 Kudos
_AK6DN_
Valued Contributor II
6,170 Views

That would be the correct pin to send the TX data on to the RS232 connector.

Either 3.3V LVTTL or 3.3V LVCMOS should work as the signal type.

It would be interesting if you could post a sample ModelSim waveform for the TX data line for some known character.

0 Kudos
MG007
Beginner
6,163 Views

As I mentioned before, I need to transmit data from FPGA for 7 bit and I need it binary. So I didn't check for characters, only for binary bits. 

 

here is waveforms when I sent 01010101. tx_dv should be on to send the data, tx_serial is serial data (PIN_G9). 

based on the waveform it is sending the each bit data for CLK_PER_BIT (clk/baud rate) times of clk. 

 

MG007_0-1699401071036.png

 

0 Kudos
_AK6DN_
Valued Contributor II
6,145 Views

Well that waveform is really not useful at all.

Sending the same data over and over like that (a 0/1 pattern) it is virtually impossible to determine the start and stop bits.

Their is no bit timing measurement, and the clock waveform can't be used as is to determine the bit period is valid.

I would suggest sending more varied data patterns (ie, not the same one over and over).

Space them out in time a bit, so that the start and stop bits can be easily discerned.

And show a measurement of edge-edge transitions of a bit cell to be able to validate the baud rate is correct.

0 Kudos
MG007
Beginner
6,123 Views

Thank you for the feedback.

I tried different data strings, 01010101, 00000000,11111111,10101010,11110000, and 00001111.

 

It seems to work fine.

It starts sending bit 0 as starting bit then sending the 8 bit data and sending 1 as ending bit. all 10 bits sent for 435 clk(50M/115200). And it sends data from MSB to LSB.

Screenshot 2023-11-07 at 11.04.44 PM.png

0 Kudos
MG007
Beginner
6,079 Views

I again tested the UART transmitted with some constant 8 bit data, and it looks working fine. But I have some other issue to resolve.  I am using Serial Port Monitor Software to read the transmitted data, but it reads it continiously in large length. How can I get the data in 8 bits only?

For example I sent 01010101 which is "55" in hex and I get this:

Screenshot 2023-11-08 at 2.16.17 PM.png

 

Or when I sent 10101010 which is "aa" in hex I get this:

Screenshot 2023-11-08 at 2.17.01 PM.png

 

How I only get 55 or aa only ?

 

 

0 Kudos
_AK6DN_
Valued Contributor II
6,057 Views

Do you mean how do you get a single character 0x55 or 0xAA in your receiver?

I suspect you are probably enabling the UART module to transmit a blast of characters, rather than just one.

Maybe unintentionally, but that is what it appears to be doing.

You need to adjust the control inputs to your UART module to transmit just one character, and then stopping.

You don't show what the top level control signals driving your uart look like so I am just speculating based on the waveform.

0 Kudos
Reply