Reputation: 9
I'm trying to connect my FPGA with my laptop using the serial protocol. For that purpose, I implemented the UART protocol on the FPGA side.
The connection between the FPGA and the Laptop is done with the UART-TTL to USB converter. I Get the wrong frame on the Laptop side. Thus, I analyse my frame continuously using a logic analyzer, I observed that the frame sent wasn't stable, i.e sometimes a wrong frame is received instead of the one sent.
Below is the code for the serial core :
library ieee ;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity TX is
port(
CLK: in std_logic;
START: in std_logic;
BUSY : out std_logic;
DATA: in std_logic_vector(7 downto 0);
TX_LINE: out std_logic
);
end TX;
architecture MAIN of TX is
signal PRSCL : integer range 0 to 5208:=0;
signal index : integer range 0 to 9:=0;
signal DATAFLL : std_logic_vector (9 downto 0);
signal TX_FLAG: STD_LOGIC:='0';
begin
process(CLK)
begin
if(CLK'EVENT and CLK='1') then
if(TX_FLAG='0' and START='1') then
TX_FLAG<='1';
BUSY<='1';
DATAFLL(0)<='0';
DATAFLL(9)<='1';
DATAFLL(8 downto 1)<=DATA;
TX_LINE<='1';
end if;
-- send data , 50MHz /9600=5208 (9600: the baudrate)
IF(TX_FLAG='1') then
IF (PRSCL <5207) then
PRSCL<=PRSCL+1;
else
PRSCL<=0;
end if;
IF(PRSCL=2600)THEN
TX_LINE<=DATAFLL(INDEX);
IF(INDEX<9)THEN
INDEX<=INDEX+1;
ELSE
TX_FLAG<='0';
BUSY<='0';
INDEX<=0;
END IF;
END IF;
END IF;
END IF;
end process ;
end MAIN;
The control unit to instantiate the serial core is below :
library ieee ;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity UART is
port (
CLOCK_50: in std_logic;
SW: in std_logic_vector(3 downto 0);
KEY: in std_logic_vector(1 downto 0);
LEDG : out std_logic_vector (7 downto 0);
UART_TXD : out std_logic;
UART_RXD: in std_logic
);
end UART ;
ARCHITECTURE MAIN OF UART IS
SIGNAL TX_DATA: STD_LOGIC_VECTOR(7 downto 0);
SIGNAL TX_START: STD_LOGIC:='0';
SIGNAL TX_BUSY: STD_LOGIC:='0';
SIGNAL RX_DATA: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL RX_BUSY: STD_LOGIC:='0';
COMPONENT TX
PORT(
CLK:IN STD_LOGIC;
START:IN STD_LOGIC;
BUSY:OUT STD_LOGIC;
DATA: IN STD_LOGIC_VECTOR(7 downto 0);
TX_LINE:OUT STD_LOGIC
);
END COMPONENT TX;
BEGIN
C1: TX PORT MAP (CLOCK_50,TX_START,TX_BUSY,TX_DATA,UART_TXD);
--C2: RX PORT MAP (CLOCK_50,UART_RXD,RX_DATA,RX_BUSY);
PROCESS(CLOCK_50)
BEGIN
IF(CLOCK_50'EVENT AND CLOCK_50='1')THEN
IF(KEY(0)='1' AND TX_BUSY='0')THEN -- Key(0)='0' MEAN that the key is pressed
TX_DATA<="0000" & SW(3 DOWNTO 0);
TX_START<='1';
LEDG<=TX_DATA;
ELSE
TX_START<='0';
TX_DATA<=(others=>'0') ;
END IF;
END IF;
END PROCESS;
END MAIN;
Thanks for you help.
Best regards,
Upvotes: 1
Views: 2272
Reputation: 3388
Any asynchronous input have to be resynchronized before use, otherwise your circuit will become metastable and erratic behaviour will follow. On your top level, sw and key are asynchronous.
A synchronization circuit is typically 2 cascaded flip-flops, only the output of the second flip-flop should be used in your code:
...
signal sw_resync1 : std_logic_vector(3 downto 0);
signal sw_resync2 : std_logic_vector(3 downto 0);
signal key_resync1 : std_logic_vector(3 downto 0);
signal key_resync2 : std_logic_vector(3 downto 0);
begin
RESYNC: process(CLOCK_50)
begin
if (CLOCK_50'event and CLOCK_50 = '1') then
SW_resync1 <= SW;
SW_resync2 <= SW_resync1;
KEY_resync1 <= KEY;
KEY_resync2 <= KEY_resync1;
end if;
end process RESYNC;
...
IF(KEY_resync2(0)='1' AND TX_BUSY='0')THEN -- Key(0)='0' MEAN that the key is pressed
TX_DATA<="0000" & SW_resync2(3 DOWNTO 0);
...
You should also be aware that mechanical inputs (suck as sw and key) should be debounced or you will read several transitions for the same key stroke.
Upvotes: 2