liyang53719 发表于 2015-1-21 18:22:50

想用FPGA读PS2手柄,用串口模块改装是否可行?

前提:
1 PS2手柄宽接口的那种
           PS手柄针脚输出端(面对插头)

         ---------------------------------------------------------
          PIN 1->| ooo | ooo | ooo |
       \________________________________/

2 PS手柄信号
        PS手柄通讯都是8 bit串行数据最低有效位先行。在PS 手柄总线的所有时码在时钟下降沿都是同步的。传送一个字节的情况如下所示。
                       |BIT 0|BIT 1|BIT 2|BIT 3|BIT 4|BIT 5|BIT 6|BIT 7|
          CLOCK -----___---___---___---___---___---___---___---___-----------
          DATA-----000000111111222222333333444444555555666666777777--------
                          *   *   *   *   *   *   *   *
          CMND-----000000111111222222333333444444555555666666777777--------
        注:        CMND:FPGA端向手柄端发送指令
                DATA:手柄端向FPGA端发送信号

3 串口收发模块借用《verilog那些事》里串口收发模块

两者异同:
同:        都是8位有效位,低位先行。
        上升沿采集信号
        收发互不干扰
异:        收发模块时钟同频率,但是不一定同步。
        串口没有时钟线,PS2需要(FPGA端)提供时钟信号
       
正式问题:
        在《verilog那些事》里串口收发模块各自都有BPS模块,但是发送端只有在有数据要发送时BPS才开始计时。接受模块也是在接受到第一位信号时BPS才开始计时的。我想把这两个BPS模块从收发模块中独立出来。用这个模块输出PS2端口的时钟,同时送给两个收发模块。收发模块都有使能信号。不使能时应该不会影响。
        再加一个控制模块直接接受串口接收模块的8位数据,再发送另一个8位数据给串口发送模块。以实现解读PS2手柄信息。
       
想请教一下这种想法是否可行,如可行还有那些地方我要注意的也请多多指教。
另:本人基础薄弱,描述的不清楚请见谅。

zkf0100007 发表于 2015-1-21 19:05:17

肯定可以,但是为什么要用串口模块改装,不如重新写

liyang53719 发表于 2015-1-21 21:35:24

zkf0100007 发表于 2015-1-21 19:05
肯定可以,但是为什么要用串口模块改装,不如重新写

开始懒得重写,现在越来越发现好像该还不如重写。

zkf0100007 发表于 2015-1-22 09:11:31

倒是可以参考PS键盘和鼠标的代码

liyang53719 发表于 2015-1-22 18:54:22

zkf0100007 发表于 2015-1-22 09:11
倒是可以参考PS键盘和鼠标的代码

谢谢,两者很相似么?PS键盘没研究过

zkf0100007 发表于 2015-1-22 19:18:54

liyang53719 发表于 2015-1-22 18:54
谢谢,两者很相似么?PS键盘没研究过

------------------------------------------------------------------------
--   Keyboard.vhd -- Demonstrate basic keyboard function
------------------------------------------------------------------------
-- Author:Ken Nelson
--          Copyright 2004 Digilent, Inc.
------------------------------------------------------------------------
-- DESCRIPTION
------------------------------------------------------------------------
-- Revision History:
--       06/14/04 (Created) KenN
--07/01/04 (Optomized) DanP
------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity Keyboard is
        Port (        CLK, RST, KD, KC: in std_logic;
                                an: out std_logic_vector (3 downto 0);
                                ssg: out std_logic_vector (6 downto 0));
end Keyboard;


