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

Generic driver to rest of the system communication - advice needed?

Altera_Forum
Honored Contributor II
1,740 Views

Hello all,  

 

First - I am new to VHDL but: 

 

I have built a state machine that communicates with FT245 USB chip using parallel protocol (it is very simple - 8-bit data bus, read and write strobes and 2 flags from the FT245 to indicate if its internal FIFO has space - to write or has data - to read). I have tested it and it sends data to PC fine and I can also read received byte in VHDL.  

 

My next step is to make this code more generic so I can re-use it in my other projects and to really be able to send data to PC and receive the data into some controller code to make some action.  

 

As such I was thinking for my FT245 driver to have an input byte STD_LOGIC_VECTOR(7 DOWNTO 0) that module user would send byte which has to be send to FT245 and consequently to the PC and the same 1 byte as output byte. Since I will be utilizing FIFO from the FT245 chip, I would pass state of its flags to the module user, so it can be checked if read or write is possible.  

 

For writing, user would have to assert write_request flag to '1' and then my FT245 module would go into the writing part of the state machine (of course - flag that FIFO for writing from FT245 would have to be in proper state). Next write request can happen only if write_request flag is put back to '0' and then back to '1'.  

 

For reading, user would have to assert read_request flag to '1' and then my data_ready flag would drop from '1' to '0'. On next clock cycle, data will be read (lasts several clock cycles @ 50Mhz FPGA clock) and then data_ready flag will be asserted back to '1'.  

 

In case both write_request and read_request are asserted on same clock edge, write would take precedence.  

 

I am posting this since I am not particularly happy with the flags approach.  

What is write_request flag is forgoten to be set back to 0? Should I think it is again a new write_request and continue from idle state to writing part immediately thus sending data again and again? Same with read_request - is it really read or? Similarly notifying that new that is available is so-so....  

 

I guess after one write cylce, I can make a new state where I wait for write_request to drop back to 0, if it is not already. And same for the read cycle. But then I can be stuck in those states.... 

 

Since such "communication" between modules aka. various hardware drivers is I guess common - what are the usual approaches taken?  

 

After this is done, I need to do communication with ADC, then make 32-bit quadrature encoder decoder with counter and some configuration part where PC sends some configuration like encoder counts to mm coefficient and so on. That is why I am thinking of using modular approach.  

 

 

I am using some chinese Cyclone IV E FPGA module.
0 Kudos
7 Replies
Altera_Forum
Honored Contributor II
367 Views

Your description is very wordy - no timing diagrams, so I dont really know what you're getting at. Are there any standard interfaces to use rather than this that would allow you to plug it into more mudules (like an Avalon or AXI-4?) read_req/wr_request is pretty standard and straight forward, just like a FIFO. But it seems a bit odd (and inefficient) to have to detect a rising edge on wr_req, you're data rate will be half the clock rate. THis seems to be more suitable for a requesd/acknowledge type interface.

0 Kudos
Altera_Forum
Honored Contributor II
367 Views

Thanks for your reply.  

There is no code nor timing diagrams since I wanted to describe my idea first in an human time-efficient manner which is by using words.  

Developing the solution to produce code and timing diagrams would take some time after which someone can provide better or more efficient protocol type, which is also simple to implement but I didn't even know it exists.  

 

Are there any "design patterns" or "best practices" books or papers for always repeating codes and/or glue logic such as this? Because I am sure that in most more complex FPGA solutions you have bunch of "modules" communicating with each other (sending, reading, waiting for completion of some task, etc). It is very hard to find something online as opposed to software where this is common.  

 

Request/acknowledge type interface would work as: 

 

1. Byte data put on input vector of FT245 driver. FT245 driver "data_sent" bit is low. 

2. Request to write put high.  

3. FT245 driver goes to next state and performs sending sequence.  

4. FT245 driver goes to state upon completion of sending sequence and puts data_sent bit high.  

5. Requester waits for data_sent to become high. When this happens, puts request to write to low and puts ACK bit to FT245 as high.  

6. FT245 driver puts "data_sent" bit back to low and goes to idle state.  

 

As for data rate: 

 

@ 50Mhz clock every clock is at 20ns. Write pulse to FT245 chip is at minimum 50ns (= 3 clock cycles = 60ns). Read pulse is also 50ns (= 3 clock cycles = 60ns). I would loose about 3-4 clocks on this "communication protocol" making my write speed about 7 clock cycles (140ns) for 1 byte. This is 6.811MB/s which is well over the USB 2.0 data rate limit. so It is OK. however I would definetly like to learn more about more efficient implementations to know for the future!
0 Kudos
Altera_Forum
Honored Contributor II
367 Views

Here's some information on interfacing to FTDI devices ... 

 

http://www.ovro.caltech.edu/~dwh/correlator/pdf/ftdi.pdf 

 

Cheers, 

Dave
0 Kudos
Altera_Forum
Honored Contributor II
367 Views

I have looked at the Avalon bus specification for memory mapped slaves and devised a similar protocol: 

 

