Jump to content
  • 0

Pmod JSTK2: Two-axis Joystick -- Beginner Issues


Frank Soucy

Question

Hello,

 

I am developing on an ARTY A7-35T board and attempting to connect my PMOD JSTK2 joystick. I believe I am correctly implementing the SPI specification found here: https://reference.digilentinc.com/reference/pmod/pmodjstk2/reference-manual. My CS output is always low, my MOSI output is always low, and I am turning my 100 MHz clock into a 1 MHz clock (per the SPI specification) using a counter. I am attempting to simply get the basic 5 bytes from the joystick, with ideally the final bit of the final byte of this sequence being high if the joystick is pressed in. However, using the ILA IP core, it seems that despite my output signals being correct to my understanding, the MISO signal is almost always low (rarely and erratically high). I have posted my Verilog, constraints, and ILA output below. Thank you very much for your help.

 

Code:

module top(
    input wire clk,             // board clock: 100 MHz on Arty/Basys3/Nexys
    input wire i_miso,
    output wire o_cs,
    output wire o_mosi,
    output wire o_sck,
    output wire blue
    );
        
    reg [15:0] count = 0;
    reg cs = 1;
    reg sck = 0;
    reg [8:0] bit = 0;
    reg joystick_status = 0;
    reg mosi = 0;
    
    assign o_cs = cs;
    assign o_mosi = mosi;
    assign o_sck = sck;
    assign blue = joystick_status;
    
    // ja[0] is CS
    // ja[1] is MOSI
    // ja[2] is MISO
    // ja[3] is serial clock
    
    reg [31:0] cs_count = 0;
    
    ila_0 myila (clk, o_cs, o_mosi, i_miso, o_sck);
    
    always @(posedge clk) begin
      mosi <= 0;
      
      if (count == 49) begin
        count <= 0;
        sck <= ~sck;
      end
      else begin
        count <= count + 1;
      end
      
      if (cs == 1) begin
        if (cs_count == 200) begin
          cs_count <= 0;
          cs <= 0;
        end
        else begin
          cs_count <= cs_count + 1;
        end
      end
      
      if (cs == 0) begin // cs low
      if (i_miso) begin
        //joystick_status <= 1;
      end
      if (bit == 79 && count == 3 && ~sck) joystick_status <= i_miso;
      if (count == 49) begin
        // bits 0-7 send 0, bit 49 is joystick input
        // bit 49 is joystick
        if (~sck) begin // going high
          if (bit == 79) begin
            bit <= 0;
            cs <= 1;
          end
          else begin
            bit <= bit + 1;
          end
        end
      end
    end
    end // cs low
endmodule

Constraints:

## Clock signal
set_property -dict { PACKAGE_PIN E3    IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L12P_T1_MRCC_35 Sch=gclk[100]
create_clock -add -name sys_clk_pin -period 10 -waveform {0 5} [get_ports { clk }];

## Switches
#set_property -dict { PACKAGE_PIN A8    IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L12N_T1_MRCC_16 Sch=sw[0]
#set_property -dict { PACKAGE_PIN C11   IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L13P_T2_MRCC_16 Sch=sw[1]
#set_property -dict { PACKAGE_PIN C10   IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L13N_T2_MRCC_16 Sch=sw[2]
#set_property -dict { PACKAGE_PIN A10   IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L14P_T2_SRCC_16 Sch=sw[3]

## RGB LEDs
set_property -dict { PACKAGE_PIN E1    IOSTANDARD LVCMOS33 } [get_ports { blue }]; #IO_L18N_T2_35 Sch=led0_b

## Pmod Header JA
#set_property -dict { PACKAGE_PIN G13   IOSTANDARD LVCMOS33 } [get_ports { o_cs }]; #IO_0_15 Sch=ja[1]
#set_property -dict { PACKAGE_PIN B11   IOSTANDARD LVCMOS33 } [get_ports { o_mosi }]; #IO_L4P_T0_15 Sch=ja[2]
#set_property -dict { PACKAGE_PIN A11   IOSTANDARD LVCMOS33 } [get_ports { i_miso }]; #IO_L4N_T0_15 Sch=ja[3]
#set_property -dict { PACKAGE_PIN D12   IOSTANDARD LVCMOS33 } [get_ports { o_sck }]; #IO_L6P_T0_15 Sch=ja[4]
#set_property -dict { PACKAGE_PIN D13   IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L6N_T0_VREF_15 Sch=ja[7]
#set_property -dict { PACKAGE_PIN B18   IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L10P_T1_AD11P_15 Sch=ja[8]
#set_property -dict { PACKAGE_PIN A18   IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L10N_T1_AD11N_15 Sch=ja[9]
#set_property -dict { PACKAGE_PIN K16   IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_25_15 Sch=ja[10]

## Pmod Header JB
set_property -dict { PACKAGE_PIN E15   IOSTANDARD LVCMOS33 } [get_ports { o_cs }]; #IO_L11P_T1_SRCC_15 Sch=jb_p[1]
set_property -dict { PACKAGE_PIN E16   IOSTANDARD LVCMOS33 } [get_ports { o_mosi }]; #IO_L11N_T1_SRCC_15 Sch=jb_n[1]
set_property -dict { PACKAGE_PIN D15   IOSTANDARD LVCMOS33 } [get_ports { i_miso }]; #IO_L12P_T1_MRCC_15 Sch=jb_p[2]
set_property -dict { PACKAGE_PIN C15   IOSTANDARD LVCMOS33 } [get_ports { o_sck }]; #IO_L12N_T1_MRCC_15 Sch=jb_n[2]
#set_property -dict { PACKAGE_PIN J17   IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L23P_T3_FOE_B_15 Sch=jb_p[3]
#set_property -dict { PACKAGE_PIN J18   IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L23N_T3_FWE_B_15 Sch=jb_n[3]
#set_property -dict { PACKAGE_PIN K15   IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_L24P_T3_RS1_15 Sch=jb_p[4]
#set_property -dict { PACKAGE_PIN J15   IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L24N_T3_RS0_15 Sch=jb_n[4]

ILA output:

v4.thumb.png.84f09d79b97411ab47bc7c80207ec0e5.png

Link to comment
Share on other sites

5 answers to this question

Recommended Posts

2 hours ago, Frank Soucy said:

@D@n, thank you very much for your help. Ok, got it. I have a few follow up questions. 1) If CS is always low, ...

