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?
This is what it looks like in the Netlist Analyzer:
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()