UART on FPGA - Page 1
Forum section: electronics / general

author: gauravmp
author_rank: Regular Contributor
timestamp: June 28, 2016, 02:33:05 pm
content: Hello,I've been working on trying to get UART running on an FPGA(MAX10) using my own code and other code from online sources like opencores and fpga4fun.comMy own code resembles that from fpga4fun.com (http://www.fpga4fun.com/SerialInterface.html). However, whatever I try, I keep getting junk values when I read this data on my laptop. For converting to USB, I'm using an FTDI which I've used before for several microcontrollers and it has worked always.Could someone pls let me know what I should be looking for?Thanks

author: nctnico
author_rank: Super Contributor
timestamp: June 28, 2016, 02:45:11 pm
content: I'd check the signals using an oscilloscope.Also: did you run the FPGA code through a simulator? That would be a wise thing to do.

author: Andy Watson
author_rank: Super Contributor
timestamp: June 28, 2016, 02:59:57 pm
content: I would be looking for an oscilloscope!Don't try to make the whole lot work at once - break it down into blocks or modules that you can easily debug. This may entail writing extra code and/or make extra hardware.How are you implementing the "physical layer" - have you accounted for the inversion of the logic?

author: tszaboo
author_rank: Super Contributor
timestamp: June 28, 2016, 03:01:13 pm
content: Could be that your baud rate setting is wrong. Or it is off a few percent. Or you put it to the wrong pins. Or the data gremlin. Or voltage level. Or interference. Or or or...

author: SteveyG
author_rank: Unknown
timestamp: June 28, 2016, 03:38:59 pm
content: How do the simulations look? Chances of you writing HDL that works first time in hardware are nil.If you've copied most of the design, I'd be checking your clock generation.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: June 28, 2016, 03:48:55 pm
content: Quote from: gauravmp on June 28, 2016, 02:33:05 pmWhy are you looking at it on your laptop and not a scope?If the answer is that you don't have a scope, then get one before you spend another second on this. Doing FPGA stuff without a scope is a hopeless waste of time.

author: gauravmp
author_rank: Regular Contributor
timestamp: June 28, 2016, 05:33:57 pm
content: Thanks for the suggestions guys! Taking your suggestions, I am using my scope now. The problem seems to be that my state machine is screwed up. So it's going to a state when it should be. Pls see this and tell me if you know what is wrong:always @(posedge clk)beginif(switch==0)begintransmit_flag <= 1;led <= 0;endelsebegintransmit_flag <= 0;led <= 1;endend// baud ticksalways @(posedge clk_baud)beginbaud_count <= baud_count+1;if(baud_count==16)baud_count <= 0;endassign baud_tick = (baud_count==15);//state machinereg start;always @(posedge clk)case(state)4'b0000: if(transmit_flag) begin state <= 4'b0100; start <= 1; end4'b0100: if(baud_tick) begin state <= 4'b1000; start <= 0; end // start4'b1000: if(baud_tick) state <= 4'b1001; // bit 04'b1001: if(baud_tick) state <= 4'b1010; // bit 14'b1010: if(baud_tick) state <= 4'b1011; // bit 24'b1011: if(baud_tick) state <= 4'b1100; // bit 34'b1100: if(baud_tick) state <= 4'b1101; // bit 44'b1101: if(baud_tick) state <= 4'b1110; // bit 54'b1110: if(baud_tick) state <= 4'b1111; // bit 64'b1111: if(baud_tick) state <= 4'b0001; // bit 74'b0001: if(baud_tick) state <= 4'b0000; // stop1//4'b0010: if(baud_tick) state <= 4'b0000; // stop2default: if(baud_tick) state <= 4'b0000;endcasereg muxbit;always @(state[2:0])case(state[2:0])0: muxbit <= 0;//tx_data;1: muxbit <= 1;//tx_data;2: muxbit <= 0;//tx_data;3: muxbit <= 0;//tx_data;4: muxbit <= 0;//tx_data;5: muxbit <= 0;//tx_data;6: muxbit <= 1;//tx_data;7: muxbit <= 0;//tx_data;endcase// combine start, data, and stop bits togetherassign tx = (state<4) | (state & muxbit);THanks

