This is a personal project; it regards connecting an FPGA to a N64, the byte values that the FPGA receives are then sent through UART to my computer. It actually functions pretty well! At random times unfortunately, the device will fail, then recover. Through debugging, I've managed to find the problem, however I am stumped at how to fix it because I'm fairly incompetent with VHDL.
I've been toying with the VHDL for a couple days now and I may be incapable of resolving this.
I have an oscilloscope measuring the N64 signal into the FPGA, and the other channel connects to the output of the FPGA. I also have digital pins recording the counter value.
Essentially, the N64 sends 9 data bits, including a STOP bit. The counter counts the data bits received and when I reach 9 bits, the FPGA starts transmitting via UART.
Here's correct behavior:
The FPGA is the blue waveform and the orange waveform is the input of the N64. For the duration of receiving, my FPGA "echos" the signal of the input for debugging purposes. After the FPGA counts to 9, it begins transmitting the data through UART. Notice that the digital pins count to 9 and the FPGA output goes LOW immediately after the N64 is finished.
Here's an example of a failure:
Notice that the counter skips bits 2 and 7! The FPGA reaches the end, waiting for the next start bit from the N64 but nothing. So the FPGA times out and recovers.
This is the VHDL for the N64 receive module. It contains the counter: 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;
So, any ideas? Debugging tips? Tips on coding Finite State Machines?
In the meantime, I'll keep playing around with it (I'll have it eventually)! Help me Stack Exchange, you're my only hope!
A further discovery in my debugging, the states will jump from waitForStart back to waitForStop. I gave each state a value with waitForStart equal to '5' and waitForStop equal to '4'. See the image below: