Interfacing an SNES controller with an FPGA (help)

Thread Starter

aftrumpet

Joined Jan 7, 2015
6
I have been trying to write a Verilog design for a while to interface with a SNES controller and read it's button outputs, using this page as a guide: http://www.gamefaqs.com/snes/916396-super-nintendo/faqs/5395

This is what I have:
Code:
module SNES(input clock, input snes_data,
    output snes_clock, output reg snes_latch,
    output reg a, output reg b, output reg x, output reg y,
    output reg up, output reg down, output reg left, output reg right,
    output reg l, output reg r, output reg start, output reg select);

reg[3:0] btn_counter;

reg latch;

initial latch <= 1;

assign snes_clock = snes_latch ? 1 : clock;

always @ (posedge clock)
snes_latch <= latch;

always @ (negedge clock)
if (latch) latch <= 0;
else begin
case (btn_counter)
    0: b <= ~snes_data;
    1: y <= ~snes_data;
    2: select <= ~snes_data;
    3: start <= ~snes_data;
    4: up <= ~snes_data;
    5: down <= ~snes_data;
    6: left <= ~snes_data;
    7: right <= ~snes_data;
    8: a <= ~snes_data;
    9: x <= ~snes_data;
    10: l <= ~snes_data;
    11: r <= ~snes_data;
endcase
btn_counter <= btn_counter + 1;
latch <= btn_counter == 0;
end

endmodule
And the clock I'm using has a period of 12us (to fit the specifications described), and is divided up with this:
Code:
module clk_div(Clk_in, Clk_out);

// input ports
input Clk_in;

// output ports
output reg Clk_out;

parameter max = 300; // max-counter size

reg [8:0]counter = 0; // 9-bit counter size

always@(posedge Clk_in) begin
    if (counter == max-1)
        begin
        counter <= 0;
        Clk_out <= ~Clk_out;
        end
    else
        begin
        counter <= counter + 1'd1;
        end
    end
endmodule
However, I am getting nothing but a high signal from the SNES data line. I have debugged this with both a simulator and Signal Tap and seem to be doing everything right. My logic analyzer output is attached, with data, clock, and latch from top to bottom. Just looking at this, can anyone see if I am doing something wrong? This far, I haven't been able to get anything but a high data signal from the controller.
 

Attachments

JWHassler

Joined Sep 25, 2013
308
What device are you compiling this for?
I ask because the construction
always @ (negedge clock)
is not supported by most hardware accessible to us (forgive me) small-timers.
Most parts from A**** and X***** do everything on the positive clock-edge.
It's not a problem, though: do everything based on your 25MHz(?) input-clock. The value of a particular input is then read at the " positive-edge of the 50th 25MHz clock in a 300 clock sequence" or
whatever the numbers work out to.
Also, I don't see that your clock-divider module is tied to your decoder in any way. Perhaps you have a higher-level module that connects them?
 

Thread Starter

aftrumpet

Joined Jan 7, 2015
6
I probably should have explained this clearer. I'm using a block diagram to connect the output of the clock divider to the clock of the SNES controller module.

As for hardware, I'm using the Altera DE0 board, which is powered by a Cyclone III. According to the attached Signal Tap output, the negative edge trigger is working as expected and the signals are what I want them to be, but the SNES controller is not responding as it should so I think my methodology is wrong, not the execution.
 

Brownout

Joined Jan 10, 2012
2,390
I am getting nothing but a high signal from the SNES data line.
If you mean "snes_data" you've declared that as an input, and you don't generate that with your code. There is nothing you can do from a code standpoint to fix this. What is this signal? Where is it generated? If this comes from an external device, check that your design is pinned out correctly. BTW, you need to connect the 'reset' signal from your board and use it to initialize your logic. The "initial" construct doesn't work for read hardware.
 
Last edited:

Brownout

Joined Jan 10, 2012
2,390
One more thing, it looks like you're generating the snes_latch in your code, but if that is a signal to synchronize the arriving data, it must come from the external device.
 

MagicMatt

Joined Sep 30, 2013
117
No, the latch is created by the console, and is a signal to tell the controller to read the state of the buttons. When you release latch, the controller then sends back the button data.
 

MagicMatt

Joined Sep 30, 2013
117
The clock is for reading the button data... I wouldn't regard it as a clock personally, it's more like a "next" signal. When you release the latch, you get the state of the first button on the data line. If you then pulse the next(clock) line, you get the second button on the data line, etc.
 

Thread Starter

aftrumpet

Joined Jan 7, 2015
6
If you mean "snes_data" you've declared that as an input, and you don't generate that with your code. There is nothing you can do from a code standpoint to fix this. What is this signal? Where is it generated? If this comes from an external device, check that your design is pinned out correctly. BTW, you need to connect the 'reset' signal from your board and use it to initialize your logic. The "initial" construct doesn't work for read hardware.
snes_data is an input, yes, but it comes from the SNES controller and is controlled by the latch and clock lines. I have tested an Arduino library someone made for this and it does the same thing, the code can be viewed here: https://github.com/TacticalCode/SNESpaduino/blob/master/SNESpaduino.cpp

As far as finding a solution goes, one potential source of the problem is that the GPIO pins on the DE0 board are 3.3V signals, but I have been providing 5V power to the SNES controller. I can try to power it with 3.3V and see if this solves anything, and if this doesn't work I may have to use a logic level converter.

I am also going to try to analyze the signals from the working Arduino sketch and potentially replicate those.
 

MagicMatt

Joined Sep 30, 2013
117
I can't remember what the actual chips are inside the SNES controllers - whether they are CMOS or TTL. If they are CMOS, you may be creating your own problem, because the "high" level will be 2/3 of VDD, and at 5V that's 3V, which is pretty close to the 3.3V and doesn't give you much allowance for any drop on the cable etc. If you supply 3,3V to the controller and it's CMOS, it should run ok and the logic high will drop down to just under 2V.
 

Thread Starter

aftrumpet

Joined Jan 7, 2015
6
Just looked it up and the controller is indeed CMOS. I tried using the FPGA to analyze the Arduino's logic signals but those are 5V, so no luck there. I ordered a logic analyzer though so that should come next week.

Also of note is I tried unconnecting the power line to the controller and still got a high data signal, meaning that it's just the default pulled up high and nothing more. Based on this I might have my pin configuration wrong, though I have checked many times to ensure that it's correct.
 

MagicMatt

Joined Sep 30, 2013
117
I found an old SNES controller... I couldn't use your code as I only have MASM and XC8...

This sequence worked though, based on your link in psuedo-code:
Code:
Put the "latch" pin high for 12 micro seconds
Put the "latch" pin low
LOOP 12 times:
    Wait 6 micro seconds
    Read the serial data line (gives you status of button)
    Wait 6 micro seconds
    Put "clock" to high
    Wait 12 micro seconds
    Put "clock" to low
END LOOP
Every time you go around the loop, you get the status of the next button until you've read all the buttons.

You can use a timer to make that execute every 16mS (the spec says 16.67mS but it happily ran far more frequently).
 

MagicMatt

Joined Sep 30, 2013
117
Note: It will also run far faster - this just worked too:
Code:
Put the "latch" pin high for 12 micro seconds
Put the "latch" pin low
LOOP 12 times:
    Wait 3 micro seconds
    Read the serial data line (gives you status of button)
    Wait 3 micro seconds
    Put "clock" to high
    Wait 6 micro seconds
    Put "clock" to low
END LOOP
 

Thread Starter

aftrumpet

Joined Jan 7, 2015
6
I found an old SNES controller... I couldn't use your code as I only have MASM and XC8...

This sequence worked though, based on your link in psuedo-code:
Code:
Put the "latch" pin high for 12 micro seconds
Put the "latch" pin low
LOOP 12 times:
    Wait 6 micro seconds
    Read the serial data line (gives you status of button)
    Wait 6 micro seconds
    Put "clock" to high
    Wait 12 micro seconds
    Put "clock" to low
END LOOP
Every time you go around the loop, you get the status of the next button until you've read all the buttons.

You can use a timer to make that execute every 16mS (the spec says 16.67mS but it happily ran far more frequently).
Can you look at the logic analyzer output I've attached to the first post? That seems like exactly what I've been doing, and if this is the same then I likely have a connection or voltage issue.
 

MagicMatt

Joined Sep 30, 2013
117
I see two differences (other than the lack of data)
1 - I used a cheap PIC I had laying around - a PIC16F690 - everything is 5V.
2 - My clock is LOW and STAYS LOW when I trigger the latch. This is why I do not like calling it a clock - it's a "NEXT" - a trigger to read the next value on a 16 bit shift register.
 

MagicMatt

Joined Sep 30, 2013
117
As far as I can tell, what happens inside the controller is that the "latch" tells the controller to read the button states and load them into the 16bit shift register (probably two 8 bit registers in series). You're then reading that data and using the "next" signal to shuffle the data along to read the next value.
 

Thread Starter

aftrumpet

Joined Jan 7, 2015
6
I just tested the circuit with my logic analyzer, and I'm not getting anything on the output pins. Weird. My DE0's GPIO may be broken (though I don't know when that would've happened), but I also have a Papilio One that I will try this design out on.
 
Top