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()