Below is the user of the FT245 driver - it is a 2 process state machine: 

 

LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY Comm IS PORT ( clk : IN STD_LOGIC; rstn : IN STD_LOGIC; debug_wr_flag : STD_LOGIC; debug_in_data : IN STD_LOGIC_VECTOR(7 DOWNTO 0); debug_data_rd : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); debug_data_wr : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) ); END ENTITY; ARCHITECTURE behavioral OF Comm is SIGNAL debug_wr_flag_reg : STD_LOGIC; SIGNAL debug_in_data_reg : STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL rd_fifo_has_data : STD_LOGIC; -- FT245 fifo has data for reading SIGNAL wr_fifo_full : STD_LOGIC; -- FT245 fifo is full for writing SIGNAL waitreq : STD_LOGIC; -- FT245 is busy SIGNAL rd : STD_LOGIC; -- request rd SIGNAL wr : STD_LOGIC; -- request wr SIGNAL rddatavalid : STD_LOGIC; -- data is valid SIGNAL rd_data : STD_LOGIC_VECTOR(7 DOWNTO 0); -- received (read) data by FT245 SIGNAL wr_data : STD_LOGIC_VECTOR(7 DOWNTO 0); -- data to be written to FT245 SIGNAL can_write : STD_LOGIC; SIGNAL can_read : STD_LOGIC; TYPE state IS (init, idle, wait_write, wait_read); SIGNAL pr_state, nx_state : state; COMPONENT FT245 IS PORT ( clk : IN STD_LOGIC; rstn : IN STD_LOGIC; rd_flag : IN STD_LOGIC; wr_flag : IN STD_LOGIC; rd_fifo_has_data : OUT STD_LOGIC; wr_fifo_full : OUT STD_LOGIC; waitreq : OUT STD_LOGIC; rddatavalid : OUT STD_LOGIC; data_write : IN STD_LOGIC_VECTOR(7 DOWNTO 0); data_read : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) ); END COMPONENT; BEGIN driver : FT245 port map ( clk => clk, rstn => rstn, rd_flag => rd, wr_flag => wr, rd_fifo_has_data => rd_fifo_has_data, wr_fifo_full => wr_fifo_full, waitreq => waitreq, rddatavalid => rddatavalid, data_write => wr_data, data_read => rd_data ); -- For debug purposes - show current values of rd and wr data. Not synced on purpose. debug_data_rd <= rd_data; debug_data_wr <= wr_data; -- For debug purposes - to inject some data to send... PROCESS(clk) BEGIN IF(rising_edge(clk)) THEN debug_wr_flag_reg <= debug_wr_flag; debug_in_data_reg <= debug_in_data; END IF; END PROCESS; -- Sequential part PROCESS(clk, rstn) BEGIN IF(rstn = '0') THEN pr_state <= init; ELSIF(rising_edge(clk)) THEN pr_state <= nx_state; END IF; END PROCESS; -- Combinatorial part -- can write only if debug wr flag is 1 and fifo is not full and no transaction is in progress can_write <= '1' WHEN debug_wr_flag_reg = '1' and wr_fifo_full = '0' and wr = '0' and rd = '0' and waitreq = '0' ELSE '0'; -- can read only if FT245 fifo has data and no transacation is in progress can_read <= '1' WHEN rd_fifo_has_data = '1' and wr = '0' and rd = '0' and waitreq = '0' ELSE '0'; PROCESS(pr_state, wr_fifo_full, waitreq, rddatavalid, rd_data, can_write, can_read, debug_in_data_reg) BEGIN CASE pr_state IS WHEN init => wr_data <= (others => '0'); rd <= '0'; wr <= '0'; nx_state <= idle; WHEN idle => wr_data <= (others => '0'); rd <= '0'; wr <= '0'; nx_state <= idle; IF(can_write = '1') THEN wr_data <= debug_in_data_reg; wr <= '1'; nx_state <= wait_write; ELSIF(can_read = '1') THEN rd <= '1'; nx_state <= wait_read; END IF; WHEN wait_write => wr_data <= debug_in_data_reg; wr <= '1'; rd <= '0'; nx_state <= wait_write; IF(waitreq = '0') THEN wr <='0'; nx_state <= idle; END IF; WHEN wait_read => rd <= '1'; wr <= '0'; wr_data <= (others => '0'); nx_state <= wait_read; IF(waitreq = '0' and rddatavalid = '1') THEN rd <= '0'; nx_state <= idle; END IF; WHEN others => wr_data <= (others => '0'); wr <= '0'; rd <= '0'; nx_state <= init; END CASE; END PROCESS; END behavioral;  

 

And this is the skeleton of FT245 driver as a single process timed state machine. When it enters do_write and do_read, it will have sub-states to actually strobe the FT245 chip with data, etc. This code only shows the communication side towards. 

I had some trouble with inferring latches for the output so I did a single process FSM.  

 

