Hintergrund
Dies ist ein persönliches Projekt; Beim Anschließen eines FPGA an einen N64 werden die vom FPGA empfangenen Bytewerte dann über UART an meinen Computer gesendet. Es funktioniert tatsächlich ziemlich gut! Zu zufälligen Zeiten fällt das Gerät leider aus und wird dann wiederhergestellt. Durch das Debuggen habe ich es geschafft, das Problem zu finden, aber ich bin ratlos, wie ich es beheben kann, weil ich mit VHDL ziemlich inkompetent bin.
Ich spiele jetzt seit ein paar Tagen mit der VHDL und bin möglicherweise nicht in der Lage, dieses Problem zu lösen.
Das Problem
Ich habe ein Oszilloskop, das das N64-Signal im FPGA misst, und der andere Kanal wird mit dem Ausgang des FPGA verbunden. Ich habe auch digitale Pins, die den Zählerwert aufzeichnen.
Im Wesentlichen sendet der N64 9 Datenbits, einschließlich eines STOP-Bits. Der Zähler zählt die empfangenen Datenbits und wenn ich 9 Bits erreiche, beginnt das FPGA mit der Übertragung über UART.
Hier ist das richtige Verhalten:
Das FPGA ist die blaue Wellenform und die orange Wellenform ist der Eingang des N64. Für die Dauer des Empfangs "hallt" mein FPGA das Signal des Eingangs zu Debugging-Zwecken. Nachdem das FPGA bis 9 gezählt hat, beginnt es mit der Übertragung der Daten über UART. Beachten Sie, dass die digitalen Pins bis 9 zählen und der FPGA-Ausgang unmittelbar nach Fertigstellung des N64 auf LOW geht.
Hier ist ein Beispiel für einen Fehler:
Beachten Sie, dass der Zähler die Bits 2 und 7 überspringt! Das FPGA erreicht das Ende und wartet auf das nächste Startbit vom N64, aber nichts. Das FPGA läuft also ab und erholt sich.
Dies ist die VHDL für das N64-Empfangsmodul. Es enthält den Zähler: 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;
Also irgendwelche Ideen? Debugging-Tipps? Tipps zum Codieren von Finite-State-Maschinen?
In der Zwischenzeit werde ich weiter damit herumspielen (ich werde es irgendwann haben)! Hilf mir, den Austausch zu stapeln, du bist meine einzige Hoffnung!
Bearbeiten
Eine weitere Entdeckung in meinem Debugging ist, dass die Zustände von waitForStart zurück zu waitForStop springen. Ich habe jedem Status einen Wert mit waitForStart gleich '5' und waitForStop gleich '4' gegeben. Siehe das Bild unten: