element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Experts, Learning and Guidance
  • Technologies
  • More
Experts, Learning and Guidance
Ask an Expert Forum How do I make my UART Loopback work?
  • Blog
  • Forum
  • Documents
  • Leaderboard
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Experts, Learning and Guidance to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • State Not Answered
  • Replies 3 replies
  • Subscribers 286 subscribers
  • Views 674 views
  • Users 0 members are here
  • python
  • fpga
  • vhdl
  • uart
  • serial
  • fpga implementation
Related
See a helpful answer?

Be sure to click 'more' and select 'suggest as answer'!

If you're the thread creator, be sure to click 'more' then 'Verify as Answer'!

How do I make my UART Loopback work?

androo
androo 8 months ago

Hello! I am currently working on a simple UART Loopback in VHDL to implement in LCMXO3D-9400HC board. I did solder R14 and R15 on the board and configure port B of FT2232HL to RS232 UART and Virtual COM Port with FT_Prog to enable to use its RS232 function. The solder looks like a mess, but I tested and it's working lol. However, after configuring it in the board and running a python script where the input will be written, and the output will be read through serial, I get no output. How do I make this work?

image

This is what it looks like in the Netlist Analyzer:

image

Here is my code for the UART Loopback in VHDL:

RECEIVER:

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.NUMERIC_STD.all;

library MachXO3D;
use MachXO3D.all; 

entity UART_RX2 is
	port (
		CLK				: in STD_LOGIC;
		RST				: in STD_LOGIC;
		RX_SERIAL_I		: in STD_LOGIC;
		BAUD_TICK 		: in STD_LOGIC;
		RX_READY		: out STD_LOGIC;
		RX_DATA_O		: out STD_LOGIC_VECTOR (7 DOWNTO 0);
		RX_DATA_TICK	: out STD_LOGIC	
	); 
end entity UART_RX2;
	
architecture RTL of UART_RX2 is	 
	type RX_STATE is (IDLE, START, SHIFT, STOP);
	signal RX : RX_STATE := IDLE;
	signal RX_COUNT : INTEGER range 0 to 7 := 0;
	signal RX_DATA : STD_LOGIC_VECTOR(7 DOWNTO 0) := (others => '0'); --"00000000";
	
	signal BAUD_TICKD: STD_LOGIC := '0';

begin

	BT_HALF: process (CLK)
	begin
		if rising_edge(CLK) then
            if RST = '1' then
                BAUD_TICKD <= '0';
            else
                BAUD_TICKD <= BAUD_TICK;
            end if;
        end if;
	
	end process BT_HALF;
	
	RX_FSM: process (CLK)
	begin
	if rising_edge(CLK) then
		if RST = '1' then
			RX <= IDLE;
			RX_READY <= '1';
			RX_DATA_TICK <= '0';
			RX_DATA <= (others => '0');
		else 
			case RX is
				when IDLE =>
					RX_READY <= '1';
					RX_DATA_TICK <= '0';
					if RX_SERIAL_I = '0' then
						RX <= START;
						RX_READY <= '0';
					end if;
					
				when START =>
						if BAUD_TICK = '1' then
						RX <= SHIFT;
						RX_COUNT <= 0;
					end if;
					
				when SHIFT =>
					if BAUD_TICKD = '1' then
						RX_DATA(RX_COUNT) <= RX_SERIAL_I;
						if RX_COUNT = 7 then
							RX <= STOP;
							RX_DATA_TICK <= '1';
						else	
							RX_COUNT <= RX_COUNT + 1;
						end if;
					end if;
					
				when STOP =>
					if BAUD_TICK = '1' then
						RX <= IDLE;
					end if;
						
			end case;
		end if;
	end if;
	end process;
	
	RX_DATA_O <= RX_DATA;
		

	
end RTL; 



TRANSMITTER:

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.NUMERIC_STD.all;

library MachXO3D;
use MachXO3D.all;

entity UART_TX2 is
	port (
		CLK				: in STD_LOGIC;
		RST				: in STD_LOGIC;
		TX_DATA 		: in STD_LOGIC_VECTOR (7 DOWNTO 0);
		READY			: in STD_LOGIC;
		BAUD_TICK		: in STD_LOGIC;
		TX_SERIAL_O		: out STD_LOGIC;
		TX_DATA_TICK	: out STD_LOGIC;
		TX_READY 		: out STD_LOGIC
	);
end entity UART_TX2;

architecture BEHAVIORAL of UART_TX2 is
	type TX_STATE is (IDLE, START, SHIFT, STOP);
	signal TX : TX_STATE := IDLE;
	signal TX_COUNT : INTEGER range 0 to 7 := 0;

begin
	
	TX_FSM: process (CLK)
	begin
	if rising_edge(CLK) then
		if RST = '1' then
			TX <= IDLE;
			TX_SERIAL_O <= '1'; --idle
			TX_READY <= '1';
			TX_DATA_TICK <= '0';
		else
			case TX is
				when IDLE => 
					TX_READY <= '1';
					TX_DATA_TICK <= '0';
					if READY = '1' then --and TX_DATA_TICK = '1'  BAUD_TICK = '1'
						TX <= START;
						TX_SERIAL_O <= '0';
						TX_READY <= '0';
					end if;
				when START =>
					if BAUD_TICK = '1' then
						TX <= SHIFT;
					end if;
				
				when SHIFT =>
					if BAUD_TICK = '1' then
						TX_SERIAL_O <= TX_DATA(TX_COUNT);
						if TX_COUNT = 7 then
							TX <= STOP;
							TX_DATA_TICK <= '1';
						else 
							TX_COUNT <= TX_COUNT + 1;
						end if;
					end if;
				
				when STOP =>
					if BAUD_TICK = '1' then
						TX_SERIAL_O <= '1';
						TX <= IDLE;
					end if;
				
			end case;
		end if;
	end if;

	end process;
	
	
end BEHAVIORAL;

BAUD GENERATION:

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.NUMERIC_STD.all;

library MachXO3D;
use MachXO3D.all;

entity BAUD_GEN is
	generic (
		constant SYS_CLK	: INTEGER := 12e6;
		constant BAUD_RATE	: INTEGER := 9600
	);
	port (
		CLK				: in STD_LOGIC;
		RST				: in STD_LOGIC;
		BAUD_TICK		: out STD_LOGIC := '0'
	); 
end entity BAUD_GEN;
	
architecture BEHAVIORAL of BAUD_GEN is	 
	constant BAUD_DIVISOR : INTEGER := SYS_CLK / BAUD_RATE;
	signal BAUD_COUNTER : UNSIGNED(15 DOWNTO 0) := (others => '0');
	
begin

	--BAUD TICK GENERATION--
	process(CLK)
	begin  
		if rising_edge(CLK) then
			if RST = '1' then
				BAUD_TICK <= '0';
				BAUD_COUNTER <= (others => '0');
			else
				if BAUD_COUNTER <= BAUD_DIVISOR - 1 then
					BAUD_TICK <= '1';
					BAUD_COUNTER <= (others => '0');
				else
					BAUD_TICK <= '0';
					BAUD_COUNTER <= BAUD_COUNTER + 1;
				end if;
			end if;				
		end if;
	end process;

end BEHAVIORAL; 	

SAMPLING INCOMING SIGNAL:

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.NUMERIC_STD.all;
use IEEE.MATH_REAL.ALL;

library MachXO3D;
use MachXO3D.all; 

entity SAMPLING is
	generic (
		constant OS_RATE: INTEGER := 16
	);
	port (
		CLK				: in STD_LOGIC;
		RST				: in STD_LOGIC;
		RX_SERIAL_I		: in STD_LOGIC;
		RX_SAMPLE		: out STD_LOGIC
	);
end entity SAMPLING;

	
architecture BEHAVIORAL of SAMPLING is	 
	signal OS_COUNTER : unsigned(natural(ceil(log2(real(OS_RATE)))) - 1 downto 0) := (others => '0');
	signal SAMPLE_DATA : std_logic_vector(OS_RATE - 1 downto 0);
	signal COUNT1 : unsigned(natural(ceil(log2(real(OS_RATE)))) downto 0);
begin

	process(CLK)
	begin 
		if rising_edge(CLK) then
			if RST = '1' then
				OS_COUNTER <= (others => '0');
				SAMPLE_DATA <= (others => '0');
				RX_SAMPLE <= '1'; 
			else
				if OS_COUNTER = OS_RATE - 1 then 
					OS_COUNTER <= (others => '0'); -- RESET COUNTER
					COUNT1 <= (others => '0');
					
					for x in 0 to OS_RATE - 1 loop
						if SAMPLE_DATA(x) = '1' then
							COUNT1 <= COUNT1 + 1;
						end if;
					end loop;
					
					if COUNT1 > OS_RATE / 2 then
                        RX_SAMPLE <= '1';
                    else
                        RX_SAMPLE <= '0';
                    end if;
					
				else
					SAMPLE_DATA(to_integer(unsigned(OS_COUNTER))) <= RX_SERIAL_I;
					OS_COUNTER <= OS_COUNTER + 1;
				end if;
			end if;
		end if;
	end process;

end BEHAVIORAL;

UART LOOPBACK MAIN:

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.NUMERIC_STD.all;

library MachXO3D;
use MachXO3D.all;

entity UART_LOOPBACK is
	port (
		CLKFT 	: in STD_LOGIC; --clock source from FT2232
		RST		: in STD_LOGIC; -- from SW1 pushbutton
		DPSW	: in STD_LOGIC; 
		RX_A11 	: in STD_LOGIC;
		RXD		: out STD_LOGIC_VECTOR (7 DOWNTO 0); 
		RRDY	: out STD_LOGIC; 
		RXDT	: out STD_LOGIC; 
		TX_C11	: out STD_LOGIC;
		TXD		: out STD_LOGIC_VECTOR (7 DOWNTO 0);
		TXR		: out STD_LOGIC; 
		TXDT	: out STD_LOGIC
	); 
	end entity UART_LOOPBACK; 
	
architecture RTL of UART_LOOPBACK is
	signal RSTN : STD_LOGIC; 
	signal OSC : STD_LOGIC; -- output from oscillator
	signal CLK_SRC : STD_LOGIC; -- clock input to be used
	signal BT	: STD_LOGIC;
	signal RXS	: STD_LOGIC;
	signal SEDSTDBY : STD_LOGIC;
	component OSCJ
	generic (
		NOM_FREQ : String := "12.09"
	);
	port (
		STDBY : in std_logic := 'X';
		OSC, SEDSTDBY, OSCESB : out std_logic := 'X'
	);
	end component;

	attribute NOM_FREQ : string;
	attribute NOM_FREQ of INT_OSC : label is "12.09";
   
begin
	--CLOCK SOURCE SELECTION--
	CLK_SRC <= OSC when DPSW = '1' else CLKFT; 
	RSTN <= RST;
	
	INT_OSC: OSCJ
		port map (
			STDBY 	=> '0',
			OSC		=> OSC,
			SEDSTDBY=> SEDSTDBY,
			OSCESB	=> open
		);
	
	BAUD_GEN: entity work.BAUD_GEN
		generic map (
			SYS_CLK		=> 12e6,
			BAUD_RATE	=> 9600
		)
		port map (
			CLK			=> CLK_SRC,
			RST 		=> RST,
			BAUD_TICK 	=> BT
		); 
	
	
	INCOMING_SIGNAL: entity work.SAMPLING
		generic map (
			OS_RATE => 16
		)
		port map (
			CLK			=> CLK_SRC,
			RST			=> RST,
			RX_SERIAL_I	=> RX_A11,	
			RX_SAMPLE	=> RXS 		
		); 
	
	UART_RX: entity work.UART_RX2
		port map (
			CLK			=> CLK_SRC,
			RST			=> RST,
			RX_SERIAL_I	=> RXS, 
			BAUD_TICK	=> BT,
			RX_READY	=> RRDY, 
			RX_DATA_O	=> RXD, 
			RX_DATA_TICK=> RXDT	 
	
	);
	
	UART_TX: entity work.UART_TX2
		port map (
			CLK			=> CLK_SRC,
			RST			=> RST,
			TX_DATA 	=> RXD, 
			READY		=> RXDT, 
			BAUD_TICK	=> BT,
			TX_READY 	=> TXR,	
			TX_SERIAL_O	=> TX_C11,	
			TX_DATA_TICK=> TXDT	
	);
	
	TXD <= RXD;
	
end RTL;

Python script:

import time
import serial

ser = serial.Serial(port="COM4", baudrate=9600, bytesize=serial.EIGHTBITS, timeout=1, stopbits=serial.STOPBITS_ONE)

