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
- http://soclab.cn.nctu.edu.tw/course/FPGA102/ps2_ctrl.pdf
- http://hamsterworks.co.nz/mediawiki/index.php/Papilio_Plus/PS2_Keyboard
- https://github.com/thelonious/ps2_io/tree/master/keyboard_scan_code
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
andLED2
are continuously onLED3
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:
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?)