Electronic – Using the PS/2 port of the Papilio One FPGA from VHDL

fpgaps2vhdlxilinx

I'm trying to receive data from a keyboard via the PS/2 port on the Papilio One Arcade Megawing. Eventually I'll want to implement this from scratch, but I thought I'd get some public code working first as a form of smoke-test.

The three sources I played with were

I've modified each by changing the UCF file to

NET "Clk"      LOC="P89"  | IOSTANDARD = LVCMOS25 | PERIOD=31.25ns;
NET "Reset"    LOC="P67"  | IOSTANDARD=LVTTL | PULLDOWN;
NET "PS2_Clk"  LOC="P91"  | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP;
NET "PS2_Data" LOC="P92"  | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP;
NET "LED1"     LOC="P57"  | IOSTANDARD=LVTTL;
NET "LED2"     LOC="P53"  | IOSTANDARD=LVTTL;
NET "LED3"     LOC="P40"  | IOSTANDARD=LVTTL;

and I'm driving LED1 straight from PS2_Clk, LED2 from PS2_Data and LED3 from a register that should go from low to high (and stay high) when the first complete scancode is read.

The problem is, with all three implementations, what I get instead is

  • LED1 and LED2 are continuously on
  • LED3 never turns on

The keyboard I'm using is a Microsoft Natural Keyboard 4000 via a USB-to-PS/2 dongle. The function key lock LED on the keyboard lights up when I connect it to the Papilio so at least I know it's getting juice.

Full Xilinx ISE project dumps are available at http://forum.gadgetfactory.net/index.php?/topic/1917-ps2-ports-on-arcade-megawing/

@Leor mentioned below that the PS/2 port uses a clock frequency of 10 KHz. Does n't that mean that I should see a blinking LED (with about 1.6 second frequency) with the following code:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity main is
    Port ( CLK : in  STD_LOGIC;
           PS2_CLK : in  STD_LOGIC;
           LED : out  STD_LOGIC);
end main;

architecture Behavioral of main is
signal counter: unsigned(13 downto 0) := (others => '0');
signal PS2_CLK_PREV : std_logic := '1';
signal LED_clamped : std_logic := '0';
begin
LED <= LED_clamped;
process(CLK) is
begin
  if rising_edge(CLK) then
    if not (PS2_CLK = PS2_CLK_PREV) then
      counter <= counter + 1;
    end if;

    if counter = 0 then
      LED_clamped <= not LED_clamped;
    end if;

    PS2_CLK_PREV <= PS2_CLK;
  end if;
end process;

end Behavioral;

Because if I try this, the LED is still continuously on.

Best Answer

PS/2 uses a 10 KHz clock, so connecting an LED to the clock or data lines will just result in the LED appearing always on at a brightness corresponding to the signal duty cycle.

Have you tried simulating the example code with the ISE simulator? That would at least tell you that the clock and data outputs are doing something sensible.

Update If I'm understanding the second code correctly:

The CLK signal is a 32 MHz clock The PS2_CLK signal is a 10 KHz (PS2 allows between 10 and 16 KHz apparently - do you know exactly what this signal is?) which is generated... somewhere?

The second piece of code you posted is going to:

  1. Initiate the counter at 0, PS2_CLK_PREV at 1
  2. On every CLK rising edge (ie at 32 MHz), the process will run

The process you've defined will increment the counter whenever PS2_CLK has changed.

So the counter will be incremented once for every positive and negative clock transition on PS2_CLK (ie at 20 KHz).

The counter will increment until it overflows and goes back to 0. As it's 14 bits, that means it will take 16384 increments, which at 20 KHz increment rate (twice per clock cycle) is 0.819 seconds.

Your LED is only 1 when the counter is 0, which will happen for 5 uS every 0.819 seconds. That's not long enough for you to notice it turned on, and so the LED is essentially 0.

If the LED is appearing to be constantly turned on, it means that the counter is constantly at 0. That suggests that PS2_CLK always equals PS2_CLK_PREV, which suggests that perhaps your PS2_CLK isn't doing anything. I'd suggest looking at what's driving that clock signal (is it a DCM that you've instantiated? A simple clock divider?)