results = open("results4.txt", "wb")

def data_in_chunks(data, chunk_size=8):
    return [data[max(i - chunk_size, 0):i] for i in range(len(data), 0, -chunk_size)]
   
with open('stim_in2.txt', 'rb') as testvectors:
    while True:
        line = testvectors.readline().strip()
        if not line:
            print("\nTest done.")
            break
        line_clean = line.replace(b' ', b'')
        label = line_clean[:3]
        data = line_clean[3:]
        print(label)
        print(data)

        alu_chunk = data_in_chunks(data, 8)

        print(alu_chunk)

        for i in range(len(alu_chunk)):
            # Ensure the byte has 8 bits, padding with zeros if it's less than 8 bits
            if len(alu_chunk[i]) < 8:
                alu_chunk[i] = alu_chunk[i].ljust(8, b'0')  # Pad with '0's from the left to make it 8 bits
            elif len(alu_chunk[i]) > 8:
                alu_chunk[i] = alu_chunk[i][:8]

        print(alu_chunk)
        results.write(label)
        results.write(b' ')
        for i in range(len(alu_chunk)):
            alu_input = alu_chunk[i]
            ser.write(alu_input)
            time.sleep(1)
            print("alu_input", i + 1, ":", alu_input)
            output = ser.read(8)

            time.sleep(1)
            print("FROM SERIAL: ", output)
          
            results.write(output)
            time.sleep(0.01)

        time.sleep(0.0001)

        results.write(b'\n')


results.close()
ser.close()

  • Sign in to reply
  • Cancel

Top Replies

  • michaelkellett
    michaelkellett 8 months ago +1
    Its not at all clear to me how this is connected. How is the Python talking to the FPGA/FTDI chip ? You need to show us the whole thing, especially the hardware connections. You WILL need a scope…
Parents
  • michaelkellett
    0 michaelkellett 8 months ago

    Its not at all clear to me how this is connected.

    How is the Python talking to the FPGA/FTDI chip ?

    You need to show us the whole thing, especially the hardware connections.

    You WILL need a scope.

    But first - how does the simulation look ?

    MK

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
Reply
  • michaelkellett
    0 michaelkellett 8 months ago

    Its not at all clear to me how this is connected.

    How is the Python talking to the FPGA/FTDI chip ?

    You need to show us the whole thing, especially the hardware connections.

    You WILL need a scope.

    But first - how does the simulation look ?

    MK

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
Children
  • androo
    0 androo 8 months ago in reply to michaelkellett

    I am sending input data to FPGA using the FTDI chip as a USB intetface. Since FT2232HL has 2 ports (1st port for JTAG, and 2nd port for UART/Serial), I used the 2nd port to send the data to the FPGA and also read the output from it.

    As for hardware connections, the board is connected to my computer via USB. Soldering R14 and R15 on the board is for RS232 connections. R14 connects pin 38 of FT2232HL and pin A11 on LCMXO3D which is for RX. R15 connects C11 of LCMXO3D and pin 39 which is for TX. Aside from this, I did not do additional hardware connections as of yet. Did I understand your question correctly? 

    By scope, you mean oscilloscope? I don't have any other equipment yet with me other than a multimeter for further troubleshooting.

    Actually, this is just the first part of my research. I am currently making the UART work first before inserting the unit that will process the input data; hence, I don't have the simulation for the loopback alone.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • michaelkellett
    0 michaelkellett 8 months ago in reply to androo

    One of the key tools in successful FPGA design work is the simulator.

    I never load a new chunk of code into a physical FPGA that hasn't been simulated first.

    The Lattice development tools offer some kind of oscilloscope-on-fpga tools but I've never found them (or the X or A equivalents) to be very useful.

    Right now you don't know if the data from the PC is reaching the A11 pn on the FPGA and if anything is happening on C11 of the FPGA.

    Running a simulation of the FPGA code would give you some confidence that RX data on All was echoed on C11 but you need to check these things.

    If you don't have a scope then connect interesting signals to LEDs driven by the FPGA. LEDs to monitor the A11 and C11 seem like a good plan.

    If you drop the baud rate as low as you can you should be able to tell if anything is happening.

    The simulator is free (part of Lattice toolset).

    But you won't get far without a logic analyser or scope.

    Good luck.

    MK

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube