Antecedentes
Este es un proyecto personal; se trata de conectar un FPGA a un N64, los valores de bytes que recibe el FPGA se envían a través de UART a mi computadora. En realidad funciona bastante bien! Desafortunadamente, en momentos aleatorios, el dispositivo fallará y luego se recuperará. A través de la depuración, he logrado encontrar el problema, sin embargo, estoy desconcertado sobre cómo solucionarlo porque soy bastante incompetente con VHDL.
He estado jugando con el VHDL durante un par de días y es posible que no pueda resolver esto.
El problema
Tengo un osciloscopio que mide la señal N64 en el FPGA, y el otro canal se conecta a la salida del FPGA. También tengo pines digitales que registran el valor del contador.
Esencialmente, el N64 envía 9 bits de datos, incluido un bit STOP. El contador cuenta los bits de datos recibidos y cuando alcanzo los 9 bits, el FPGA comienza a transmitir a través de UART.
Aquí está el comportamiento correcto:
El FPGA es la forma de onda azul y la forma de onda naranja es la entrada del N64. Durante la duración de la recepción, mi FPGA "echos" la señal de la entrada para fines de depuración. Después de que el FPGA cuenta hasta 9, comienza a transmitir los datos a través de UART. Tenga en cuenta que los pines digitales cuentan hasta 9 y la salida FPGA pasa a BAJA inmediatamente después de que finaliza el N64.
Aquí hay un ejemplo de falla:
¡Observe que el contador omite los bits 2 y 7! El FPGA llega al final, esperando el próximo bit de inicio del N64 pero nada. Entonces el FPGA agota el tiempo de espera y se recupera.
Este es el VHDL para el módulo de recepción N64. Contiene el 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;
Entonces, ¿alguna idea? Consejos de depuración? ¿Consejos para codificar máquinas de estado finito?
Mientras tanto, seguiré jugando con él (lo tendré eventualmente). ¡Ayúdame a Stack Exchange, eres mi única esperanza!
Editar
Un descubrimiento adicional en mi depuración, los estados pasarán de waitForStart a waitForStop. Le di a cada estado un valor con waitForStart igual a '5' y waitForStop igual a '4'. Ver la imagen a continuación: