Ir al contenido principal

Placa de prototipado FPGA Cyclone IV EP4CE6

Existen en el mercado multitud de placas de entrenamiento FPGA. Ya hemos visto algunas en este blog, pero os quiero hablar de una que me ha llamado la atención por su enfoque diferente. Elegir una placa de entrenamiento a veces se complica, ya que no sólo hay que buscar una con la familia de FPGA que nos interesa, también hay que evaluar qué elementos periféricos trae consigo.

¿Necesitamos un display de siete segmentos? ¿botones? ¿salida VGA o entrada para teclado? La aproximación de Waveshare me ha resultado interesante, ya que lejos de incluir una serie de elementos periféricos a la FPGA, ha optado por un sistema totalmente modular, lo que tiene ciertas ventajas (y desventajas, claro).

Core FPGA y expansión

La idea es ofrecer una placa FPGA básica, a la que llaman core, con la FPGA que necesitemos (ya sea de Altera o XILINX). Esta placa core puede acoplarse a una placa de expansión con una buena cantidad de conectores. En la fotografía anterior hay una FPGA de la familia Cyclone IV de Altera (se trata de la placa CoreEP4CE6) junto con la expansión, en este caso la DVK601. Cuidado porque dependiendo del modelo de FPGA hay que elegir una placa de expansión u otra. Por ejemplo si queremos usar la placa FPGA EP4CE10, tendremos que optar por la expansión DVK600.
La ventaja radica en que a esta placa de expansión podemos conectar aquellos módulos que vayamos necesitando (ya sean de los vendidos por Waveshare o de cualquier otro fabricante).

Complementos FPGA

Es esta imagen hay módulos que añaden un display de cuatro dígitos, pulsadores, lectores de memoria flash, una memoria SDRAM y un puerto VGA y PS/2. Hay mucha variedad. Por ejemplo, el display lo adquirí en la propia web del fabricante, pero los pulsadores son de Dealextreme.

Para probarla, he adaptado el código VHDL del reloj digital que ya vimos en un artículo anterior y demás he usado el circuito antirrebote de la semana pasada para añadir la funcionalidad de adelantar el minutero para ajustar la hora pulsando un botón. Así queda la placa de expansión con la FPGA, el display y los pulsadores.

montaje

Tengo que decir que el display se ilumina muy poco. La placa de expansión suministra 3.3V en lugar de 5V, que según las especificaciones del display, es la tensión correcta. El código VHDL del reloj, tras adaptarlo, es el siguiente.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity digital_clock is
port (
  clk50mhz: 	in STD_LOGIC;
  display: 	out STD_LOGIC_VECTOR(7 downto 0);
  cur_display:	out STD_LOGIC_VECTOR(3 downto 0);
  point: out STD_LOGIC;
  button: in STD_LOGIC
);
end digital_clock;
architecture beh of digital_clock is
  constant max_count: INTEGER := 25000000; -- 50000000/2
  constant max_refresh_count: INTEGER := 100000; -- 50Mzh/100000=500Hz
  signal count: INTEGER range 0 to max_count;
  signal refresh_count: INTEGER range 0 to max_refresh_count;
  signal refresh_state: STD_LOGIC_VECTOR(1 downto 0) := (others => '0');
  signal clk_state: STD_LOGIC := '0';
  signal display_sel: STD_LOGIC_VECTOR(3 downto 0) := (others => '0');
  shared variable hora1, hora2, min1, min2: INTEGER range 0 to 10 := 0;
  shared variable segundos: INTEGER range 0 to 59 := 0;
  constant CNT_SIZE : integer := 19;
 
  function digito(numero:INTEGER) return STD_LOGIC_VECTOR is
	variable salida: STD_LOGIC_VECTOR(7 downto 0);
  begin
	case numero is
		when 0 => salida := "11000000"; -- 0 
		when 1 => salida := "11111001"; -- 1
		when 2 => salida := "10100100"; -- 2
		when 3 => salida := "10110000"; -- 3
		when 4 => salida := "10011001"; -- 4
		when 5 => salida := "10010010"; -- 5
		when 6 => salida := "10000011"; -- 6
		when 7 => salida := "11111000"; -- 7 
		when 8 => salida := "10000000"; -- 8
		when 9 => salida := "10010000"; -- 9
		when others => salida := "11111111";
	end case;
	return(salida);
  end digito;
	
  begin
    cur_display <= display_sel;
    gen_clock: process(clk50mhz, clk_state, count)
    begin
	if clk50mhz'event and clk50mhz='1' then
		-- contador 1HZ
		if count < max_count then 
			count <= count + 1;
		else
			clk_state <= not clk_state;
			count <= 0;
		end if;
		
		-- contador 500Hz (para refresco del display)
		if refresh_count < max_refresh_count then
			refresh_count <= refresh_count + 1;
		else
			refresh_state <= refresh_state + 1;
			refresh_count <= 0; 
                end if; 
         end if; 
      end process; 
      show_display: process(refresh_state) 
      begin -- selección del display 
          case refresh_state is 
              when "00" => display_sel <= "0001"; -- display 0 
              when "01" => display_sel <= "0010"; -- display 1 
              when "10" => display_sel <= "0100"; -- display 2 
              when "11" => display_sel <= "1000"; -- display 3 
              when others => display_sel <= "1111"; 
           end case; 
           -- mostrar hora 
           case display_sel is 
              when "0001" => display <= digito(hora2); -- display 0 
              when "0010" => display <= digito(hora1); -- display 1 
              when "0100" => display <= digito(min2); -- display 2 
              when "1000" => display <= digito(min1); -- display 3 
              when others => display <= "11111111"; 
            end case;
	
	    -- parpadeo del punto
	    point <= clk_state;
	 end process;
	
  persecond: process (clk_state)
  begin
  
  
	if clk_state'event and clk_state='1' then
		
		-- contador de segundos
		if segundos < 59 then
			-- comprobar pulsacion de boton
			if button = '0' then
				segundos := 0;
				min1 := min1 + 1; -- +1 minuto
			else 
				segundos := segundos + 1;
			end if;
		else 
			segundos := 0;
			min1 := min1 + 1; -- +1 minuto
		end if;
		
		-- segundo dígito minutero
		if min1 = 10 then
			min2 := min2 + 1;
			min1 := 0;
		end if;
		
		-- primer dígito hora
		if min2 = 6 then
			hora1 := hora1 + 1;
			min2 := 0;
		end if;
		
		-- segundo dígito hora
		if hora1 = 10 then
			hora2 := hora2 + 1;
			hora1 := 0;
		end if;
			
		if hora2=2 and hora1=4 then
			hora2 := 0;
			hora1 := 0;
		end if;
	end if;
  end process;