architecture Behavioral of Keyboard is

        ------------------------------------------------------------------------
        -- Component Declarations
        ------------------------------------------------------------------------

        ------------------------------------------------------------------------
        -- Signal Declarations
        ------------------------------------------------------------------------
        signal clkDiv : std_logic_vector (12 downto 0);
        signal pclk : std_logic;
        signal sclk:std_logic_vector(1 downto 0);
        signal KDI, KCI : std_logic;
        signal DFF1, DFF2 : std_logic;
        signal shiftRegSig1: std_logic_vector(10 downto 0);
        signal shiftRegSig2: std_logic_vector(10 downto 1);
        signal MUXOUT: std_logic_vector (3 downto 0);
        signal WaitReg: std_logic_vector (7 downto 0);       
        signal DisReg0,DisReg1,DisReg2,DisReg3:std_logic_vector (3 downto 0);
        signal Dis:bit;
        ------------------------------------------------------------------------
        -- Module Implementation
        ------------------------------------------------------------------------

        begin
        --Divide the master clock down to a lower frequency--
        CLKDivider: Process (CLK)
        begin
                if (CLK = '1' and CLK'Event) then
                        clkDiv <= clkDiv +1;
                end if;       
        end Process;

        sclk <= clkDiv(11 downto 10);
        pclk <= clkDiv(3);

        --Flip Flops used to condition siglans coming from PS2--
        Process (pclk, RST, KC, KD)
        begin
                if(RST = '1') then
                        DFF1 <= '0'; DFF2 <= '0'; KDI <= '0'; KCI <= '0';
                else                                                                                               
                        if (pclk = '1' and pclk'Event) then
                                DFF1 <= KD; KDI <= DFF1; DFF2 <= KC; KCI <= DFF2;
                        end if;
                end if;
        end process;

        --Shift Registers used to clock in scan codes from PS2--
        Process(KDI, KCI, RST) --DFF2 carries KD and DFF4, and DFF4 carries KC
        begin                                                                                                                                                                          
                if (RST = '1') then
                        ShiftRegSig1 <= "00000000000";
                        ShiftRegSig2 <= "0000000000";
                else
                        if (KCI = '0' and KCI'Event) then
                                ShiftRegSig1(10 downto 0) <= KDI & ShiftRegSig1(10 downto 1);
                                ShiftRegSig2(10 downto 1) <= ShiftRegSig1(0) & ShiftRegSig2(10 downto 2);
                        end if;
                end if;
        end process;
       
        --Wait Register
        process(ShiftRegSig1, ShiftRegSig2, RST, KCI)
        begin
                if(RST = '1')then
                        WaitReg <= "00000000";
                else
                        if(KCI'event and KCI = '1' and ShiftRegSig2(8 downto 1) = "11110000")then
                                WaitReg <= ShiftRegSig1(8 downto 1);
                                --case WaitReg is
                                        --when "01000101"=> DisReg<="0000";--0
                                        --when "00010110"=> DisReg<="0001";--1
                                        --when "00011110"=> DisReg<="0010";--2
                                        --when "00100110"=> DisReg<="0011";--3
                                        --when "00100101"=> DisReg<="0100";--4
                                        --when "00101110"=> DisReg<="0101";--5
                                        --when "00110110"=> DisReg<="0110";--6
                                        --when "00111101"=> DisReg<="0111";--7
                                        --when "00111110"=> DisReg<="1000";--8
                                        --when "01000110"=> DisReg<="1001";--9
                                        --when "00011100"=> DisReg<="1010";--A
                                        --when "00110010"=> DisReg<="1011";--B
                                        --when "00100001"=> DisReg<="1100";--C
                                        --when "00100011"=> DisReg<="1101";--D
                                        --when "00100100"=> DisReg<="1110";--E
                                        --when "00101011"=> DisReg<="1111";--F
                                        --when others=>null;
                                --end case;
                               
                                DisReg1<=DisReg0;
                                DisReg2<=DisReg1;
                                DisReg3<=DisReg2;
                        end if;                       
                end if;
        end Process;

        DisReg0<="0000" when WaitReg="01000101" else --45 0
                   "0001"when WaitReg="00010110" else --16 1
                   "0010"when WaitReg="00011110" else --1E 2
                   "0011"when WaitReg="00100110" else --26 3
                   "0100"when WaitReg="00100101" else --25 4
                   "0101"when WaitReg="00101110" else --2E 5
                   "0110"when WaitReg="00110110" else --36 6
                   "0111"when WaitReg="00111101" else --3D 7
                   "1000"when WaitReg="00111110" else --3E 8
                   "1001"when WaitReg="01000110" else --46 9
                   "1010"when WaitReg="00011100" else --1C A
                   "1011"when WaitReg="00110010" else --32 B
                   "1100"when WaitReg="00100001" else --21 C
                   "1101"when WaitReg="00100011" else --23 D
                   "1110"when WaitReg="00100100" else --24 E
                   "1111"when WaitReg="00101011" else --2B F
                   "ZZZZ";

        Dis<='1'when WaitReg="01000101" else
                '1'when WaitReg="00010110" else
                '1'when WaitReg="00011110" else --1E 2
                '1'when WaitReg="00100110" else --26 3
                '1'when WaitReg="00100101" else --25 4
                '1'when WaitReg="00101110" else --2E 5
                '1'when WaitReg="00110110" else --36 6
                '1'when WaitReg="00111101" else --3D 7
                '1'when WaitReg="00111110" else --3E 8
                '1'when WaitReg="01000110" else --46 9
                '1'when WaitReg="00011100" else --1C A
                '1'when WaitReg="00110010" else --32 B
                '1'when WaitReg="00100001" else --21 C
                '1'when WaitReg="00100011" else --23 D
                '1'when WaitReg="00100100" else --24 E
                '1'when WaitReg="00101011" else --2B F
                '0';
                  
        --Multiplexer

        MUXOUT <=DisReg0 when sclk = "00" else
                  DisReg1 when sclk = "01" else
                  DisReg2 when sclk = "10" else
                  DisReg3 when sclk = "11";
                  
                                  

        --Seven Segment Decoder--
        ssg <=        "1000000" when MUXOUT = "0000" else
                        "1111001" when MUXOUT = "0001" else
                        "0100100" when MUXOUT = "0010" else
                        "0110000" when MUXOUT = "0011" else
                        "0011001" when MUXOUT = "0100" else
                        "0010010" when MUXOUT = "0101" else
                        "0000010" when MUXOUT = "0110" else
                        "1111000" when MUXOUT = "0111" else
                        "0000000" when MUXOUT = "1000" else
                        "0010000" when MUXOUT = "1001" else
                        "0001000" when MUXOUT = "1010" else
                        "0000011" when MUXOUT = "1011" else
                        "1000110" when MUXOUT = "1100" else
                        "0100001" when MUXOUT = "1101" else
                        "0000110" when MUXOUT = "1110" else
                        "0001110" when MUXOUT = "1111" else
                        "1111111";

        --Anode Driver--
        an<="1110" when sclk = "00" and Dis='1' else
          "1101" when sclk = "01" and Dis='1' else
          "1011" when sclk = "10" and Dis='1' else
          "0111" when sclk = "11" and Dis='1' else
          "1111";
          
                               
end Behavioral;

zkf0100007 发表于 2015-1-22 19:19:59

上面是PS键盘的代码,可以参考一下

putty 发表于 2015-1-23 10:00:01

想读PS2手柄的话,用SPI正好

liyang53719 发表于 2015-1-23 15:23:59

zkf0100007 发表于 2015-1-22 19:19
上面是PS键盘的代码,可以参考一下

多谢多谢,我研究一下

liyang53719 发表于 2015-1-23 15:25:32

putty 发表于 2015-1-23 10:00
想读PS2手柄的话,用SPI正好

SPI是接口还是个协议?协议听说过I2C。

liyang53719 发表于 2015-1-23 16:58:37

本帖最后由 liyang53719 于 2015-1-23 17:45 编辑

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity handset is
generic(divdelay:integer :=99999);
port(busclk      :in std_logic;   --shizhong
       sclk           :in std_logic;   --
       reset        :in std_logic;
       handdata        :in std_logic;
       command        :out std_logic_vector(2 downto 0);
       IDcheck1   :out std_logic_vector(7 downto 0);
       IDcheck2   :out std_logic_vector(7 downto 0);
       IDcheck3   :out std_logic_vector(7 downto 0);
       recAnalogData1   :out std_logic_vector(7 downto 0);
       recAnalogData2   :out std_logic_vector(7 downto 0);
       recAnalogData3   :out std_logic_vector(7 downto 0);
       recAnalogData4   :out std_logic_vector(7 downto 0);
       recDigitalData1       :out std_logic_vector(7 downto 0);
       recDigitalData2       :out std_logic_vector(7 downto 0));
endhandset;
architecture Behavioral of handset is
signal count   :integerrange 0 to 8 := 0;
signal comdcount   :integerrange 0 to 10 ;
signal temp_data : std_logic_vector(7 downto 0) :="11111111";
signal temp_command : std_logic_vector(2 downto 0) := "111";
signal comdstate :std_logic := '0';
signal comdstate1 :std_logic := '0';
signal comdstate2 :std_logic := '0';
signal comdstate3   :std_logic := '0';
signal comdstate4   :std_logic := '0';
signal delaystate   :std_logic := '0';
signal delaystate1   :std_logic := '0';
signal delaystate2   :std_logic := '0';
signal result : std_logic_vector(8 downto 0) :="000000000";
signal HandsetMode   :std_logic;
        --signal comdstate1,comdstate2 : std_logic := '0';

begin

process(comdcount,temp_data(7 downto 0))
begin
        case comdcount is
                when 0 => temp_data(7 downto 0) <= "00000001";
                when 1 => temp_data(7 downto 0) <= "01000010";
                when 2 => temp_data(7 downto 0) <= "11111111";
                when 3 => temp_data(7 downto 0) <= "11111111";
                when 4 => temp_data(7 downto 0) <= "11111111";
                when 5 => temp_data(7 downto 0) <= "11111111";
                when 6 => temp_data(7 downto 0) <= "11111111";
                when 7 => temp_data(7 downto 0) <= "11111111";                                       
                when 8 => temp_data(7 downto 0) <= "11111111";
                when 9 => temp_data(7 downto 0) <= "11111111";       
                when        others => null;
        end case;
end process;
command(2 downto 0) <= temp_command(2 downto 0);
process(sclk,comdcount)
begin
        if(comdcount = 9) then
                temp_command(2) <= '1';--拉高ATT
                comdstate <= '0';
        elsif(sclk'EVENT and sclk = '1')then
                comdstate <= '1';
                temp_command(2) <= '0';--拉低ATT
        end if;               
end process;

process(busclk,temp_data(7 downto 0),comdstate,comdstate1,comdstate2,comdstate3,delaystate1,delaystate2,handdata,count,comdcount)
variable tempcount :integer range 0 to 99999 :=0;
variable count1 :integer range 0 to 9 :=0;
begin
--if(sclk'EVENT and sclk = '1')then
--comdstate1 <= '1';
--end if;

if(busclk'EVENT and busclk = '1')then
        if(comdstate = '1')then
                if(tempcount = 99999)then
                        tempcount := 0;
                        comdstate1 <= '1';
                else
                        tempcount := tempcount + 1;
                        if(count1 = 8)then
                                --count <= 0;
                                case comdcount is
                                when 0 => null;
                                IDcheck1(7 downto 0)<= result(7 downto 0);
                                when 1 => null;
                                IDcheck2(7 downto 0)<= result(7 downto 0);
                                when 2 => null;IDcheck3(7 downto 0)<= result(7 downto 0);
                                when 3 =>
                                recDigitalData1(7 downto 0)<= result(7 downto 0);
                                when 4 =>
                                recDigitalData2(7 downto 0)<= result(7 downto 0);
                                when 5 =>
                                recAnalogData1(7 downto 0)<= result(7 downto 0);
                                when 6 =>
                                recAnalogData2(7 downto 0)<= result(7 downto 0);
                                when 7 =>
                                recAnalogData3(7 downto 0)<= result(7 downto 0);               
                                when 8 =>
                                recAnalogData4(7 downto 0)<= result(7 downto 0);
                                when        others => comdcount <= 0;
                                end case;
                                if (delaystate = '1')then
                                        comdcount <= comdcount + 1;
                                        comdstate1 <= '1';
                                        comdstate4 <= '0';
                                        count1 := 0;
                                end if;
                        elsif(comdstate1 = '1')then
                                temp_command(0) <= temp_data(count);
                                temp_command(1) <= '1';
                                comdstate1 <= '0';
                                comdstate2 <= '1';
                        elsif(delaystate1 = '1')then
                                temp_command(1) <= '0';
                                comdstate2 <= '0';
                                comdstate3 <= '1';
                                result(count) <= handdata;
                        elsif(delaystate2 = '1')then
                                --result(count) <= handdata;
                                comdstate3 <= '0';
                                count1 := count1 + 1;
                                if (count1 = 8)        then
                                        comdstate1 <= '0';
                                        comdstate4 <= '1';
                                        temp_command(1) <= '1';
                                        count <= 0;
                                else
                                        temp_command(1) <= '1';
                                        comdstate1 <= '1';
                                        count <= count1;
                                end if;
                        end if;
                end if;
        else
                comdcount <= 0;
                tempcount := 99999;
                comdstate1 <= '0';
                comdstate2 <= '0';
                comdstate3 <= '0';
                temp_command(1 downto 0) <= "11";
        end if;
end if;
end process;

--process(busclk,count,handdata)
--begin
--if(busclk'EVENT and busclk = '1')then
--        result(count) <= handdata;
--end if;
--end process;

process(busclk,comdstate2,comdstate3)
variable delaycount: integerrange 0 to 3999 := 499;
begin
        if(busclk'EVENT and busclk = '1')then
                if(comdstate4 = '1') then
                        delaycount := delaycount + 1;
                        if(delaycount = 2*divdelay - 1)then
                                delaystate <= '1';
                        elsif(delaycount = 2*divdelay)then
                                delaystate <= '0';
                                delaycount := 0;
                        end if;
                elsif(comdstate2 = '1') then
                        delaycount := delaycount + 1;
                        if(delaycount = divdelay-1)then
                                delaystate1 <= '1';
                        elsif(delaycount = divdelay)then
                                delaystate1 <= '0';
                                delaycount := 0;
                        end if;
                elsif(comdstate3 = '1') then
                        delaycount := delaycount + 1;
                        if(delaycount = divdelay-1)then
                                delaystate2 <= '1';
                        elsif(delaycount = divdelay )then
                                delaystate2 <= '0';
                                delaycount := 0;
                        end if;
                else
                        delaystate2 <= '0';
                        delaystate1 <= '0';
                        delaycount := 0;
                end if;
        end if;
end process;

end Behavioral;

liyang53719 发表于 2015-1-23 16:59:52

找到一个VHDL写的程序,看起来有些吃力,大家一起来分析分析

liyang53719 发表于 2015-1-23 17:41:51

本帖最后由 liyang53719 于 2015-1-23 22:50 编辑

经过测试这段程序完全可用!

//-------------------------------------------------------------------
//                                                         
// PLAYSTATION CONTROLLER(DUALSHOCK TYPE) INTERFACE TOP         
//                                                         
// Version : 2.00                                          
//                                                         
// Copyright(c) 2003 - 2004 Katsumi Degawa , All rights reserved
//                                                         
// Important !                                             
//                                                         
// This program is freeware for non-commercial use.         
// An author does no guarantee about this program.         
// You can use this under your own risk.                  
//
// 2003.10.30It is optimized . by K Degawa
//                                                      
//-------------------------------------------------------------------
`timescale 100ps/10ps               

//--------- SIMULATION ----------------------------------------------
//`define        SIMULATION_1       

`ifdef SIMULATION_1
`define Timer_siz 18
`else
`define Timer_siz 12
`endif
//-------------------------------------------------------------------
`define Dualshock

module psPAD_top(

I_CLK250K,       //MAIN CLK 250KHz
I_RSTn,          //MAIN RESET
O_psCLK,         //psCLK CLK OUT
O_psSEL,         //psSEL OUT      
O_psTXD,         //psTXD OUT
I_psRXD,         //psRXD IN
O_RXD_1,         //RX DATA 1 (8bit)
O_RXD_2,         //RX DATA 2 (8bit)
O_RXD_3,         //RX DATA 3 (8bit)
O_RXD_4,         //RX DATA 4 (8bit)
O_RXD_5,         //RX DATA 5 (8bit)
O_RXD_6,         //RX DATA 6 (8bit)
I_CONF_SW,       //Dualshook ConfigACTIVE-HI
I_MODE_SW,       //Dualshook Mode Set DEGITAL PAD 0: ANALOG PAD 1:
I_MODE_EN,       //Dualshook Mode ControlOFF 0: ON 1:
I_VIB_SW,      //Vibration SWVIB_SW Small Moter OFF 0:ON1:
               //                VIB_SW Bic Moter   OFF 0:ON1(Dualshook Only)
I_VIB_DAT      //Vibration(Bic Moter)Data   8'H00-8'HFF (Dualshook Only)

);

inputI_CLK250K,I_RSTn;
inputI_CONF_SW;
inputI_MODE_SW,I_MODE_EN;
inputI_VIB_SW;
inputI_VIB_DAT;
inputI_psRXD;
output O_psCLK;
output O_psSEL;
output O_psTXD;
output O_RXD_1;
output O_RXD_2;
output O_RXD_3;
output O_RXD_4;
output O_RXD_5;
output O_RXD_6;

wire   W_scan_seq_pls;
wire   W_type;
wire   W_byte_cnt;
wire   W_RXWT;
wire   W_TXWT;
wire   W_TXSET;
wire   W_TXEN;
wire   W_TXD_DAT;
wire   W_RXD_DAT;
wire   W_conf_ent;

ps_pls_gan pls(

.I_CLK(I_CLK250K),
.I_RSTn(I_RSTn),
.I_TYPE(W_type),            // DEGITAL PAD 0: ANALOG PAD 1:

.O_SCAN_SEQ_PLS(W_scan_seq_pls),
.O_RXWT(W_RXWT),
.O_TXWT(W_TXWT),
.O_TXSET(W_TXSET),
.O_TXEN(W_TXEN),
.O_psCLK(O_psCLK),
.O_psSEL(O_psSEL),
.O_byte_cnt(W_byte_cnt),

//.Timer(O_Timer)
.Timer()

);

`ifdef Dualshock
txd_commnd cmd(

.I_CLK(W_TXSET),
.I_RSTn(I_RSTn),
.I_BYTE_CNT(W_byte_cnt),
.I_MODE({I_CONF_SW,~I_MODE_EN,I_MODE_SW}),
.I_VIB_SW(I_VIB_SW),
.I_VIB_DAT(I_VIB_DAT),
.I_RXD_DAT(W_RXD_DAT),
.O_TXD_DAT(W_TXD_DAT),
.O_TYPE(W_type),
.O_CONF_ENT(W_conf_ent)

);

`else
txd_commnd_EZ cmd(

.I_CLK(W_TXSET),
.I_RSTn(I_RSTn),
.I_BYTE_CNT(W_byte_cnt),
.I_MODE(),
.I_VIB_SW(I_VIB_SW),
.I_VIB_DAT(),
.I_RXD_DAT(),
.O_TXD_DAT(W_TXD_DAT),
.O_TYPE(W_type),
.O_CONF_ENT(W_conf_ent)

);

`endif

ps_txd txd(

.I_CLK(I_CLK250K),
.I_RSTn(I_RSTn),
.I_WT(W_TXWT),
.I_EN(W_TXEN),
.I_TXD_DAT(W_TXD_DAT),
.O_psTXD(O_psTXD)

);

ps_rxd rxd(

.I_CLK(O_psCLK),
.I_RSTn(I_RSTn),       
.I_WT(W_RXWT),
.I_psRXD(I_psRXD),
.O_RXD_DAT(W_RXD_DAT)

);

//----------   RXD DATA DEC----------------------------------------
reg    O_RXD_1;
reg    O_RXD_2;
reg    O_RXD_3;
reg    O_RXD_4;
reg    O_RXD_5;
reg    O_RXD_6;

reg   W_rxd_mask;
always@(posedge W_scan_seq_pls)
   W_rxd_mask <= ~W_conf_ent;

always@(negedge W_RXWT)
begin
   if(W_rxd_mask)begin
      case(W_byte_cnt)
            3: O_RXD_1 <= W_RXD_DAT;
            4: O_RXD_2 <= W_RXD_DAT;
            5: O_RXD_3 <= W_RXD_DAT;
            6: O_RXD_4 <= W_RXD_DAT;
            7: O_RXD_5 <= W_RXD_DAT;
            8: O_RXD_6 <= W_RXD_DAT;
       default:;
      endcase
   end
end

endmodule

`ifdef Dualshock
module txd_commnd_EZ(

I_CLK,
I_RSTn,
I_BYTE_CNT,
I_MODE,
I_VIB_SW,
I_VIB_DAT,
I_RXD_DAT,
O_TXD_DAT,
O_TYPE,
O_CONF_ENT

);

inputI_CLK,I_RSTn;
inputI_BYTE_CNT;
inputI_MODE;
inputI_VIB_SW;
inputI_VIB_DAT;
inputI_RXD_DAT;
output O_TXD_DAT;
output O_TYPE;
output O_CONF_ENT;

reg    O_TXD_DAT;

assign O_TYPE = 1'b1;
assign O_CONF_ENT = 1'b0;
always@(posedge I_CLK or negedge I_RSTn)
begin
   if(! I_RSTn)begin
      O_TXD_DAT <= 8'h00;
   end
   else begin
      case(I_BYTE_CNT)
         0:O_TXD_DAT <= 8'h01;
         1:O_TXD_DAT <= 8'h42;
         3:begin
            if(I_VIB_SW) O_TXD_DAT <= 8'h40;
            else         O_TXD_DAT <= 8'h00;
         end
         4:begin
            if(I_VIB_SW) O_TXD_DAT <= 8'h01;
            else         O_TXD_DAT <= 8'h00;
         end
       default: O_TXD_DAT <= 8'h00;
      endcase
   end
end

endmodule
`endif

module txd_commnd(

I_CLK,
I_RSTn,
I_BYTE_CNT,
I_MODE,
I_VIB_SW,
I_VIB_DAT,
I_RXD_DAT,
O_TXD_DAT,
O_TYPE,
O_CONF_ENT

);

inputI_CLK,I_RSTn;
inputI_BYTE_CNT;
inputI_MODE;
inputI_VIB_SW;
inputI_VIB_DAT;
inputI_RXD_DAT;
output O_TXD_DAT;
output O_TYPE;
output O_CONF_ENT;

wire   pad_mode = I_MODE;
wire   ds_sw= I_MODE;

reg    O_TXD_DAT;
reg    conf_state;
reg    conf_entry;
reg    conf_ent_reg;
reg    conf_done;
reg    pad_status;
reg    pad_id;

assign O_TYPE = pad_id;
assign O_CONF_ENT = conf_entry;

always@(posedge I_CLK or negedge I_RSTn)
begin
   if(! I_RSTn)    pad_id <= 1'b0;
   else begin
      if(I_BYTE_CNT==2)begin
         case(I_RXD_DAT) //------GET TYPE(Byte_SEQ)
            8'h23: pad_id <= 1'b1;
            8'h41: pad_id <= 1'b0;
            8'h53: pad_id <= 1'b1;
            8'h73: pad_id <= 1'b1;
            8'hE3: pad_id <= 1'b1;
            8'hF3: pad_id <= 1'b1;
          default: pad_id <= 1'b0;
         endcase
      end
   end
end

always@(posedge I_CLK or negedge I_RSTn)
begin
   if(! I_RSTn)begin
      O_TXD_DAT    <= 8'h00;
      conf_entry   <= 1'b0;
      conf_ent_reg <= 1'b0;
          conf_done    <= 1'b1;
      conf_state   <= 0;
      pad_status   <= 0;      
   end
   else begin
//---------- nomal mode --------------------------------------------------------
//----------------- read_data_and_vibrate_ex    01,42,00,WW,PP(,00,00,00,00)
//                                              --,ID,SS,XX,XX(,XX,XX,XX,XX)
      if(~conf_entry)begin
         case(I_BYTE_CNT)
            0:O_TXD_DAT <= 8'h01;
            1:O_TXD_DAT <= 8'h42;
            3:begin
            if(I_RXD_DAT==8'h00) conf_ent_reg <= 1'b1;
               if(pad_status)begin
                  if(I_VIB_SW) O_TXD_DAT <= 8'h01;
                  else            O_TXD_DAT <= 8'h00;
               end
                             else begin
                  if(I_VIB_SW | I_VIB_SW) O_TXD_DAT <= 8'h40;
                  else            O_TXD_DAT <= 8'h00;                                
               end
            end
            4:begin
               if(pad_status)begin
                  if(I_VIB_SW) O_TXD_DAT <= I_VIB_DAT;
                  else            O_TXD_DAT <= 8'h00;
               end
                             else begin
                  if(I_VIB_SW | I_VIB_SW) O_TXD_DAT <= 8'h01;
                  else            O_TXD_DAT <= 8'h00;                                
               end
                             if(pad_id==0)begin
                  if(conf_state == 0 && ds_sw)
                     conf_entry <= 1'b1;
                  if(conf_state == 7 && (pad_status&conf_ent_reg))begin
                     conf_state <= 0;
                     conf_entry <= 1'b1;
                  end
               end
            end
            8:begin
               O_TXD_DAT <= 8'h00;
               if(pad_id==1)begin
                  if(conf_state == 0 && ds_sw)
                     conf_entry <= 1'b1;
                  if(conf_state == 7 && (pad_status&conf_ent_reg))begin
                     conf_state <= 0;
                     conf_entry <= 1'b1;
                  end
               end
            end      
         default: O_TXD_DAT <= 8'h00;
         endcase
      end
//---------- confg mode --------------------------------------------------------
      else begin
         case(conf_state)
         //-------- config_mode_enter (43):   01,43,00,01,00(,00 x 4 or XX x 16)
         //                                     --,ID,SS,XX,XX(,XX x 4 or XX x 16)
            0:begin
               case(I_BYTE_CNT)
                  0:begin
                         O_TXD_DAT <= 8'h01;
                         conf_done <= 1'b0;
                      end
                  1:O_TXD_DAT <= 8'h43;
                  3:O_TXD_DAT <= 8'h01;
                  4:begin
                         O_TXD_DAT <= 8'h00;
                         if(pad_id==0)begin
                            if(pad_status) conf_state <= 3;
                            else         conf_state <= 1;   
                         end
                      end
                  8:begin
                         O_TXD_DAT <= 8'h00;
                         if(pad_id==1)begin
                            if(pad_status) conf_state <= 3;
                            else         conf_state <= 1;   
                         end
                      end                                                                                                                                
                  default:O_TXD_DAT <= 8'h00;
               endcase
            end
         //-------- query_model_and_mode (45):01,45,00,5A,5A,5A,5A,5A,5A
         //                                     FF,F3,5A,TT,02,MM,VV,01,00
            1:begin
               case(I_BYTE_CNT)
                  0:O_TXD_DAT <= 8'h01;
                  1:O_TXD_DAT <= 8'h45;
                  2:begin
                         O_TXD_DAT <= 8'h00;
                         conf_done <= (I_RXD_DAT == 8'hF3)? 1'b0:1'b1;
                      end
                  4:begin
                         O_TXD_DAT <= 8'h00;
                         if(I_RXD_DAT==8'h01 || I_RXD_DAT==8'h03) pad_status <= 1;
                         if(pad_id==0 && conf_done==1'b1)begin
                            conf_state <= 7;
                            conf_entry <= 1'b0;
                         end
                      end
                  8:begin
                         O_TXD_DAT <= 8'h00;
                         conf_state <= 2;
                         if(pad_id==1 && conf_done==1'b1)begin
                            conf_state <= 7;
                            conf_entry <= 1'b0;
                         end                              
                      end                                                                                                         
                  default:O_TXD_DAT <= 8'h00;
               endcase
            end
         //-------- set_mode_and_lock (44):   01,44,00,XX,YY,00,00,00,00
         //                                     --,F3,5A,00,00,00,00,00,00
            2:begin
               case(I_BYTE_CNT)
                  0:O_TXD_DAT <= 8'h01;
                  1:O_TXD_DAT <= 8'h44;
                  3:O_TXD_DAT <= pad_mode ? 8'h01:8'h00;
                  4:O_TXD_DAT <= pad_mode ? 8'h03:8'h00;
                  8:begin
                         O_TXD_DAT <= 8'h00;
                         conf_state<= 3;
                      end
                  default:O_TXD_DAT <= 8'h00;
               endcase
            end
         //-------- vibration_enable (4D):      01,4D,00,00,01,FF,FF,FF,FF
         //                                     --,F3,5A,XX,YY,FF,FF,FF,FF
            3:begin
               case(I_BYTE_CNT)
                  0:O_TXD_DAT <= 8'h01;
                  1:O_TXD_DAT <= 8'h4D;
                  2,3:O_TXD_DAT <= 8'h00;
                  4:O_TXD_DAT <= 8'h01;
                  8:begin
                         O_TXD_DAT <= 8'hFF;
                         conf_state<= 6;
                      end
                  default:O_TXD_DAT <= 8'hFF;
               endcase
            end
         //-------- config_mode_exit (43):      01,43,00,00,5A,5A,5A,5A,5A
         //                                     --,F3,5A,00,00,00,00,00,00
            6:begin
               case(I_BYTE_CNT)
                  0:O_TXD_DAT <= 8'h01;
                  1:O_TXD_DAT <= 8'h43;
                  2,3:O_TXD_DAT <= 8'h00;
                  8:begin
                         O_TXD_DAT <= 8'h5A;
                         conf_state<= 7;
                         conf_entry<= 1'b0;
                         conf_done <= 1'b1;
                         conf_ent_reg<= 1'b0;                                                
                     end
                  default:O_TXD_DAT <= 8'h5A;
               endcase
            end
          default:;
         endcase
      end
   end
end

endmodule

module ps_pls_gan(

I_CLK,
I_RSTn,
I_TYPE,

O_SCAN_SEQ_PLS,
O_RXWT,
O_TXWT,
O_TXSET,
O_TXEN,
O_psCLK,
O_psSEL,
O_byte_cnt,

Timer

);

parameter Timer_size = `Timer_siz;

inputI_CLK,I_RSTn;
inputI_TYPE;
output O_SCAN_SEQ_PLS;
output O_RXWT;
output O_TXWT;
output O_TXSET;
output O_TXEN;
output O_psCLK;
output O_psSEL;
output O_byte_cnt;

output Timer;
reg    Timer;

reg    O_SCAN_SEQ_PLS;
reg    RXWT;
reg    TXWT;
reg    TXSET;
reg    psCLK_gate;
reg    psSEL;
reg    O_byte_cnt;

always@(posedge I_CLK or negedge I_RSTn)
begin
   if(! I_RSTn) Timer <= 0;
   else         Timer <= Timer+1;
end

always@(posedge I_CLK or negedge I_RSTn)
begin
   if(! I_RSTn)
      O_SCAN_SEQ_PLS <= 0;
   else begin
      if(Timer == 0) O_SCAN_SEQ_PLS <= 1;
          else         O_SCAN_SEQ_PLS <= 0;            
   end
end

always@(posedge I_CLK or negedge I_RSTn)
begin
   if(! I_RSTn)
   begin
      psCLK_gate <= 1;
      RXWT   <= 0;
          TXWT   <= 0;
          TXSET    <= 0;
   end
   else begin
      case(Timer)
          6: TXSET <= 1;
          8: TXSET <= 0;
          9: TXWT <= 1;
         11: TXWT <= 0;
         12: psCLK_gate <= 0;
         20: psCLK_gate <= 1;
         21: RXWT <= 1;
         23: RXWT <= 0;
      default:;
      endcase
   end
end

always@(posedge I_CLK or negedge I_RSTn)
begin
   if(! I_RSTn)
      psSEL <= 1;
   else begin       
      if(O_SCAN_SEQ_PLS == 1)
         psSEL <= 0;
      else if((I_TYPE == 0)&&(Timer == 158))
         psSEL <= 1;
      else if((I_TYPE == 1)&&(Timer == 286))
         psSEL <= 1;
   end
end

always@(posedge I_CLK or negedge I_RSTn)
begin
   if(! I_RSTn)
      O_byte_cnt <= 0;
   else begin
      if( O_SCAN_SEQ_PLS == 1)
         O_byte_cnt <= 0;
      else begin
         if( Timer == 5'b11111)begin
            if(I_TYPE == 0 && O_byte_cnt == 5)
               O_byte_cnt <= O_byte_cnt;
            else if(I_TYPE == 1 && O_byte_cnt == 9)
               O_byte_cnt <= O_byte_cnt;
            else
               O_byte_cnt <= O_byte_cnt+1;
         end   
      end
   end
end

assign O_psCLK = psCLK_gate | I_CLK | psSEL;
assign O_psSEL = psSEL;
assign O_RXWT= ~psSEL&RXWT;
assign O_TXSET = ~psSEL&TXSET;
assign O_TXWT= ~psSEL&TXWT;
assign O_TXEN= ~psSEL&(~psCLK_gate);

endmodule

module ps_rxd(

I_CLK,
I_RSTn,       
I_WT,
I_psRXD,
O_RXD_DAT

);

input        I_CLK,I_RSTn,I_WT;
input        I_psRXD;
output        O_RXD_DAT;
reg   O_RXD_DAT;
reg   sp;

always@(posedge I_CLK or negedge I_RSTn)
   if(! I_RSTn) sp <= 1;
   else         sp <= { I_psRXD, sp};
always@(posedge I_WT or negedge I_RSTn)
   if(! I_RSTn) O_RXD_DAT <= 1;
   else         O_RXD_DAT <= sp;

endmodule

module ps_txd(

I_CLK,
I_RSTn,
I_WT,
I_EN,
I_TXD_DAT,
O_psTXD

);

input        I_CLK,I_RSTn;
input        I_WT,I_EN;
input        I_TXD_DAT;
output        O_psTXD;
reg   O_psTXD;
reg   ps;

always@(negedge I_CLK or negedge I_RSTn)
begin
   if(! I_RSTn)begin
      O_psTXD <= 1;
      ps      <= 0;
   end
   else begin
      if(I_WT)
         ps<= I_TXD_DAT;
      else begin
         if(I_EN)begin
            O_psTXD <= ps;
            ps      <= {1'b1, ps};
         end
         else begin
            O_psTXD <= 1'd1;
            ps<= ps;
         end
      end
   end        
end

endmodule

liyang53719 发表于 2015-1-23 17:44:00

这是刚找到的另一个verilog的代码,光看引脚名称感觉这个更靠谱一点。这个应该是最核心的模块,我们分析分析吧!

steinwai 发表于 2015-3-11 19:25:33

liyang53719 发表于 2015-1-23 17:41
经过测试这段程序完全可用!

楼主,这个可以直接用吗,ps手柄与开发板如何连接呢,能详细说说具体测试过程吗,{:loveliness:} 测试结果如何呢

funnybow 发表于 2015-3-11 22:45:54

PS2手柄的接口比SPI多了一个ACK线,用SPI在加一根ACK线就可以了,具体的协议可以公布吗,我不知道啊

liyang53719 发表于 2015-3-14 21:15:36

steinwai 发表于 2015-3-11 19:25
楼主,这个可以直接用吗,ps手柄与开发板如何连接呢,能详细说说具体测试过程吗, 测试结 ...

可以直接用 具体接口网上应该有 我现在不在学校了 东西都不在了

liyang53719 发表于 2015-3-14 21:16:09

funnybow 发表于 2015-3-11 22:45
PS2手柄的接口比SPI多了一个ACK线,用SPI在加一根ACK线就可以了,具体的协议可以公布吗,我不知道啊 ...

网上可以搜到,搜PSX试试

steinwai 发表于 2015-3-15 22:50:17

liyang53719 发表于 2015-3-14 21:15
可以直接用 具体接口网上应该有 我现在不在学校了 东西都不在了

已经搜了好几天了,各种实在是搜不到{:cry:} ,lz能给点线索吗,提示一下关键字也行啊

liyang53719 发表于 2015-3-15 22:57:50

steinwai 发表于 2015-3-15 22:50
已经搜了好几天了,各种实在是搜不到 ,lz能给点线索吗,提示一下关键字也行啊 ...

PS2 PSX 接口时序 通信协议 之类的你试试。我记得有个英文的最全

funnybow 发表于 2015-3-16 21:16:44

steinwai 发表于 2015-3-15 22:50
已经搜了好几天了,各种实在是搜不到 ,lz能给点线索吗,提示一下关键字也行啊 ...

看这个
http://www.amobbs.com/thread-947324-1-1.html

steinwai 发表于 2015-3-16 23:39:06

十三楼的那几个IO和手柄的管脚如何对应呢?名字都不一样看起来好费力

liyang53719 发表于 2015-3-18 15:23:52

steinwai 发表于 2015-3-16 23:39
十三楼的那几个IO和手柄的管脚如何对应呢?名字都不一样看起来好费力

DATA        -to I_psRXD
CLK                -to O_psCLK
COMMAND        -to O_psTXD
ATT                -to O_psSEL
原来的资料找不到了。这是我之前做的笔记。你们看看能否有帮助

steinwai 发表于 2015-3-18 23:12:37

本帖最后由 steinwai 于 2015-3-19 20:30 编辑

补充:用之前还得先分个250k的频给I_CLK250K

steinwai 发表于 2015-3-19 20:28:14

找到了完整的工程文件,来分享一下{:smile:}{:victory:}

steinwai 发表于 2015-3-20 20:36:20

att command clk 在示波器中显示都好,但data在按键时完全没图像

liyang53719 发表于 2015-3-20 23:59:09

steinwai 发表于 2015-3-20 20:36
att command clk 在示波器中显示都好,但data在按键时完全没图像

有红灯模式绿灯模式,你按一下mode键试试,或者动摇干

steinwai 发表于 2015-4-3 21:07:09

lz能否共享一下你的工程呢?搞了好久都没成功{:sleepy:}{:cry:}

steinwai 发表于 2015-4-5 10:28:39

lz请求帮助,please{:3_60:}

liyang53719 发表于 2015-4-5 11:03:19

steinwai 发表于 2015-4-5 10:28
lz请求帮助,please

工程原文件都在学校了没带出来。我现在也只有13楼那个代码。
你先搞清楚PS2接口的定义,就是名字。然后用RTL视图找代码接口。
按照下面这种方法接
DATA      -to I_psRXD
CLK                -to O_psCLK
COMMAND      -to O_psTXD
ATT                -to O_psSEL
还有你需要给代码一个时钟信号,具体数值我忘了,10M,50M你都试一下。
手柄和FPGA接好之后,打开signaltap II监测每个输出引脚电平变化。然后上电。你要做的就是按下手柄上的一个键去Signaltap II里找电平变化的对应脚。高变低还是低变高我也忘了。总之会有变化(注意采样深度太大可能会有延时)。如果没反应,按下mode键再试,或者按两次再试。找到按键和对应脚记下来。将来可以做个顶层打包的东西用。
过程大概就是这样。这个代码是没问题的,我也抱着怀疑的心态试了很久。但是是可以用的。你要工程的话我这里是没有了,现在也没时间再弄这个了。
希望可以帮到你。

steinwai 发表于 2015-4-5 11:08:39

I_CLK250K,       //MAIN CLK 250KH这句不是表示需要一个250khz的时钟给顶层吗,于是我就先写了个分频器给他,是直接用板子的50m时钟就好了 吗{:3_49:}

steinwai 发表于 2015-4-5 11:35:32

非常感谢lz耐心指教

steinwai 发表于 2015-4-5 15:37:50

看了一篇文章解释的data与按键对应,还想再请教一下,如何在signaltap中让时间轴变长一点呢?得到第4和5byte才能判断按键呐{:3_57:}

steinwai 发表于 2015-4-5 15:42:27

我的系统时钟是50m的,不会分10m,于是只好对半分了,也就是25m

liyang53719 发表于 2015-4-5 22:28:03

steinwai 发表于 2015-4-5 11:08
I_CLK250K,       //MAIN CLK 250KH这句不是表示需要一个250khz的时钟给顶层吗,于是我就先写了个分频器 ...

分个频是对的,可能是我记错了

liyang53719 发表于 2015-4-5 22:29:52

steinwai 发表于 2015-4-5 15:37
看了一篇文章解释的data与按键对应,还想再请教一下,如何在signaltap中让时间轴变长一点呢?得到第4和5byt ...

让时间轴变长一点
这个没理解

steinwai 发表于 2015-4-6 16:05:02

liyang53719 发表于 2015-4-5 22:29
让时间轴变长一点
这个没理解

就是想让波形多显示一点,

steinwai 发表于 2015-4-6 19:16:11

不然图像太短了显示不到第4,5个byte

liyang53719 发表于 2015-4-6 21:14:49

steinwai 发表于 2015-4-6 19:16
不然图像太短了显示不到第4,5个byte

采样深度大一点。改成2k或以上试试

steinwai 发表于 2015-4-11 19:22:46

liyang53719 发表于 2015-4-6 21:14
采样深度大一点。改成2k或以上试试

4k都显示不到第四个byte,8k就没反应了{:3_60:}

liyang53719 发表于 2015-4-11 19:57:58

steinwai 发表于 2015-4-11 19:22
4k都显示不到第四个byte,8k就没反应了

8k好像因为采集的点太多,没法实时显示你可以采集一会停止应该就有了。但是明显不应该是8k这么大的。你可以试试换个采样时钟。用O_psCLK做采样时钟。或者自己分个频。25M、10M、1M的试一下。

steinwai 发表于 2015-4-14 19:50:37

直接接在板子的extra pin上面就可以了吗,对io的类型有要求吗?

steinwai 发表于 2015-4-14 20:37:51

终于可以显示完5个byte了,可是按键后没看出data有变化呢
页: [1]
查看完整版本: 想用FPGA读PS2手柄,用串口模块改装是否可行?