Let me stop your right there.  CS is *not* "always low".  It needs to be high between sets of the five bytes.  Indeed, if you want to read a second set of five bytes, I would expect that you would need to raise the CS line.

If you haven't read it, then let me recommend Digilent's SPI primer to you.  (I'd normally recommend one of my own, but I've only written one SPI primer and that was specific to reading from flash memory.)  In particular, note their diagram:

spi_signals.png?w=900&tok=5742c2

The typical SPI interaction starts with CS  high (inactive).  Once it goes low, the whole communication becomes active and the frame starts.  You can set and hold MOSI low to keep from sending a command to the joystick, otherwise there are several commands you could send.  In all cases, the first bit is so marked by the first rising edge of the clock after CS goes low (active).  Most of the designs I've built will also stop SCK from toggling once CS is high as well, as in this example from my flash tutorial.

spi-bare.png

In your case, you should have five bytes transfer from slave (the joystick) to the master (your FPGA).  Once all five bytes have been received, the CS line should be pulled high for a minimum of time (could be one clock period, might be more, should be in the data sheet for the part and not necessarily Digilent's resource page).  After that time, you can lower it for the next query any time you want.

Dan

Link to comment
Share on other sites

@Frank Soucy,

Looking over your code, I think you've misunderstood the purpose of the CS signal.  Yes, it is active low.  Yes, without going low the port will remain idle.  However, the CS signal is used to determine the beginning of the 5-byte packet.  Therefore I'd recommend dropping CS for 40 SPI clocks any time you want a reading, and then raising it back again once done--that way you can drop it again later for another reading.

Dan

Link to comment
Share on other sites

4 hours ago, D@n said:

@Frank Soucy,

Looking over your code, I think you've misunderstood the purpose of the CS signal.  Yes, it is active low.  Yes, without going low the port will remain idle.  However, the CS signal is used to determine the beginning of the 5-byte packet.  Therefore I'd recommend dropping CS for 40 SPI clocks any time you want a reading, and then raising it back again once done--that way you can drop it again later for another reading.

Dan

@D@n, thank you very much for your help. Ok, got it. I have a few follow up questions. 1) If CS is always low, shouldn't I always be getting valid MISO signals if I'm sending valid MOSI signals? 2) Are my MOSI signals valid for the standard 5 byte exchange? I see the standard 5 byte exchange is a 0 byte followed by 4 "dummy" bytes -- thus, shouldn't it be valid to simply keep MOSI always low? 3) Finally, are the MOSI 5 bytes and the MISO 5 bytes sent/received simultaneously? In other words, should the "total" reading take 40 SPI clocks or 80?

Link to comment
Share on other sites

18 hours ago, D@n said:

Let me stop your right there.  CS is *not* "always low".  It needs to be high between sets of the five bytes.  Indeed, if you want to read a second set of five bytes, I would expect that you would need to raise the CS line.

If you haven't read it, then let me recommend Digilent's SPI primer to you.  (I'd normally recommend one of my own, but I've only written one SPI primer and that was specific to reading from flash memory.)  In particular, note their diagram:

spi_signals.png?w=900&tok=5742c2

The typical SPI interaction starts with CS  high (inactive).  Once it goes low, the whole communication becomes active and the frame starts.  You can set and hold MOSI low to keep from sending a command to the joystick, otherwise there are several commands you could send.  In all cases, the first bit is so marked by the first rising edge of the clock after CS goes low (active).  Most of the designs I've built will also stop SCK from toggling once CS is high as well, as in this example from my flash tutorial.

spi-bare.png

In your case, you should have five bytes transfer from slave (the joystick) to the master (your FPGA).  Once all five bytes have been received, the CS line should be pulled high for a minimum of time (could be one clock period, might be more, should be in the data sheet for the part and not necessarily Digilent's resource page).  After that time, you can lower it for the next query any time you want.

Dan

Dan, thank you very much. This is great.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...