end beh;

Los cambios más importantes son los siguientes:

Aprovechando que el display tiene dos puntos para separar horas y minutos, se ha añadido una señal llamada point para controlar el parpadeo. Otra diferencia es que ahora, tal y como se ve en el siguiente esquema, la selección del display de siete segmentos se hace a través de un transistor configurado en emisor común, lo que quiere decir que ahora el display se selecciona con una señal a nivel alto (el primer display se selecciona con 0001 en lugar de 1110 como hacíamos en el artículo anterior).

Esquema display

También se ha añadido la circuitería necesaria para adelantar el minutero al pulsar el botón. En cada ciclo de un segundo se comprueba si el botón está pulsado y si es así, se incrementa el tiempo en un minuto.

El pulsador antirrebote no ha cambiado, pero lo vuelvo a recordar aquí de todas formas.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity debouncer is  
	port (
		clk	: in std_logic;
		btn_in	: in std_logic;
		btn_out	: out std_logic);
end debouncer;
architecture beh of debouncer is
    constant CNT_SIZE : integer := 19;
    signal btn_prev   : std_logic := '0';
    signal counter    : std_logic_vector(CNT_SIZE downto 0) := (others => '0');
    begin
    process(clk)
    begin
	if (clk'event and clk='1') then
		if (btn_prev xor btn_in) = '1' then
			counter <= (others => '0');
			btn_prev <= btn_in;
		elsif (counter(CNT_SIZE) = '0') then
			counter <= counter + 1;
        	else
			btn_out <= btn_prev;
		end if;
	end if;
    end process;
end beh;

Llamadme nostálgico, pero cuando hay que acoplar pocos dispositivos, como en este caso, prefiero usar el capturador de esquemáticos en lugar de hacer un mapeo con VHDL. Este es el conexionado del reloj y el circuito antirrebote.

Circuito

Los pines están bien documentados en la wiki del propio fabricante, así que no entraré en detalle. Simplemente os dejo la configuración en pin planner para el conexionado del display y el botón.

pin planner

En este vídeo se puede ver el reloj en funcionamiento.

Comentarios

Entradas populares de este blog

Creando firmas de virus para ClamAV

ClamAv es un antivirus opensource y multiplataforma creado por Tomasz Kojm muy utilizado en los servidores de correo Linux. Este antivirus es desarrollado por la comunidad, y su utilidad práctica depende de que su base de datos de firmas sea lo suficientemente grande y actualizado. Para ello es necesario que voluntarios contribuyan activamente aportando firmas. El presente artículo pretende describir de manera sencilla cómo crear firmas de virus para ClamAV y contribuir con ellas a la comunidad.

Ingeniería inversa de un parche de Microsoft Windows

A estas alturas ya hemos asumido que la seguridad total en Internet es, cuanto menos, un mito. Ningún software está libre de vulnerabilidades, y por mucha auditoría, test de intrusión o pruebas de fuzzing que nos empeñemos en hacer, ninguna metodología puede demostrar sin lugar a dudas que un software es 100% seguro. Ante este panorama, hay dos tendencias mayoritarias a la hora de hacer públicas las vulnerabilidades. Por un lado, están los que piensan que cuando se descubre un fallo ha de hacerse público de forma inmediata. En este escenario, la publicación de una vulnerabilidad es el pistoletazo de salida para una carrera entre el desarrollador para sacar el parche y los "malos" para lograr explotarla. Esta política es conocida como full disclosure . Por otro lado, tenemos a los siguen una política responsible disclosure , que abogan por mantener la vulnerabilidad en secreto hasta la salida del parche por parte del desarrollador. Sin entrar en cuestiones filosóficas que no...

Scripts en NMAP

Cuando pensamos en NMAP, pensamos en el escaneo de puertos de un host objetivo al que estamos relizando una prueba de intrusión, pero gracias a las posibilidades que nos ofrecen su Scripting Engine , NMAP es mucho más que eso. Antes de continuar, un aviso: algunas de posibilidades que nos ofrecen los scripts de NMAP son bastante intrusivas, por lo que recomiendo hacerlas contra hosts propios, máquinas virtuales como las de Metasploitable, o contrato de pentesting mediante. Para este artículo voy a usar las máquinas de Metasploitable3 . No voy a entrar en los detalles sobre el uso básico de NMAP, ya que hay miles de tutoriales en Internet que hablan sobre ello. Lo cierto es que NMAP tiene algunas opciones que permiten obtener información extra, además de qué puertos están abiertos y cuales no. Por ejemplo, la opción -sV trata de obtener el servicio concreto, e incluso la versión del servicio que está corriendo en cada puerto. Otro ejemplo es la opción -O, que intenta averiguar el ...