sfondo
Questo è un progetto personale; riguarda il collegamento di un FPGA a un N64, i valori byte che l'FPGA riceve vengono quindi inviati tramite UART al mio computer. In realtà funziona abbastanza bene! Sfortunatamente, in momenti casuali il dispositivo non funzionerà, quindi verrà ripristinato. Attraverso il debug, sono riuscito a trovare il problema, tuttavia sono sconcertato su come risolverlo perché sono abbastanza incompetente con VHDL.
Sto giocando con il VHDL da un paio di giorni e potrei non essere in grado di risolverlo.
Il problema
Ho un oscilloscopio che misura il segnale N64 nell'FPGA e l'altro canale si collega all'uscita dell'FPGA. Ho anche pin digitali che registrano il valore del contatore.
In sostanza, l'N64 invia 9 bit di dati, incluso un bit di STOP. Il contatore conta i bit di dati ricevuti e quando raggiungo i 9 bit, l'FPGA inizia a trasmettere tramite UART.
Ecco il comportamento corretto:
L'FPGA è la forma d'onda blu e la forma d'onda arancione è l'ingresso dell'N64. Per tutta la durata della ricezione, il mio FPGA "echo" il segnale dell'ingresso a scopo di debug. Dopo che l'FPGA conta fino a 9, inizia a trasmettere i dati tramite UART. Notare che i pin digitali contano fino a 9 e l'uscita FPGA diventa BASSA immediatamente dopo il completamento dell'N64.
Ecco un esempio di errore:
Si noti che il contatore salta i bit 2 e 7! L'FPGA raggiunge la fine, aspettando il prossimo bit di partenza dall'N64 ma niente. Quindi l'FPGA scade e si ripristina.
Questo è il VHDL per il modulo di ricezione N64. Contiene il contatore: s_bitCount.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity N64RX is
port(
N64RXD : in STD_LOGIC; --Data input
clk25 : in STD_LOGIC;
clr : in STD_LOGIC;
tdre : in STD_LOGIC; --detects when UART is ready
transmit : out STD_LOGIC; --Signal to UART to transmit
sel : out STD_LOGIC;
echoSig : out STD_LOGIC;
bitcount : out STD_LOGIC_VECTOR(3 downto 0);
data : out STD_LOGIC_VECTOR(3 downto 0) --The significant nibble
);
end N64RX;
--}} End of automatically maintained section
architecture N64RX of N64RX is
type state_type is (start, delay2us, sigSample, waitForStop, waitForStart, timeout, count9bits, sendToUART);
signal state: state_type;
signal s_sel, s_echoSig, s_timeoutDetect : STD_LOGIC;
signal s_baudCount : STD_LOGIC_VECTOR(6 downto 0); --Counting variable for baud rate in delay
signal s_bitCount : STD_LOGIC_VECTOR(3 downto 0); --Counting variable for number of bits recieved
signal s_data : STD_LOGIC_VECTOR(8 downto 0); --Signal for data
constant delay : STD_LOGIC_VECTOR(6 downto 0) := "0110010"; --Provided 25MHz, 50 cycles is 2us
constant delayLong : STD_LOGIC_VECTOR(6 downto 0) := "1100100";
begin
n64RX: process(clk25, N64RXD, clr, tdre)
begin
if clr = '1' then
s_timeoutDetect <= '0';
s_echoSig <= '1';
s_sel <= '0';
state <= start;
s_data <= "000000000";
transmit <= '0';
s_bitCount <= "0000";
s_baudCount <= "0000000";
elsif (clk25'event and clk25 = '1') then --on rising edge of clock input
case state is
when start =>
--s_timeoutDetect <= '0';
s_sel <= '0';
transmit <= '0'; --Don't request UART to transfer
s_data <= "000000000";
s_bitCount <= X"0";
if N64RXD = '1' then
state <= start;
elsif N64RXD = '0' then --if Start bit detected
state <= delay2us;
end if;
when delay2us => --wait two microseconds to sample
--s_timeoutDetect <= '0';
s_sel <= '1';
s_echoSig <= '0';
if s_baudCount >= delay then
state <= sigSample;
else
s_baudCount <= s_baudCount + 1;
state <= delay2us;
end if;
when sigSample =>
--s_timeoutDetect <= '1';
s_echoSig <= N64RXD;
s_bitCount <= s_bitCount + 1;
s_baudcount <= "0000000";
s_data <= s_data(7 downto 0) & N64RXD;
state <= waitForStop;
when waitForStop =>
s_echoSig <= N64RXD;
if N64RXD = '0' then
state <= waitForStop;
elsif N64RXD = '1' then
state <= waitForStart;
end if;
when waitForStart =>
s_echoSig <= '1';
s_baudCount <= s_baudCount + 1;
if N64RXD = '0' then
s_baudCount <= "0000000";
state <= delay2us;
elsif N64RXD = '1' then
if s_baudCount >= delayLong then
state <= timeout;
elsif s_bitCount >= X"9" then
state <= count9bits;
else
state <= waitForStart;
end if;
end if;
when count9bits =>
s_sel <= '0';
if tdre = '0' then
state <= count9bits;
elsif tdre = '1' then
state <= sendToUART;
end if;
when sendToUART =>
transmit <= '1';
if tdre = '0' then
state <= start;
else
state <= sendToUART;
end if;
when timeout =>
--s_timeoutDetect <= '1';
state <= start;
end case;
end if;
end process n64RX;
--timeoutDetect <= s_timeoutDetect;
bitcount <= s_bitCount;
echoSig <= s_echoSig;
sel <= s_sel;
data <= s_data(4 downto 1);
end N64RX;
Quindi, qualche idea? Suggerimenti per il debug? Suggerimenti sulla codifica di macchine a stati finiti?
Nel frattempo, continuerò a giocarci (alla fine ce la farò)! Aiutami a Stack Exchange, sei la mia unica speranza!
modificare
Un'ulteriore scoperta nel mio debug, gli stati passeranno da waitForStart a waitForStop. Ho dato a ogni stato un valore con waitForStart uguale a '5' e waitForStop uguale a '4'. Vedi l'immagine qui sotto: