Usando el puerto PS/2 del Papilio One FPGA desde VHDL

Estoy tratando de recibir datos de un teclado a través del puerto PS/2 en Papilio One Arcade Megawing. Eventualmente, querré implementar esto desde cero, pero pensé que primero haría funcionar un código público como una forma de prueba de humo.

Las tres fuentes con las que jugué fueron

He modificado cada uno cambiando el archivo UCF a

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;

y conduzco LED1directamente desde PS2_Clk, LED2desde PS2_Datay LED3desde un registro que debe ir de menor a mayor (y permanecer alto) cuando se lee el primer código de escaneo completo.

El problema es que, con las tres implementaciones, lo que obtengo es

  • LED1y LED2están continuamente en
  • LED3nunca enciende

El teclado que estoy usando es un Microsoft Natural Keyboard 4000 a través de un dongle USB a PS/2. El LED de bloqueo de teclas de función en el teclado se enciende cuando lo conecto al Papilio, así que al menos sé que está funcionando.

Los volcados completos del proyecto ISE de Xilinx están disponibles en http://forum.gadgetfactory.net/index.php?/topic/1917-ps2-ports-on-arcade-megawing/

@Leor mencionó a continuación que el puerto PS/2 usa una frecuencia de reloj de 10 KHz. ¿Eso no significa que debería ver un LED parpadeante (con una frecuencia de aproximadamente 1,6 segundos) con el siguiente código:

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;

Porque si pruebo esto, el LED sigue encendido continuamente.

Actualicé mi código para que el LED se active desde un pestillo que se voltea cada vez que el contador llega a 0. Todavía está siempre encendido para mí.
La página en papilio.cc/index.php?n=Papilio.ArcadeMegaWing enumera los pines del reloj PS/2 como pines de salida ... lo que me confunde aún más.

Respuestas (2)

PS/2 utiliza un reloj de 10 KHz, por lo que conectar un LED al reloj oa las líneas de datos hará que el LED aparezca siempre encendido con un brillo correspondiente al ciclo de trabajo de la señal.

¿Ha intentado simular el código de ejemplo con el simulador ISE? Eso al menos le diría que el reloj y las salidas de datos están haciendo algo sensato.

Actualizar si estoy entendiendo el segundo código correctamente:

La señal CLK es un reloj de 32 MHz. La señal PS2_CLK es de 10 KHz (PS2 permite entre 10 y 16 KHz aparentemente, ¿sabes exactamente qué es esta señal?) que se genera... en alguna parte?

El segundo fragmento de código que publicaste va a:

  1. Inicia el contador en 0, PS2_CLK_PREV en 1
  2. En cada flanco ascendente de CLK (es decir, a 32 MHz), el proceso se ejecutará

El proceso que ha definido incrementará el contador cada vez que cambie PS2_CLK.

Por lo tanto, el contador se incrementará una vez por cada transición de reloj positiva y negativa en PS2_CLK (es decir, a 20 KHz).

El contador se incrementará hasta que se desborde y vuelva a 0. Como son 14 bits, eso significa que tomará 16384 incrementos, que a una tasa de incremento de 20 KHz (dos veces por ciclo de reloj) es de 0,819 segundos.

Su LED es solo 1 cuando el contador es 0, lo que sucederá durante 5 uS cada 0.819 segundos. Eso no es lo suficientemente largo para que note que está encendido, por lo que el LED es esencialmente 0.

Si el LED parece estar constantemente encendido, significa que el contador está constantemente en 0. Eso sugiere que PS2_CLK siempre es igual a PS2_CLK_PREV, lo que sugiere que quizás su PS2_CLK no esté haciendo nada. Sugeriría mirar qué está impulsando esa señal de reloj (¿es un DCM que ha instanciado? ¿Un simple divisor de reloj?)

La mención de un reloj de 10KHz me dio una idea; ver mi pregunta editada. Todavía no veo parpadear en el LED.
¿El reloj de tu PS2 de 10 KHz es el mismo que tu CLK lógico? La mayoría de la lógica FPGA se ejecuta a velocidades de reloj de 10 a 100 MHz, lo que daría como resultado que el temporizador se detuviera en menos de un milisegundo. Me sorprendería si su lógica tiene un reloj de 10 MHz (a menos que esté vinculando específicamente la lógica a ese reloj), ya que habrá muchas otras cosas que deben suceder antes y después de la transmisión de datos.
Dicho esto, el LED debería aparecer apagado si el código anterior funciona correctamente. Creo que hay otro problema en alguna parte. ¿Ha escrito, sintetizado y cargado con éxito código funcional para hacer algo simple, tal vez hacer que un LED parpadee?
Pero solo disminuyo el contador cuando cambia la señal PS2_CLK. Estoy muestreando la señal de 10 KHz a 32 MHz, al menos eso es lo que pensaba.
sobre la prueba de humo de la placa en sí: las cosas en general funcionan en la misma placa, por ejemplo, acabo de escribir y cargar en ella una pequeña configuración que usa los cuatro botones a través de un antirrebote suave para alternar los cuatro LED. Yo diría que eso prueba que el reloj y los LED funcionan. También he generado con éxito una señal VGA en la misma placa antes.
He agregado algunos comentarios a mi respuesta con respecto a su segundo código.
Pensé que el teclado generaría el reloj ps2. ¿No es este el caso?
Hmm, ahora veo por qué el LED solo sería 1 por un pequeño tiempo cuando el contador es exactamente 0 ... lo que realmente quería hacer era tener un registro de un bit que volteé cada vez que el contador es 0. Arreglaré mi programa y prueba eso.
Tienes razón: el dispositivo genera la señal del reloj. No estoy familiarizado con PS/2.
La descripción del protocolo aquí: computer-engineering.org/ps2protocol sugiere que el reloj está alto cuando no hay comunicación gracias a una resistencia pullup. ¿Tiene pullups en sus líneas de datos? Hay tantas variables que es difícil señalar un solo problema. Sugeriría comprar un analizador lógico barato (los clones baratos de Saleae cuestan alrededor de $ 10) o un alcance para que actúe como un control de cordura.

Resultó que el problema era la combinación del teclado Microsoft Natural 4000 que estaba usando para las pruebas y el dongle USB a PS/2. Después de obtener un teclado PS/2 adecuado, las configuraciones de prueba funcionan como se esperaba.

No estoy seguro de si debo aceptar esta respuesta mía o eliminar mi pregunta original... Creo que aceptaré esta respuesta ya que alguien más podría encontrarse en la misma situación con un teclado más nuevo.