author: gauravmp
author_rank: Regular Contributor
timestamp: June 28, 2016, 06:09:15 pm
content: I figured out the problem guys!!!! thanks a lot!! it works now!!!!

author: hamster_nz
author_rank: Super Contributor
timestamp: June 28, 2016, 07:04:13 pm
content: Quote from: gauravmp on June 28, 2016, 06:09:15 pmDon't leave us hanging (and broken code sitting the the thread).... what was it that tripped you up? was it anything that might trip somebody else up?

author: nctnico
author_rank: Super Contributor
timestamp: June 28, 2016, 07:09:32 pm
content: I hate that code BTW. I think I can do the same in a couple of lines of VHDL.

author: hamster_nz
author_rank: Super Contributor
timestamp: June 28, 2016, 08:52:15 pm
content: Quote from: nctnico on June 28, 2016, 07:09:32 pmTo the original poster...Don't take the above comment as a criticism, it is a very subtle joke - you can do nothing in a couple of lines of VHDL!It takes at least two lines to include the standard libraries...and another couple for the entity declarations...and then another couple for the architecture declarations...and then another three to start and end the process...and then you might start to write your first line of code.

author: nctnico
author_rank: Super Contributor
timestamp: June 28, 2016, 08:55:30 pm
content: Quote from: hamster_nz on June 28, 2016, 08:52:15 pmIt is not a joke. True you'll need some entity declarations but the UART itself can be a lot less lines of code and easier to maintain. There are way too much repetitions in the code shown above and a very typical example of how not to write HDL.Something like this (off the cuff):Code:signal uart_tx_data: std_logic(7 downto 0); --inputsignal uart_tx_start: std_logic; -- inputsignal uart_tx_shift: std_logic_vector(9 downto 0);signal uart_tx_count: unsigned(3 downto 0);signal baud_tick : std_logic;signal uart_tx : std_logic;signal uart_transmit_busy : std_logic;process uart(clk)if rising_edge(clk) thenif uart_tx_start=1' and uart_transmit_busy='0'; thenuart_transmit_busy<='1';uart_tx_shift <= "0" & uart_tx_data & "1";uart_tx_count <= 9;end if;if baud_tick='1' thenif uart_transmit_busy='1' then;uart_tx<=uart_tx_shift(to_integer(uart_tx_count));uart_tx_count<= uart_tx_count-1;if uart_tx_count=0 thenuart_transmit_busy<='0'end if;elseuart_tx<='1';end if;end if;end process;edit: typo

author: helius
author_rank: Super Contributor
timestamp: June 28, 2016, 09:32:28 pm
content: Code:always @(posedge clk_baud)beginbaud_count <= baud_count+1;if(baud_count==16)baud_count <= 0;endThink carefully about what this does. In particular, what the value ofbaud_countis at each point in the code.This looks like a bug.

author: hamster_nz
author_rank: Super Contributor
timestamp: June 28, 2016, 09:52:24 pm
content: QuoteYou are still overthinking it a little (off the cuff too, so most likely has a bug or two):Code:...port (clk : in std_logic(7 downto 0);uart_tx_data : in std_logic(7 downto 0);uart_tx_start : in std_logic;uart_busy : out std_logic;uart_tx : out std_logic);....signal uart_tx_shift : std_logic_vector(9 downto 0);signal uart_busy : std_logic_vector(9 downto 0);signal baud_count : unsigned(??? downto 0);signal baud_tick : std_logic;....uart_tx <= uart_tx_shift(0);uart_busy <= uart_busy_shift(0);...process uart(clk)if rising_edge(clk) thenif baud_tick='1' thenuart_tx_shift <= '1' & uart_tx_shift(9 downto 1);uart_busy_shift <= '0' & uart_busy_shift(9 downto 1);end if;if uart_tx_start='1' and uart_busy(0) ='0'; thenuart_tx_shift <= "1" & uart_tx_data & "0";uart_busy_shift <= (others => '1');end if;-- nasty baud tick generatorif baud_count = clock_rate/baud_rate-1 thenbaud_count <= (others => '0');baud_tick <= '1';elsebaud_count <= baud_count+1;baud_tick <= '0';end if;end if;end process;....

