fundo
Este é um projeto pessoal; No que diz respeito à conexão de um FPGA a um N64, os valores de bytes recebidos pelo FPGA são enviados pelo UART ao meu computador. Na verdade, funciona muito bem! Infelizmente, em momentos aleatórios, o dispositivo falhará e depois se recuperará. Através da depuração, eu consegui encontrar o problema, mas estou perplexo em saber como corrigi-lo porque sou bastante incompetente com o VHDL.
Estou brincando com o VHDL há alguns dias e posso ser incapaz de resolver isso.
O problema
Eu tenho um osciloscópio medindo o sinal N64 no FPGA, e o outro canal se conecta à saída do FPGA. Eu também tenho pinos digitais gravando o valor do contador.
Essencialmente, o N64 envia 9 bits de dados, incluindo um bit STOP. O contador conta os bits de dados recebidos e, quando chego aos 9 bits, o FPGA começa a transmitir via UART.
Aqui está o comportamento correto:
O FPGA é a forma de onda azul e a forma de onda laranja é a entrada do N64. Durante o recebimento, meu FPGA "repete" o sinal da entrada para fins de depuração. Depois que o FPGA conta até 9, ele começa a transmitir os dados através do UART. Observe que os pinos digitais contam até 9 e a saída do FPGA fica LOW imediatamente após a finalização do N64.
Aqui está um exemplo de falha:
Observe que o contador ignora os bits 2 e 7! O FPGA chega ao fim, aguardando o próximo bit de partida do N64, mas nada. Então o FPGA expira e se recupera.
Este é o VHDL para o módulo de recebimento N64. Ele contém o contador: 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;
Então, alguma ideia? Dicas de depuração? Dicas para codificar máquinas de estados finitos?
Enquanto isso, continuarei brincando com ele (acabarei com ele)! Ajude-me a Stack Exchange, você é minha única esperança!
Editar
Uma descoberta adicional na minha depuração, os estados passarão de waitForStart de volta para waitForStop. Eu dei a cada estado um valor com waitForStart igual a '5' e waitForStop igual a '4'. Veja a imagem abaixo: