Hmm... wydaje mi się, że będzie to nieczytelne, ale proszę :)
VHD:
-- Odbiornik UART: 8b+1b, 16 x oversampling, 115200 bps
library Ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity uart_receiver is
port ( RxD_i : in std_logic;
clk50_i : in std_logic;
rst_i : in std_logic;
buf_o : out std_logic_vector(7 downto 0):=(others=>'0')
);
end uart_receiver;
architecture behavioral of uart_receiver is
signal clkOversampling_s : std_logic:='1';
signal buf_s : std_logic_vector(7 downto 0):=(others=>'0');
type state_type is (st_idle, st_start, st_data, st_stop); --określenie stanu automatu
signal state : state_type:=st_idle;
signal cnt_o : integer range 0 to 15:=0; --licznik taktów zegara próbkującego
signal cnt_b : integer range 0 to 7:=0; --licznik bitów danych
begin
-- dzielnik częstotliwości
p_divider: process(clk50_i)
variable cnt : integer range 0 to 162;
begin
--czas trwania stanu logicznego L lub H równy połowie okresu: (50MHz/16*115200)/2=14
if rising_edge(clk50_i) then
if cnt<13 then
cnt:=cnt+1;
else
cnt:=0;
clkOversampling_s<= not clkOversampling_s;
end if;
end if;
end process;
-- automat stanu
p_FSM_comb: process(clkOversampling_s,RxD_i, rst_i)
begin
if rst_i='0' then
state<=st_idle;
buf_s<=(others=>'0');
buf_o<=(others=>'0');
cnt_o<=0;
cnt_b<=0;
elsif rising_edge(clkOversampling_s) then
case state is
when st_idle =>
if RxD_i='0' then --wystąpienie bitu Start
state<=st_start;
end if;
when st_start =>
if cnt_o=7 then --znajdź środek bitu start (ósmy takt zegara próbkującego)
state<=st_data;
cnt_o<=0;
else
cnt_o<=cnt_o+1;
end if;
when st_data =>
if cnt_o=15 then --znajdź środek bitu danych (co szesnasty takt zegara próbkującego)
cnt_o<=0;
buf_s<=RxD_i & buf_s(7 downto 1); -- rejestr przesuwajajacy (LSB first)
if cnt_b<7 then
cnt_b<=cnt_b+1;
else
state<=st_stop;
cnt_b<=0;
end if;
else
cnt_o<=cnt_o+1;
end if;
when st_stop =>
buf_o<=buf_s;
if cnt_o=15 then --odczekaj czas równy 1-bitowi (16 taktów zegara próbkującego)
state<=st_idle;
cnt_o<=0;
else
cnt_o<=cnt_o+1;
end if;
end case;
end if;
end process;
end behavioral;
VHT:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY uart_receiver_vhd_tst IS
END uart_receiver_vhd_tst;
ARCHITECTURE uart_receiver_arch OF uart_receiver_vhd_tst IS
-- constants
CONSTANT CLK50_PERIOD : time := 20 ns;
CONSTANT BAUDE_RATE_PERIOD : time := 8.68 us; -- 1/baudeRate
-- signals
SIGNAL buf_o : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL clk50_i : STD_LOGIC:='0';
SIGNAL baudeRate_s : STD_LOGIC:='0';
SIGNAL rst_i : STD_LOGIC;
SIGNAL RxD_i : STD_LOGIC;
COMPONENT uart_receiver
PORT (
buf_o : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
clk50_i : IN STD_LOGIC;
rst_i : IN STD_LOGIC;
RxD_i : IN STD_LOGIC);
END COMPONENT;
BEGIN
DUT : uart_receiver
PORT MAP (
buf_o => buf_o,
clk50_i => clk50_i,
rst_i => rst_i,
RxD_i => RxD_i);
clk50_i<= not clk50_i after CLK50_PERIOD /2; -- taktowanie modulu odbiornika
baudeRate_s<= not baudeRate_s after BAUDE_RATE_PERIOD /2; -- zegar transmisji
p_sentData : PROCESS
procedure wait_baudeRate_edge is begin
wait until rising_edge(baudeRate_s);
end;
procedure test_init is
begin
report("test reset");
rst_i<='1';
RxD_i<='1';
wait_baudeRate_edge;
end;
procedure sent_char (ascii_hex : std_logic_vector(7 downto 0)) is
begin
for i in 0 to 9 loop
if i=0 then
RxD_i<='0'; -- bit start
elsif i=9 then
RxD_i<='1'; -- bit stop
else
RxD_i<=ascii_hex(i-1); -- dane
end if;
wait_baudeRate_edge;
end loop;
end;
BEGIN
-- init
test_init;
wait for BAUDE_RATE_PERIOD;
rst_i<='0';
wait for BAUDE_RATE_PERIOD;
rst_i<='1';
wait for BAUDE_RATE_PERIOD;
-- UART test - send data
sent_char(ascii_hex => X"50"); -- P
sent_char(ascii_hex => X"55"); -- U
sent_char(ascii_hex => X"43"); -- C
wait for BAUDE_RATE_PERIOD*8;
std.env.stop;
END PROCESS p_sentData;
END uart_receiver_arch;