author: nctnico
author_rank: Super Contributor
timestamp: June 29, 2016, 10:42:24 pm
content: I wanted to stay closer to the original and show how easy it is to make a mux by using a counter as an index. BTW your method may look shorter but a mux can use the outputs of a memory like a FIFO directly and use fixed values for the start & stop bits so all in all my method (when more cleverly applied) could end up using less flipflops.

author: Kalvin
author_rank: Super Contributor
timestamp: June 30, 2016, 01:36:24 pm
content: How about implementing the UART using a simple shift register. Just load the shift register MSB with the start bit with the value "1", followed by the data bits, optional parity, the stop bit with the value "0" and finally the end token with the value "1". Then keep shifting out until all other bits are "0" except the MSB (the MSB is always "1", but it can be "0" after RESET for example, so excluding the MSB from the comparison will make the design robust). For 8 data bits and even/odd parity the total required shift register length is 12 bits.Edit: My suggestion is partly wrong as I assumed (remembered) wrongly that the data bits are sent MSB first. As hamster_nz writes below, the data will be sent LSB first which will also make the "end token" bit unnecessary.

author: hamster_nz
author_rank: Super Contributor
timestamp: July 02, 2016, 09:56:22 am
content: Quote from: nctnico on June 29, 2016, 10:42:24 pmI implemented the design suggested by Kalvin and tested it on a board sending characters from the switches and buttons - 12 LUTs and 11 FFs, for the UART, another 3 LUTs and 13 FFs to generate the bit_tick signal.Code:+-------------------+---------------+------------+------------+---------+------+-----+--------+--------+--------------+| Instance | Module | Total LUTs | Logic LUTs | LUTRAMs | SRLs | FFs | RAMB36 | RAMB18 | DSP48 Blocks |+-------------------+---------------+------------+------------+---------+------+-----+--------+--------+--------------+| basys3 | (top) | 15 | 15 | 0 | 0 | 24 | 0 | 0 | 0 || (basys3) | (top) | 3 | 3 | 0 | 0 | 13 | 0 | 0 | 0 || i_tiny_rs232_tx | tiny_rs232_tx | 12 | 12 | 0 | 0 | 11 | 0 | 0 | 0 |+-------------------+---------------+------------+------------+---------+------+-----+--------+--------+--------------+Code:library IEEE;use IEEE.STD_LOGIC_1164.ALL;entity tiny_rs232_tx isPort ( clk : in STD_LOGIC;bit_tick : in STD_LOGIC;data : in STD_LOGIC_VECTOR(7 downto 0);data_enable : in STD_LOGIC;tx : out STD_LOGIC := '1';busy : out STD_LOGIC );end tiny_rs232_tx;architecture Behavioral of tiny_rs232_tx issignal shift_reg : std_logic_vector(9 downto 0) := (others => '1');signal i_busy : std_logic;beginbusy <= i_busy;with shift_reg select i_busy <= '0' when "0000000000", '1' when others;clk_proc: process(clk)beginif rising_edge(clk) thenif i_busy = '0' and data_enable = '1' thenshift_reg <= '1' & data & '0';end if;if bit_tick = '1' thenif i_busy = '1' thentx <= shift_reg(0);shift_reg <= '0' & shift_reg(9 downto 1);end if;end if;end if;end process;end Behavioral;

author: gauravmp
author_rank: Regular Contributor
timestamp: July 20, 2016, 03:00:27 am
content: Quote from: hamster_nz on June 28, 2016, 07:04:13 pmSo, if you did notice the driver of the state machine I used was the baud tick. This baud tick is 1 for a number of clock cycles. So, I was skipping states. All I had to do was have the posedge of the baud tick instead of the clk be in the always block and it works.

author: Buriedcode
author_rank: Super Contributor
timestamp: July 20, 2016, 09:34:18 am
content: In my limited experience of programmable logic, I have always used, and seen people using pulses generated form the main clock. This isn't about clocking state machines form a derived clock - everything in the module should be clocked by the same clock, but using 'enables' instead. So say you have your main clock at 16x the baud, you would generate a single pulse, one clock width wide, that drives the state machine. The first thing the state machine does is check if this pulse line is high, if not, it does nothing.