Autor Tema: BUS LPC (Low Pin Count)  (Leído 6602 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado cmr1108

  • PIC10
  • *
  • Mensajes: 5
BUS LPC (Low Pin Count)
« en: 17 de Noviembre de 2009, 09:18:23 »
Hola a tod@s

Estoy intentando diseñar un interface de entradas y salidas en VHDL para una XC95144XL controlada por el bus LPC del PC
, antiguo bus ISA.
Para el que no sepa de que hablo le paso estos dos links.

http://en.wikipedia.org/wiki/Low_Pin_Count
http://www.intel.com/design/chipsets/industry/25128901.pdf


El caso es que buscando por la red encontre un ejemplo en varias páginas para monitorizar el puerto 80H y lo implemente y funciona.
Más tarde hice un pequeño programa en vB que, mediante unos botones, activar salidas de la CPLD y funciona tanto en la dirección 37FH como en cualquier otra dirección de I/O del PC, siempre y cuando el la CPLD este programada la misma dirección.

En cambio para leer entradas me encuentro encayado, ya que el bus con el que se comunican PC y CPLD es bidireccional y en el momento en que se escribe sobre el, dejan de funcionar las salidas.

El codigo de ejemplo que monitoriza el puerto 80H es el siguiente:





----------------------------------------------------------------------------------
-- IO80 catcher for LPC bus.
-- File: LPC_IOW80_1.1.VHD
-- Revision: 1.1
-- Author: Eric Leonard (partially based on Nicolas Gonthier's T3001)
-- Subsequent modifications by:
-- Detlef Herbst and Travis Evans - 08/10/05
-- Decode only I/O writes to 80h
-- Features:
-- - I/O 80 access only (internally decoded)
-- - No support for read, only write.
-- - All signals synchronous to LPC clock
-- Notes:
-- - Unless otherwise noted, all signals are active high.
-- - Suffix "n" indicate active low logic.
--
-- - Successfully implemented on Brownsville baseboard with Seven Segment
-- - display P/N SA39-11 (common Anode - Low turns on segment) from Kingbright
-- Related documents:
-- - Low Pin Count (LPC) Interface Specification, Revision 1.0 (sept 1997)
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--use IEEE.STD_LOGIC_ARITH.ALL;
--use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity LPC_IOW80 is
   Port
   (
      lclk:         in std_logic;                         -- LPC: 33MHz clock (rising edge)
       lframe_n:   in std_logic;                         -- LPC: frame, active low
      lreset_n:   in std_logic;                         -- LPC: reset, active low
      lad:         in std_logic_vector(3 downto 0);    -- LPC: multiplexed bus
      seven_seg_L:out std_logic_vector(7 downto 0);    -- SSeg Data output
      seven_seg_H:out std_logic_vector(7 downto 0)    -- SSeg Data output   
   );
end LPC_IOW80;

architecture RTL of LPC_IOW80 is
   type LPC_State_Type is
   (
      IDLE,      -- Waiting for a start condition
      START,    -- Start condition detected
      WADDN3,    -- I/O write address nibble 3 (A15..A12)
      WADDN2,    -- I/O write address nibble 2 (A11..A8 )
      WADDN1,    -- I/O write address nibble 1 (A7..A4)
      WADDN0,    -- I/O write address nibble 0 (A3-A0)
      WDATN1,    -- I/O write data nibble 0 (D7..D4)
      WDATN0,    -- I/O write data nibble 1 (D3..D0)
      WHTAR0,    -- I/O write host turn around phase 0
      WHTAR1,    -- I/O write host turn around phase 1
      WSYNC,    -- I/O write sync
      WPTAR    -- I/O write peripheral turn around
   );   
   signal LPC_State: LPC_State_Type;
   signal lframe_nreg: std_logic; -- LPC frame register
   signal lad_rin: std_logic_vector(lad'range); -- LPC input registers
   signal W_Data: std_logic_vector(7 downto 0); -- LPC input Post Code

begin
---------------------------------------------------------------------------
-- LPC bidirectional pins definition.
---------------------------------------------------------------------------
-- Input register to get some timing margin
   P_input_register: process(lclk)
   begin
      if (lclk'event and lclk='1') then
         lad_rin <= lad;
         lframe_nreg <= lframe_n;
      end if;
   end process;
---------------------------------------------------------------------------
-- LPC state machine
-- LPC_State value is actually one clock cycle late.
---------------------------------------------------------------------------
   P_LPC_StatMachine: process(lclk)
   begin
      if (lclk'event and lclk='1') then
-- Synchronous reset
         if (lreset_n = '0') then
            LPC_State <= IDLE;
            W_Data(7 downto 0) <= "00000000"; -- init. both displays to all on
         else
            case LPC_State is
-- Looking for a START condition
            when IDLE =>
               if (lframe_nreg = '0') and (lad_rin = "0000") then
                  LPC_State <= START; -- START condition detected
               end if;
-- Skip extra cycles on START frame
-- (can be many clock cycles)
-- and then, check for I/O write transaction
            when START =>
               if (lframe_nreg = '0') then -- frame still asserted
                  if (lad_rin /= "0000") then
                     LPC_State <= IDLE; -- unsupported start code
                  end if;
               else
                  if (lad_rin(3 downto 1) = "001") then
                     LPC_State <= WADDN3; -- I/O write detected
                  else
                     LPC_State <= IDLE; -- unsupported command
                  end if;
               end if;
-- --------------------------------
-- I/O write transaction processing
-- --------------------------------
            when WADDN3 => -- Write Data Address Nibble 3
-- Find next state
               if (lframe_nreg = '0') or (lad_rin /= "0000") then
                  LPC_State <= IDLE;     -- abort cycle, bad frame
                                       -- or address mismatch
               else
                  LPC_State <= WADDN2;
               end if;
            when WADDN2 => -- Write Data Address Nibble 2
-- Find next state
               if (lframe_nreg = '0') or (lad_rin /= "0000") then
                  LPC_State <= IDLE;    -- abort cycle, bad frame
                                       -- or address mismatch
               else
                  LPC_State <= WADDN1;
               end if;
            when WADDN1 => -- Write Data Address Nibble 1
-- Find next state
               if (lframe_nreg = '0') or (lad_rin /= "1000") then
                  LPC_State <= IDLE;    -- abort cycle, bad frame
                                       -- or address mismatch
               else
                  LPC_State <= WADDN0;
               end if;
            when WADDN0 => -- Write Data Address Nibble 0
-- Find next state
               if (lframe_nreg = '0') or (lad_rin /= "0000") then
                  LPC_State <= IDLE;    -- abort cycle, bad frame
                                       -- or address mismatch
               else
-- Write address valid. Subsequent Data displays.
                  LPC_State <= WDATN0; -- Next state will get
-- first data nibble
               end if;
            when WDATN0 => -- Data LSN (Least Significant Nibble)is
                           -- sent first
               W_Data(3 downto 0) <= lad_rin; -- latch data (LSN)
               if (lframe_nreg = '1') then
                  LPC_State <= WDATN1; -- Next state gets
                                       -- 2nd data nibble
               else
                  LPC_State <= IDLE;
               end if;
            when WDATN1 => -- Data MSN (Most Significant Nibble)
               W_Data(7 downto 4) <= lad_rin; -- latch data (MSN)
               if (lframe_nreg = '1') then
                  LPC_State <= WHTAR0;
               else
                  LPC_State <= IDLE;
               end if;
            when WHTAR0 => -- Write Data Turn Around Cycle 0
               if (lframe_nreg = '1') and (lad_rin = "1111") then
                  LPC_State <= WHTAR1;
               else
                  LPC_State <= IDLE;
               end if;
            when WHTAR1 => -- Write Data Turn Around Cycle 1
               if (lframe_nreg = '1') then
                  LPC_State <= WSYNC;
               else
                  LPC_State <= IDLE;
               end if;
            when WSYNC => -- Write Data Sync Cycle
-- Note: No device to respond with a synch at I\O addr
-- 080h. Therefore bus should time out and abort.
-- State ==> to IDLE
               if (lframe_nreg = '1') then
                  LPC_State <= WPTAR;
               else
                  LPC_State <= IDLE;
               end if;
            when WPTAR =>    -- Write Data Final Turn Around Cycle
                           -- (not needed -- see WSYNC)
               LPC_State <= IDLE; -- I/O write cycle end
            when others =>
               LPC_State <= IDLE; -- all other cases
            end case;
         end if;
      end if;
end process;
P_sseg_decode: process(lclk) -- decode section for 7 seg displays
   begin
      if (lclk'event and lclk='1') then
         case W_Data(7 downto 4) is -- Most sig digit for display
            when "0000" => seven_seg_H <= "00000011"; -- Hex 03 displays a 0
            when "0001" => seven_seg_H <= "10011111"; -- Hex 9f displays a 1
            when "0010" => seven_seg_H <= "00100101"; -- Hex 25 displays a 2
            when "0011" => seven_seg_H <= "00001101"; -- Hex 0d displays a 3
            when "0100" => seven_seg_H <= "10011001"; -- Hex 99 displays a 4
            when "0101" => seven_seg_H <= "01001001"; -- Hex 49 displays a 5
            when "0110" => seven_seg_H <= "01000001"; -- Hex 41 displays a 6
            when "0111" => seven_seg_H <= "00011111"; -- Hex 1f displays a 7
            when "1000" => seven_seg_H <= "00000001"; -- Hex 01 displays a 8
            when "1001" => seven_seg_H <= "00001001"; -- Hex 09 displays a 9
            when "1010" => seven_seg_H <= "00010001"; -- Hex 11 displays a A
            when "1011" => seven_seg_H <= "11000001"; -- Hex c1 displays a b
            when "1100" => seven_seg_H <= "01100011"; -- Hex 63 displays a C
            when "1101" => seven_seg_H <= "10000101"; -- Hex 85 displays a d
            when "1110" => seven_seg_H <= "01100001"; -- Hex 61 displays a E
            when "1111" => seven_seg_H <= "01110001"; -- Hex 71 displays a F
            when others => seven_seg_H <= "00000001"; -- Hex 01 displays a 8
         end case;
         case W_Data(3 downto 0) is -- Least sig digit for display
            when "0000" => seven_seg_L <= "00000011"; -- Hex 03 displays a 0
            when "0001" => seven_seg_L <= "10011111"; -- Hex 9f displays a 1
            when "0010" => seven_seg_L <= "00100101"; -- Hex 25 displays a 2
            when "0011" => seven_seg_L <= "00001101"; -- Hex 0d displays a 3
            when "0100" => seven_seg_L <= "10011001"; -- Hex 99 displays a 4
            when "0101" => seven_seg_L <= "01001001"; -- Hex 49 displays a 5
            when "0110" => seven_seg_L <= "01000001"; -- Hex 41 displays a 6
            when "0111" => seven_seg_L <= "00011111"; -- Hex 1f displays a 7
            when "1000" => seven_seg_L <= "00000001"; -- Hex 01 displays a 8
            when "1001" => seven_seg_L <= "00001001"; -- Hex 09 displays a 9
            when "1010" => seven_seg_L <= "00010001"; -- Hex 11 displays a A
            when "1011" => seven_seg_L <= "11000001"; -- Hex c1 displays a b
            when "1100" => seven_seg_L <= "01100011"; -- Hex 63 displays a C
            when "1101" => seven_seg_L <= "10000101"; -- Hex 85 displays a d
            when "1110" => seven_seg_L <= "01100001"; -- Hex 61 displays a E
            when "1111" => seven_seg_L <= "01110001"; -- Hex 71 displays a F
            when others => seven_seg_L <= "00000001"; -- Hex 01 displays a 8
         end case;
      end if;
   end process;
end RTL;


Agradezco de antemano vuestras aportaciones.

Salu2.

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
Re: BUS LPC (Low Pin Count)
« Respuesta #1 en: 17 de Noviembre de 2009, 17:37:48 »
Más tarde hice un pequeño programa en vB que, mediante unos botones, activar salidas de la CPLD y funciona...

En cambio para leer entradas me encuentro encayado, ya que el bus con el que se comunican PC y CPLD es bidireccional y en el momento en que se escribe sobre el, dejan de funcionar las salidas.

No termino de entender...
¿En unos casos funcionan las salidas de la CPLD y en otros no?

Si el bus LAD es bidireccional, en la entidad del modelo está declarado unicamente como entrada, por lo que la CPLD no puede escribir sobre ese bus

Desconectado cmr1108

  • PIC10
  • *
  • Mensajes: 5
Re: BUS LPC (Low Pin Count)
« Respuesta #2 en: 18 de Noviembre de 2009, 05:01:08 »
Hola Modulay muchas gracias por tu respuesta.

Tal como dices en el código lad(3:0) está declarado como in y no como inout ya que este código es el de ejemplo que se puede encontrar por la web, pero yo lo he modificado añadiendo a 'LPC_State_Type', nuevos estados para el caso de que el PC mande por el bus LPC un comando de lectura, pero esto hace que la CPLD, bloquee el bus imposibilitando operaciones de escritura.
Si te lees el PDF de intel (por cierto es muy parco en explicaciones o ejemplos), veras que hay un protocolo que es distinto para lectura y escritura.
Sería interesante que alguien que haya trabajado con este bus arroje un poco de luz al tema.

Salu2 y muchas gracias a todos.

Desconectado cmr1108

  • PIC10
  • *
  • Mensajes: 5
Re: BUS LPC (Low Pin Count)
« Respuesta #3 en: 20 de Noviembre de 2009, 08:37:55 »
Hola a tod@s
Ya he solucionado el problema y lo tengo operativo 100%  :-/
El problema está en como se gestiona las salidas que se conectan a lad ya que hay que implementar un bus bidirecional y no lo hacía correctamente.
Despues de solucionar este problema ya funciona correctamente con un pequeño programa que enciende 24 leds y testea el estado de 27 pulsadores.

Salu2

Desconectado Kid_Bengala

  • Colaborador
  • PIC18
  • *****
  • Mensajes: 490
Re: BUS LPC (Low Pin Count)
« Respuesta #4 en: 20 de Noviembre de 2009, 11:15:38 »
hola

estaria bien que pusieras el codigo o la aplicacion,por si en un futuro alguien se anima con ello y sepa por donde comenzar  ;-) .gracias

saludos de antonio

Desconectado cmr1108

  • PIC10
  • *
  • Mensajes: 5
Re: BUS LPC (Low Pin Count)
« Respuesta #5 en: 22 de Noviembre de 2009, 07:36:17 »
Hola de nuevo a tod@s

Como siempre pasa, todo es muy sencillo cuando lo entiendes :)

El problema no estaba en la falta de documentación de Intel (aunque viniendo de donde viene se podían haber extendido un poco), sino en la configuración de bus bidireccional.

Hay que añadir en la arquitectura algunas señales...
architecture RTL of LPC_IOW80 is
   type LPC_State_Type is
   (
      IDLE,         -- Waiting for a start condition
      START,       -- Start condition detected
      WADDN3,       -- I/O write address nibble 3 (A15..A12)
      WADDN2,       -- I/O write address nibble 2 (A11..A8 )
      WADDN1,       -- I/O write address nibble 1 (A7..A4)
      WADDN0,       -- I/O write address nibble 0 (A3-A0)
      WDATN1,       -- I/O write data nibble 0 (D7..D4)
      WDATN0,       -- I/O write data nibble 1 (D3..D0)
      WHTAR0,       -- I/O write host turn around phase 0
      WHTAR1,       -- I/O write host turn around phase 1
      WSYNC,       -- I/O write sync
      WPTAR,       -- I/O write peripheral turn around
      WDATOPCN0,   -- I/O read data nibble 1 (D3..D0)*****************nueva
      WDATOPCN1   -- I/O read data nibble 0 (D7..D4)*****************nueva
   );   
   signal LPC_State: LPC_State_Type;
   type address_port is range 0 to 6;***********************************nueva
   signal puerto: address_port;***************************************nueva
   signal lframe_nreg: std_logic; -- LPC frame register
   signal lad_rin: std_logic_vector(lad'range); -- LPC input registers
   signal W_Data: std_logic_vector(7 downto 0); -- LPC input Post Code
   signal r_w: std_logic:='0'; --0 => PC => CPLD  1 => CPLD <= PC************nueva
   signal read_cicle: std_logic:='0';************************************nueva
   signal R_Data: std_logic_vector(31 downto 0); -- LPC input Post Code********nueva
   signal bufer_entradas: std_logic_vector(7 downto 0);********************nueva
begin

... en el primer proceso añadir la captura de las entradas...
---------------------------------------------------------------------------
-- LPC bidirectional pins definition.
---------------------------------------------------------------------------
-- Input register to get some timing margin
   P_input_register: process(lclk)
   begin
      if (lclk'event and lclk='1') then
         lad_rin <= lad;
         lframe_nreg <= lframe_n;
         R_Data(26 downto 0) <= inputs;
      end if;
   end process;
...en el segundo proceso modificar el estado WADN0 añadiendo la bifurcación en la máquina de estados para lectura o escritura...

            when WADDN0 => -- Write Data Address Nibble 0
-- Find next state
               if (lframe_nreg = '0') then
                  LPC_State <= IDLE;    -- abort cycle, bad frame
                                       -- or address mismatch
               else
-- Write address valid. Subsequent Data displays.
                  if (lad_rin = "0110") then
                     puerto <= 0;
                  elsif   (lad_rin = "0111") then
                     puerto <= 1;
                  elsif   (lad_rin = "1000") then
                     puerto <= 2;
                  elsif   (lad_rin = "1001") then
                     puerto <= 3;
                  elsif   (lad_rin = "1010") then
                     puerto <= 4;
                  elsif   (lad_rin = "1011") then
                     puerto <= 5;
                  elsif   (lad_rin = "1100") then
                     puerto <= 6;
                  else
                     LPC_State <= IDLE;    -- abort cycle, bad frame                  
                  end if;
                  if ( read_cicle = '0' ) then
                     LPC_State <= WDATN0; -- Next state will get
                  else
                     LPC_State <= WHTAR0; -- Next state will get
                  end if;
-- first data nibble
               end if;

---modificar el tercer proceso para actualizar los buffers de entradas intermedios y los de salidas...

   P_sseg_decode: process(lclk) -- decode section for 7 seg displays
   begin
      if (lclk'event and lclk='1') then
         case puerto is
            when 0 => salida(7 downto 0) <= W_Data(7 downto 0);
            when 1 => salida(15 downto 8) <= W_Data(7 downto 0);
            when 2 => salida(23 downto 16) <= W_Data(7 downto 0);
            when 3 => bufer_entradas(7 downto 0) <= R_Data(31 downto 24);
            when 4 => bufer_entradas(7 downto 0) <= R_Data(23 downto 16);
            when 5 => bufer_entradas(7 downto 0) <= R_Data(15 downto 8);
            when 6 => bufer_entradas(7 downto 0) <= R_Data(7 downto 0);
         end case;
      end if;
   end process;

....y por último (y lo más importante), añadir un último proceso para que nos funcione el bus realmente como triestate y no escribamos en el salvo cuando realmente el chipset del PC este esperando la información...

   P_triestate: process(lclk,r_w )
   begin
      if (lclk'event and lclk='1') then
         if (r_w = '0') then
            lad <= "ZZZZ";
         else
            case LPC_State is
               when WDATOPCN0 => lad <= bufer_entradas(3 downto 0);
               when WDATOPCN1 => lad <= bufer_entradas(7 downto 4);
               when WSYNC       => lad <= "0000";
               when others    => lad <= "ZZZZ";
            end case;   
         end if;   
      end if;   
   end process;


Salu2 a tod@s y espero que esto les sirva a muchos que quieran curiosear y utilizar un PC para otras cosas de las ya habituales

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
Re: BUS LPC (Low Pin Count)
« Respuesta #6 en: 22 de Noviembre de 2009, 08:48:00 »
Imagino que también habrás modificado la entidad y ahora el bus LAD es bidireccional, si no, no debería ni compilar.

Desconectado cmr1108

  • PIC10
  • *
  • Mensajes: 5
Re: BUS LPC (Low Pin Count)
« Respuesta #7 en: 22 de Noviembre de 2009, 09:22:11 »
Citar
Tal como dices en el código lad(3:0) está declarado como in y no como inout ya que este código es el de ejemplo que se puede encontrar por la web, pero yo lo he modificado añadiendo a 'LPC_State_Type', nuevos estados para el caso de que el PC mande por el bus LPC un comando de lectura, pero esto hace que la CPLD, bloquee el bus imposibilitando operaciones de escritura.

Evidentemente.
Salu2.

Desconectado Modulay

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2651
Re: BUS LPC (Low Pin Count)
« Respuesta #8 en: 22 de Noviembre de 2009, 14:45:48 »
Haces referencias a modificaciones en la arquitectura, y no en la entidad, y como después de solucionar el problema pones el código de la arquitectura y omites el de la entidad, pues no me quedaba del todo claro qué habías hecho para hacer funcionar el diseño.
Me alegro de que lo hayas solucionado.
Un saludo