library ieee; USE ieee.std_logic_1164.all; USE ieee.numeric_std.all; ENTITY FT245 IS PORT ( clk : IN STD_LOGIC; rstn : IN STD_LOGIC; rd_flag : IN STD_LOGIC; wr_flag : IN STD_LOGIC; rd_fifo_has_data : OUT STD_LOGIC; wr_fifo_full : OUT STD_LOGIC; waitreq : OUT STD_LOGIC; rddatavalid : OUT STD_LOGIC; data_write : IN STD_LOGIC_VECTOR(7 DOWNTO 0); data_read : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) ); END ENTITY; ARCHITECTURE behavioral OF FT245 IS BEGIN -- Debug values rd_fifo_has_data <= '0'; -- will not go into reading wr_fifo_full <= '0'; -- will always mark as write is OK.... PROCESS(clk, rstn) TYPE state IS (init, idle, do_write, write_end, do_read, read_end); VARIABLE pr_state, nx_state : state; VARIABLE dummy : INTEGER RANGE 0 to 100; -- dummy counter for read data VARIABLE count : INTEGER RANGE 0 to 5; VARIABLE timer : INTEGER RANGE 0 to 5; BEGIN IF(rstn = '0') THEN count := 0; pr_state := init; nx_state := init; ELSIF(rising_edge(clk)) THEN count := count +1; CASE pr_state IS WHEN init => dummy := 0; rddatavalid <= '0'; waitreq <= '0'; timer := 0; nx_state := idle; data_read <= (others => '0'); WHEN idle => rddatavalid <= '0'; waitreq <= '0'; nx_state := idle; timer := 0; IF(wr_flag = '1') THEN waitreq <= '1'; nx_state := do_write; ELSIF(rd_flag = '1') THEN waitreq <= '1'; nx_state := do_read; END IF; WHEN do_write => rddatavalid <= '0'; waitreq <= '1'; nx_state := write_end; timer := 5; -- 100ns delay - as needed for FT245 to do its work....substates should be -- here to do actual protocol to FT245 WHEN write_end => rddatavalid <= '0'; waitreq <= '0'; nx_state := idle; timer := 0; WHEN do_read => dummy := dummy +1; rddatavalid <= '0'; waitreq <= '1'; nx_state := read_end; timer := 5; -- 100 ns delay; actually there should be sub-states here -- to talk to FT245 chip as required WHEN read_end => data_read <= std_logic_vector(to_unsigned(dummy,8)); rddatavalid <= '1'; waitreq <= '0'; nx_state := idle; timer := 0; WHEN others => data_read <= (others => '0'); rddatavalid <= '0'; waitreq <= '0'; timer := 0; nx_state := init; END CASE; -- Update present state with next state IF(count >= timer) THEN pr_state := nx_state; count := 0; END IF; END IF; -- rising clock END PROCESS; -- fsm END behavioral;  

 

 

Didn't have time to do simulation yet - holidays & such.  

 

What do you all think?
0 Kudos
Altera_Forum
Honored Contributor II
367 Views

 

--- Quote Start ---  

Here's some information on interfacing to FTDI devices ... 

 

http://www.ovro.caltech.edu/~dwh/correlator/pdf/ftdi.pdf 

 

Cheers, 

Dave 

--- Quote End ---  

 

 

Thanx.  

 

Protocol itself is very simple - I did a functional proof of concept and tested in on real hardware in 1 hour.  

 

However, there is some interesting stuff in there to check it out in terms of integrating FSM for FTDI chips into rest of the code. I will check it out.
0 Kudos
Altera_Forum
Honored Contributor II
367 Views

 

--- Quote Start ---  

I have looked at the Avalon bus specification for memory mapped slaves and devised a similar protocol ... 

 

Didn't have time to do simulation yet - holidays & such.  

 

What do you all think? 

--- Quote End ---  

 

 

We think you need to write a simulation. 

 

Altera provides a verification IP suite. You should use that suite to confirm your code simulates correctly. 

 

You comment above that you are new to VHDL, so here is a piece of advice for you to follow; Writing a simulation should be an integral part of your code development, not an afterthought. 

 

Cheers, 

Dave
0 Kudos
Altera_Forum
Honored Contributor II
367 Views

 

--- Quote Start ---  

We think you need to write a simulation. 

 

Altera provides a verification IP suite. You should use that suite to confirm your code simulates correctly. 

 

You comment above that you are new to VHDL, so here is a piece of advice for you to follow; Writing a simulation should be an integral part of your code development, not an afterthought. 

 

Cheers, 

Dave 

--- Quote End ---  

 

 

Well, I need to build something to be able to simulate it and then consequently to verify it. Now that I have built it, I can simulate it.  

 

I have noticed though, based on reading most of the threads on this sub-forum for VHDL that community on this forum/site is not as warm and welcoming as is on forums for mbed, avr or arduino where people discuss, help and teach/learn from each other. Here it is more business-like which does not really welcome beginners or people wanting to learn something....it is strange - because if it were different more people would probably be eager to learn and use FPGA/CPLDs.
0 Kudos
Reply