VHDL - UART bit parzystości

0

Cześć! Niestety jestem zielony z programowania, spędziłem już kilka godzin nad rozwiązaniem tego problemu i nic nie potrafię wskórać. Jestem zdesperowany i potrzebuję pomocy. Środowisko to Quartus Prime. Chodzi o zaprojektowanie w języku VHDL nadajnika i odbiornika asynchronicznej transmisji szeregowej (UART). Dostałem kod w języku VHDL - kod pliku vhd oraz kod pliku vht. Potrzebuję, tak przerobić te kody, aby "Zmodyfikować ramkę danych w odbiorniku: dodać bit parzystości przed bitem stop, zmodyfikować odpowiednio plik testujący" i pokazać to na symulacji RTL . Podobno proste.
Załączam kod pliku vhd, vht, który otrzymałem i wynik symulacji RTL Simulation na podstawie tych plików.

VHD:
screenshot-20200512172009.png
screenshot-20200512172030.png

VHT:
screenshot-20200512171918.png
screenshot-20200512171944.png

Symulacja:
screenshot-20200512171543.png

i tak jak wspomniałem zadanie to ""Zmodyfikować ramkę danych w odbiorniku: dodać bit parzystości przed bitem stop" i zasymulować to.

Bardzo dziękuję z góry za pomoc.

0

W VHDLu wcięcia są zakazane? Tego tak sformatowanego nie da się czytać

1

Rozumiem, że VHDL to język do programowania niskopoziomowego i FPGA ale w nim formatowanie też można stosować.
Sformatuj kod to się temu przyjrzę.

0

VHD:
screenshot-20200512183106.png
screenshot-20200512183126.png
VHT:
screenshot-20200512182917.png
screenshot-20200512182946.png

0

Nie da się tego tekstowo wkleić na forum ?

Swoją drogą tutaj masz ładny przykład implementacji UART: https://www.nandland.com/vhdl/modules/module-uart-serial-port-rs232.html

0

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;

0

Boję się, że skoro nie ogarniasz wysyłania posta na forum to z ogarnięciem portu szeregowego może być kiepsko.
Postaram się to odpalić w jakimś symulatorze. Za kilka godzin dam znać czy się cośudało.


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;

Kolejny plik


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;

0

Dziś podejście nr dwa. Wczoraj poległem na instalacji symulatora :-)
Obecnie mam jedynie LTE a paczka zajmuje 6GB - nie znasz czegoś lżejszego ?

0

Hej, niestety nie pomogę, z tym programowaniem mam tyle do czynienia co wymagają na uczelni.

Wiem, że ciężko tak bez środowiska wskazać rozwiązanie ale może nasuwają Ci się jakieś pomysły tak patrząc po prostu na kod? Prowadzący powiedział, że jest to proste zadanie i polecił skupić się na miejscu gdzie przesyłane są dane, czyli:

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

Domyślam się, że trzeba też zwiększyć długośc wektora do 9. Ogólnie męczyłem się kilka h próbowałem modyfikować ten fragment kodu:

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;

W mniej więcej taki sposób (różnie kombinowałem ale do tego to się sprowadzało):

procedure sent_char (ascii_hex : std_logic_vector(7 downto 0)) is
variable t : std_logic;
begin
for i in 0 to 10 loop
if i=0 then
RxD_i<='0'; -- bit start

elsif i/=0 and i/=9 and i/=10 then
RxD_i<=ascii_hex(i-1); -- dane
t := '0';
t := t xor ascii_hex(i-1);

elsif i=9 then

ascii_hex(i-1)<=t;
elsif i=10 then
RxD_i<='1'; -- bit stop


end if;
wait_baudeRate_edge;
end loop;

Wynik symulacji wychodził wtedy taki:
screenshot-20200513104013.png

Na pierwszy rzut oka jest ok, faktycznie jest kontrola parzystości, ale gdy zmieniłem przesłane dane na jakieś inne już się nie zgadzało. Do tego jakby te bity się poprzesuwały.

Dziękuję Ci bardzo, że poświęcasz wgl swój czas.

0

Generalnie dobrze kombinujesz bo co do idei zadanie jest rzeczywiście proste. Wystarczy dodać jeden bit. Tylko ten kod jest zbyt mało czytelnie napisany żeby męczyć się i strzelać "w ciemno".

p.s.
pobrało się już 30% :-) Mam nadzieję, że na Linux Mint nie będzie robiło problemu bo na stronce Intela sugerowali Ubuntu.

0

56% ... Chyba szybciej to zrobisz niż ja zainstaluję :-)
screenshot-20200513134526.png

0

screenshot-20200513161753.png

Mam Jeszcze taki algorytm działania programu. Podejrzewam, że trzeba zmienić odpowiednio wartości związane z cntb. Dalej próbuje ale nic :D
Możę algorytm coś pomoże

1 użytkowników online, w tym zalogowanych: 0, gości: 1