Conheça a FPGA Altera Cyclone II

Conheça a FPGA Altera Cyclone II 2

FPGAs são dispositivos reconfiguráveis que podem ser modificados à nível de hardware, desta forma oferecem uma flexibilidade muito superior a microcontroladores onde apenas o software pode ser modificado.

A FPGA Altera Cyclone II EP2C5T144 é uma FPGA de baixo custo e uma excelente plataforma de desenvolvimento para aqueles que estão começando a se aventurar com hardwares reconfiguráveis. Neste post veremos algumas características deste dispositivo e como desenvolver um projeto simples utilizando-a.

Material necessário

O que é uma FPGA?

Uma FPGA (Field Programmable Gate Array, em português Arranjo de Portas Programáveis em Campo) é um circuito integrado desenvolvido para ser configurado, em nível de hardware, pelo usuário. Diferente de um microprocessador, onde apenas podemos modificar o software, na FPGA é possível modificar o circuito, o que dá a estes dispositivos uma flexibilidade muito superior aos microprocessadores.

Conheça a FPGA Altera Cyclone II

Internamente uma FPGA é composta por pequenos blocos chamados de LEs (Logic Elements – Elementos Lógicos). Cada LE é composto basicamente por uma pequena memória RAM e um (ou mais) Flip Flops. A memória RAM é utilizada para implementar lógicas combinacionais (operações lógicas simples como OR, NOT, AND e XOR) e o Flip Flop para implementar lógicas sequenciais (que requerem um sinal de clock). Um único LE pode implementar circuitos extremamente simples, mas LEs podem ser combinados para formar circuitos extremamente complexos.

Conheça a FPGA Altera Cyclone II
Lógic Element Fonte: https://www.eetimes.com

Note que a memória utilizada no LE é volátil, ou seja, ao desligar a FPGA toda a configuração é perdida. Memórias voláteis geralmente são mais simples, rápidas e duráveis que memórias não voláteis (nas quais o simples processo de escrita provoca um desgaste). Para criar circuitos persistentes utiliza-se um dispositivo de configuração – este componente é basicamente uma pequena memória não volátil que guarda as informações do circuito e o configura na FPGA toda vez que é ligado.

Além de LEs, é comum encontrar em FPGAs módulos de hardwares que seriam difíceis, ineficientes ou impossíveis de se implementar com LEs, tais como memórias, PLLs, drives de GPIOs, entre outros. Se quiser entender melhor como FPGAs funcionam, acesse o post Primeiros Passos de FPGA com a Papilio One.

Como uma FPGA é configurada em nível de hardware, nós não utilizamos linguagens de programação, mas sim linguagens de descrição para descrever como o circuito interno deve ser montado. Duas das linguagens de descrição mais populares e suportadas por diversas FPGAs são a VHDL e Verilog.

A FPGA Altera Cyclone II

A Cyclone II EP2C5 Mini Dev Board é uma placa de desenvolvimento baseada na FPGA Cyclone II EP2C5T144C8. A Cyclone é uma família de FPGAs de baixo custo desenvolvida pela Altera (adquirida pela Intel). Especificamente a EP2C custa apenas 20 dólares, o que faz dela uma excelente entrada para aqueles que estão aprendendo a utilizar FPGAs.

Conheça a FPGA Altera Cyclone II

Além da EP2C5, a placa contém também o hardware mínimo para seu funcionamento, o que inclui:

  • Cristal oscilador de 50MHz (utilizado para produzir sinal de clock)
  • Circuito de alimentação (permite alimentar a placa com +5Vcc)
  • Configurador Serial (para gravação permanente do circuito)
  • 3 LEDs configuráveis
  • 1 Push button (geralmente utilizado para reset)

Vamos aprender a utilizar a Cyclone II EP2C5 na prática desenvolvendo um circuito de LED chaser, onde dois ou mais LEDs são iluminados, em sequência, um de cada vez, e configurando a FPGA tanto de forma temporária quanto permanente. Vamos utilizar o botão e os LEDs embutidos na placa, portanto nenhum circuito externo é necessário.

Diagrama em Blocos do Circuito

Ao projetar um sistema de hardware, é útil primeiro construir um diagrama em blocos do circuito, onde o sistema é dividido em módulos de hardware (blocos), cada um com uma função específica. Esse diagrama é útil também em projetos com FPGA.

O diagrama do LED Chaser está representado na imagem abaixo:

Conheça a FPGA Altera Cyclone II

Note que o sistema é composto por um único macro-bloco chamado Top. Dentro deste bloco há dois sub-blocos: Divisor de Clock e Contador de Década.

O primeiro sub-bloco é um divisor de clock de fator 1/50 milhões. O cristal oscilador embutido na FPGA tem uma frequência de 50 MHz, o que é muito rápido para nossa visão, precisamos portanto, reduzi-lo para uma frequência menor. Dividindo-o por um fator de 50 milhões a frequência resultante é 1 Hz, que pode ser visto sem dificuldade.

O segundo sub-bloco trata-se de um contador binário de década. Este contador conta em potências de 2 ao invés de 1 em 1. O resultado é que apenas uma das saídas fica ativa a cada pulso de clock, em sequência, o exato comportamento do LED Chaser.

Criar o diagrama em blocos vai facilitar muito o desenvolvimento, especialmente quando podemos traduzir cada bloco em componentes ou entidades (veremos isso mais a frente).

Quartus II

O software utilizado para configurar as FPGAs da Altera é o Quartus, desenvolvido pela própria empresa, podendo ser encontrado no site da Intel. A Linha Cyclone II é uma família antiga de FPGAs e não é suportada nas versões mais recentes do Quartus.

Vamos instalar a versão Quartus II – 13.0sp1, a versão mais recente que ainda suporta a família Cyclone II. Esta versão conta com uma Web Edition, uma versão gratuita que, embora não tenha todas os recursos da versão paga, inclui tudo o que necessitamos para configurar, gravar e “debugar” a FPGA. O download completo do Quartus é muito grande, superior a 4 gigas, podemos reduzi-lo baixando apenas os componentes que necessitamos (ainda sim o download é superior a 3 gigas).

Na página de download do Quartus, selecione a aba Individual Files e, na guia Quartus II Web Edition (Free), baixe os arquivos: Quartus II Software (includes Nios II EDS) e ModelSim-Altera Edition (includes Starter Edition). O primeiro arquivo é o próprio Quartus; o segundo é opcional, mas recomendado – trata-se de um simulador que permite realizar testes no circuito antes de configurá-lo na FPGA.

Conheça a FPGA Altera Cyclone II

Precisamos baixar também os arquivos de suporte às FPGAs. Estes arquivos estão na guia Devices. Esta versão do Quartus suporta nove famílias de dispositivos, precisamos baixar apenas a que contém suporte para a Cyclone II.

Conheça a FPGA Altera Cyclone II

Por fim, precisamos do software de gravação e opcionalmente os arquivos de ajuda, ambos se encontram na guia Additional Software.

Conheça a FPGA Altera Cyclone II

Você pode ser solicitado a criar uma conta na Intel antes de poder baixar os arquivos. Uma vez que todos os downloads terminarem, certifique-se que todos os arquivos estão na mesma pasta e execute o Quartus Setup Web e o instalador deve detectar os outros arquivos e instalá-los automaticamente. Siga as instruções que surgirem na tela – este processo costuma demorar.

Criando o primeiro projeto com Quartus II

Com o programa instalado, vamos criar o nosso primeiro projeto com a EP2C5. O Quartus nos permite configurar uma FPGA com duas linguagens: Verilog e VHDL. Algumas palavras-chaves e estruturas destas linguagens podem lembrar linguagens de programação convencionais, mas certos comportamentos são diferentes. Neste post usaremos a linguagem VHDL para descrever os circuitos.

Ao abrir o Quartus, uma mensagem de boas vindas é exibida e você pode criar um novo projeto clicando em Create a New Project ou clicando no menu File e, em seguida, New Project Wizard.

Conheça a FPGA Altera Cyclone II

Conheça a FPGA Altera Cyclone II

Após isso, uma janela de introdução à criação de projetos abrirá, clique em Next para prosseguir a janela de Diretório, Nome e Entidade Top-Level. Nesta janela você deve indicar qual a pasta em que o projeto será criado, o nome do projeto e o nome da entidade superior.

Quando projetamos um hardware em uma FPGA, é comum dividir o circuito em módulos menores e mais simples, cada um com uma função específica. Podemos criar módulos mais complexos combinando módulos mais simples. Estes módulos são chamados de entidades e a entidade superior é o circuito principal do projeto, dentro do qual estão todos os sub-módulos. Lembra-se do diagrama em blocos? A entidade superior, ou top-level é o macrobloco e cada sub-bloco é uma entidade VHDL que deve ser descrita em seu próprio arquivo VHDL.

Conheça a FPGA Altera Cyclone II

Na segunda janela podemos adicionar arquivos ao projeto. Neste caso, iremos criar e adicionar posteriormente, portanto apenas clique em Next. Na próxima janela, devemos selecionar o modelo da FPGA, selecione Cyclone II em Device Family e digite EP2C5T144C8 (o modelo da FPGA) em Name Filter. Um único resultado deve aparecer em Available devices, selecione-o. As demais janelas podem ser ignoradas por hora, portanto, após selecionar o dispositivo, clique em Finish.

Conheça a FPGA Altera Cyclone II

Com o projeto criado, precisamos descrever as entidades que compõem nosso circuito, a começar pela entidade top-level. Clique no símbolo de folha em branco no canto superior esquerdo do Quartus para criar um novo arquivo e uma janela abrirá, clique em VHDL File dentro da guia Design Files. O código a ser escrito está demonstrado abaixo, salve-o com o mesmo nome que colocou como entidade superior, neste caso “top.vhd” (.vhd é a extensão dos arquivos VHDL):

library ieee;
use ieee.std_logic_1164.all;

entity top is
	port(
		clk : in std_logic;
		n_rst, n_pwo_rst : in std_logic;
		leds_out : out std_logic_vector(2 downto 0)
	);
end entity;

architecture a_top of top is
	-- Componentes
	component DecCount_3 is
		port(
			rst, clk, en : in std_logic;
			q : out std_logic_vector(2 downto 0)
		);
	end component;
	component ClkDiv50M is
		port(
			rst, clk, en : in std_logic;
			q : out std_logic
		);
	end component;
	-- Sinais
	signal rst, en : std_logic;
	signal n_out : std_logic_vector(2 downto 0);
begin
	-- Instanciação e Conexão dos componentes
	cd1 : ClkDiv50M port map(
		rst => rst,
		clk => clk,
		en => '1',
		q => en
	); 
	dc1 : DecCount_3 port map(
		rst => rst,
		clk => clk,
		en => en,
		q => n_out
	);
	-- Conexão dos sinais
	rst <= not (n_rst and n_pwo_rst);
	leds_out <= not n_out;
end architecture;

Vamos analisar o código por partes. Antes de mais nada, vale ressaltar que VHDL, diferente de C e Python, é Case Insensitive, ou seja, não há distinção entre letras maiúsculas e minúsculas.

Assim como em linguagens de programação, podemos declarar bibliotecas e pacotes para armazenar entidades, funções, constantes e tipos, evitando a repetição destes elementos em um mesmo projeto ou em projetos diferentes. Na primeira linha importamos a biblioteca ieee (lê-se i-três-é) e, logo após, declarando que usaremos tudo o que estiver disponível no pacote std_logic_1164.

Praticamente em todos os projetos com FPGA e VHDL, estas duas linhas estarão presentes pois o pacote std_logic_1164 (disponível dentro da biblioteca ieee) contém as definições dos valores lógicos utilizados no design do circuito.

No arduino, dois valores lógicos podem ser escritos (ou lidos) das GPIOs, sendo eles LOW (0 volts) ou HIGH (5 volts). O std_logic definido pela IEEE (Institute of Electrical and Electronics Engineers – Instituto de Engenheiros Eletricistas e Eletrônicos em português) é um pouco mais complexo e define nove valores lógicos:

Símbolo Nome Função
‘U’ Não Inicializado Usado em simulações para  representar memórias não inicializadas e erros
‘X’ Desconhecido Forte
‘0’ Baixo Forte Equivalente ao LOW
‘1’ Alto Forte Equivalente ao HIGH
‘Z’ Alta Impedância Tristate (pode ser entendido como desconectado)
‘W’ Desconhecido Fraco —-
‘L’ Baixo Fraco Pull-Down
‘H’ Alto Fraco Pull-Up
‘-’ Não Importa Utilizado para lógicas que independem do valor

Na maioria das vezes, utilizaremos apenas os valores ‘0’ (LOW) e ‘1‘ (HIGH), no entanto é bom conhecer os outro valores.

Após importar as bibliotecas e pacotes, definimos a entidade. Ela não define o funcionamento do circuito, mas apenas sua interface (entradas e saídas). A estrutura genérica para declarar entidades é:

entity <Nome da Entidade> is
	port(
		<Nome(s),> : <Direção> <Tipo>;
		<Nome(s),> : <Direção> <Tipo>
	);
end entity;

O nome do arquivo deve ser o mesmo que o nome da entidade. A interface da entidade é declarada dentro de port, podemos declarar uma ou mais portas (Entradas/Saídas) do mesmo tipo e direção (entrada ou saída) separadas por vírgulas. Portas de tipo ou direção diferentes devem ser separadas por ponto e vírgula, a última não deve ter um ponto e vírgula ao final. Em nosso projeto, declaramos a entidade top que possui três entradas do tipo std_logic e uma saída do tipo std_logic_vector – este tipo também é definido em std_logic_1164 e trata-se de um grupo ordenado de std_logic. Você pode pensar nesta saída como um barramento (conjunto de fios) de três fios numerados de 2 a 0.

Após a entidade, declaramos a arquitetura onde a lógica e comportamento do circuito é implementado. A estrutura genérica para declarar arquiteturas é:

architecture <Nome da Arquitetura> of <Nome da Entidade> is
	<Declaração de sinais e componentes;>
begin
	<Implementação do circuito>
end architecture;

Declaramos a arquitetura a_top vinculada à entidade top. Como mostrado na estrutura, a arquitetura é dividido em dois campos. No primeiro, declaramos dois componentes: DecCount_3 e ClkDiv50M e dois sinais: rst do tipo std_logic e n_out do tipo std_logic_vector.

architecture a_top of top is
	-- Componentes
	component DecCount_3 is
		port(
			rst, clk, en : in std_logic;
			q : out std_logic_vector(2 downto 0)
		);
	end component;
	component ClkDiv50M is
		port(
			rst, clk, en : in std_logic;
			q : out std_logic
		);
	end component;
	-- Sinais
	signal rst, en : std_logic;
	signal n_out : std_logic_vector(2 downto 0);
begin
	< … >
end architecture;

Sinais podem ser vistos como fios que usamos para criar as conexões internas do circuito. Neste caso, declaramos um fio chamado rst e um barramento de três fios chamado n_out. Sinais são declarados de forma semelhante às portas, porém são precedidos pela palavra signal e não especificam direção (são naturalmente bidirecionais).

Componentes são módulos de hardware que serão utilizados dentro da arquitetura. Quando o circuito for sintetizado, o Quartus vai buscar entidades cujo nome correspondem aos nomes dos componentes e os implementá-las nos locais indicados. Note que ainda não descrevemos as entidades associadas a estes componentes, faremos isso mais tarde, mas como já sabemos suas interfaces podemos declará-los.

No segundo campo da arquitetura, após begin, é onde o comportamento do circuito é especificado. Nele utilizamos componentes, sinais, operações lógicas e matemáticas para definir o comportamento das saídas em função das entradas.

architecture a_top of top is
	<...>
begin
	-- Instanciação e Conexão dos componentes
	dc1 : DecCount_3 port map(
		rst => rst,
		clk => clk,
		en => en,
		q => n_out
	);
	clk_div: ClkDiv50M port map(
		rst => rst,
		clk => clk,
		en => '1',
		q => en
	); 
	-- Conexão dos sinais
	rst <= not (n_rst and n_pwo_rst);
	leds_out <= not n_out;
end architecture;

Instanciamos um componente DecCount_3 e o nomeamos dc1. Em um mesmo circuito pode haver várias instâncias de um mesmo componente, desde que cada uma tenha nomes diferentes (lembre que letras maiúsculas não são diferenciadas de minúsculas). Após instanciar o componente, precisamos mapear suas portas (à esquerda) para sinais ou para as portas do circuito externo (à direita).O mapeamento utiliza o símbolo => e deve ser separado por vírgulas.

O mesmo é feito para ClkDiv50M. Repare que a porta en (enable) do componente é mapeado para ‘1’, isso é equivalente a ligar esta entrada à um sinal alto constante (Vcc). Na prática, estamos dizendo que o componente clk_div vai sempre estar ativo; o dc1, no entanto, vai estar ativo (recebendo pulsos de clock) somente quando o sinal en, controlado pelo componente clk_div, estiver em ‘1’. Como a saída de clk_div é equivalente ao sinal de clock dividido por 50 milhões, efetivamente estamos ligando dc1 em um clock de 1 Hz (50 MHz / 50M).

Por fim, conectamos os sinais às entradas e saídas do circuito. O sinal rst é o reset do circuito e há duas entradas vinculadas: a primeira provém de um botão que podemos pressionar para resetar e a segunda é um sinal especial que fica em alto ao ligar o circuito e após isso permanece em zero (utilizado para o reset inicial). Ambos os sinais tem lógica negativa (ativo em zero), portanto invertemos ambos. O sinal n_out é a saída do circuito, vamos ligá-la aos LEDs embutidos na placa, porém como os LEDs também tem lógica negativa, invertemos o sinal.

Com isso terminamos de descrever a entidade top-level, no entanto se tentarmos configurar este circuito na FPGA ocorrerá um erro, pois não definimos as entidade DecCount_3 e ClkDiv50M que declaramos como componente em top. Crie um novo arquivo vhdl e salve-o como DecCount_3.vhd; nele, vamos descrever o hardware de um contador de década de três bits:

library ieee;
use ieee.std_logic_1164.all;

entity DecCount_3 is
	port(
		rst, clk, en : in std_logic;
		q : out std_logic_vector(2 downto 0)
	);
end entity;

architecture a_DecCount_3 of DecCount_3 is
	signal data : std_logic_vector(3 downto 0) := "1000";
begin
	process(clk, rst)
	begin
		if rst='1' then
			data <= "1000";
		elsif (clk'event and clk='1') and en='1' then
			data <= data(2 downto 0) & data(3);
		else
			data <= data;
		end if;
	end process;
	q <= data(2 downto 0);
end architecture;

A estrutura do DecCount_3 é semelhante à da entidade top, mas há dois conceitos de VHDL que devem ser introduzidos. O primeiro refere-se ao sinal data, enquanto na entidade top os sinais foram utilizados principalmente para interconexões e para construção de lógicas combinacionais (onde a saída depende unicamente do valor atual da entrada) em lógicas sequenciais (onde a saída depende não só da entrada atual, mas também das anteriores) – sinais também podem ser usados como variáveis ou memórias. O sinal data atua como uma pequena memória de 4 bits que inicialmente possui o valor “1000”.

O segundo é o bloco de processo (process), utilizado em VHDL para construção de lógicas sequenciais. Um bloco de processo pode conter uma lista de sensibilidade, com nome de sinais entre parênteses. Se a lista for especificada, os conteúdos dentro de processo somente serão executados caso haja uma mudança no valor de, ao menos, um sinal da lista.

No bloco de processo de DecCount_3, especificamos que toda vez que houver uma mudança no valor de clk ou rst:

  1. Se rst estiver em alto, então o valor de data é atualizado para “1000”;
  2. Caso contrário, se houver uma borda de subida em clk (transição de baixo para alto) e en estiver em alto, então o valor de data é rotacionado à esquerda com carry;
  3. Caso nenhuma das condições anteriores seja válida, data permanece com o mesmo valor.

Dentro de process, utilizamos (clk’event and clk=’1′) como umas das condições para realizar o shift à esquerda de data. Essa condição somente é verdadeira no exato momento da transição do clock de baixo para alto (borda de subida). A condição clk’event só pode ser utilizada em combinação com uma comparação direta de clk (neste caso clk=’1’). Toda vez que precisar especificar condições de borda de subida ou descida, agrupe a condição de evento com a comparação direta entre parênteses. É comum ocorrerem erros de síntese caso contrário.

Embora as declarações dentro de process sejam executadas em sequência, apenas uma atribuição para cada sinal é feita em cada execução do bloco e todas as atribuições são feitas em paralelo. Veja o exemplo abaixo:

PROCESS(clk)
BEGIN
	A <= ‘1’;
	B <= A;
	A <= ‘0’;
END PROCESS;

Em programação convencional, espera-se que cada declaração seja executada em sequência. Primeiro A recebe o valor 1, depois B recebe o valor de A (ou seja, 1) e, por fim, A recebe o valor 0. Ao fim da execução, espera-se que A tenha o valor 0 e B tenha o valor 1.

Em VHDL, no entanto, não é isso o que ocorre. Apenas uma atribuição a A pode ser feita, portanto somente a última é considerada. Ao fim da execução, A terá o valor 0 e como a atribuição de B é feita em paralelo a de A, B terá o valor que A possuía antes do bloco ser executado.

Por fim, crie mais um arquivo chamado ClkDiv50M.vhd onde será descrito o circuito do divisor de clock.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity ClkDiv50M is
	port(
		rst, clk, en : in std_logic;
		q : out std_logic
	);
end entity;

architecture a_ClkDiv50M of ClkDiv50M is
	signal cnt : integer range 1 to 50000000 := 1;
begin
	process(clk, rst)
	begin
		if rst='1' then
			cnt <= 1;
		elsif (clk'event and clk='1') and en='1' then
			if cnt >= 50000000 then
				cnt <= 1;
			else
				cnt <= cnt + 1;
			end if;
		else
			cnt <= cnt;
		end if;
	end process;
	q <= '1' when en='0' or cnt=50000000 else '0';
end architecture;

Neste código estamos utilizando um pacote novo, também pertencente à biblioteca ieee, o numeric_std. Este pacote define os tipos numéricos e nos permite realizar operações matemáticas.
Na arquitetura do circuito, definimos um sinal do tipo inteiro com alcance de 1 a 50 milhões (pode representar qualquer número dentro deste intervalo). No bloco de processo, incrementamos esse valor a cada pulso de clock até atingir 50 milhões. No próximo pulso de clock, o valor retorna para 1.

Após o bloco process, definimos que a saída (chamada de q) possui valor 1 quando (when) cnt possui valor igual a 50 milhões ou a entrada en é igual a 0 – caso contrário, a saída terá valor 0. Note que a condicional na saída utiliza a palavra when ao invés de if: when é utilizado para multiplexar valores (cria um mutex), é uma lógica combinacional; if, no entanto, é utilizado para lógicas sequências e só pode ser usado dentro de blocos de processo.

A saída do circuito, quando o mesmo está ativo (entrada en, ou enable, igual a 1), só fica ativa a cada 50 milhões de pulsos de clock, considerando clock de 50MHz a saída terá frequência de 1 Hz. É importante ressaltar que, por questões de sincronia, não é aconselhado a utilizar a saída do divisor diretamente como sinal de clock para outros circuitos. O recomendado é que todos os circuitos partilhem o mesmo sinal de clock e que a saída do divisor seja utilizada como sinal de ativação (enable) para os circuitos que operam a 1 Hz. Desta forma, garantimos que todos os circuitos sequências estão sincronizados.

Síntese do Circuito

Finalizada a descrição do circuito, é necessário realizar a síntese. Esse processo converte o código VHDL para um circuito físico que pode ser implementado pela FPGA. Para iniciar a síntese no Quartus, basta clicar no botão Start Analisys & Synthesis no menu de ferramentas, destacado em vermelho na imagem abaixo.

Conheça a FPGA Altera Cyclone II

Uma mensagem de alerta aparecerá informando se o procedimento foi bem sucedido. Caso haja erros, verifique a janela de log na parte inferior – nela constarão informações mais detalhadas dos erros encontrados (o quartus informa apenas um erro por vez, repita o processo de síntese até que não sejam encontrados mais erros), geralmente os erros nesta fase estão relacionados à sintaxe do VHDL.

Após a síntese, podemos visualizar graficamente o circuito clicando em Tools, Netlist Viewers, RTL Viewer. Por padrão é mostrado o circuito da entidade top-level, clique em uma das entidades instanciadas para ver seu circuito interno.

Conheça a FPGA Altera Cyclone II

Circuito da Entidade ClkDiv50M
Circuito da Entidade ClkDiv50M
Circuito da Entidade DecCount_3
Circuito da Entidade DecCount_3

Atribuição de Pinos

Antes de gravarmos o circuito na FPGA, precisamos vincular as entradas e saídas da entidade top-level com os pinos físicos da FPGA. Desta forma o circuito pode se comunicar com exterior. No menu de ferramentas, clique em Pin Planner.

Conheça a FPGA Altera Cyclone II

Uma janela contendo a posição física de cada pino na FPGA e uma lista das entradas e saídas da entidade superior se abrirá. Para associar uma entrada/saída com pino, clique na célula da coluna Location correspondente à porta descrita na coluna Node Name e digite PIN_ seguido pelo número do pino escolhido (estes números estão impressos na parte superior da placa, próximo a seu respectivo conector).

Apesar da EP2C5T144 possuir um grande número de pinos disponíveis (89 utilizáveis), alguns são mais adequados para certos propósitos e a placa de desenvolvimento reserva alguns para comunicação com os hardwares embutidos. Uma lista dos pinos reservados e sua função, da Cyclone II EP2C5 Mini Dev Board, está descrita abaixo:

Pino Função Descrição
3 LED D2 Ativos em nível baixo (GND)
7 LED D4
9 LED D5
144 Push Button Pressione para conectar ao GND. Necessita do Pull-Up interno da FPGA.
17 Clock de 50MHz Sinal de Clock
73 Power On Reset Circuit Utilizado para reset inicial
26 Resistor de zero ohm para 1.2V  Mantidos por questões de compatibilidade com a FPGA EPC28
27 Resistor de zero ohm para GND
80 Resistor de zero ohm para GND
81 Resistor de zero ohm para 1.2V 

Vamos conectar as saídas do circuito aos LEDs (pinos 3, 7 e 9), o n_rst ao push button (pino 144), o n_pwo_rst ao circuito de Power On Reset (pino 73) e o clk à entrada de clock (pino 17). Como mostrado na tabela, o push button necessita de um resistor de Pull-Up, a EP2C conta com Pull-Ups internos. Para ativá-los clique na célula correspondente na coluna Weak Pull-Up Resistor e selecione On. Se essa coluna não for mostrada clique com o botão direito no nome de qualquer coluna e habilite a opção Weak Pull-Up Resistor.

Ao fim da atribuição de pinos, a janela Pin Planner deve estar como mostrado na imagem abaixo.

Conheça a FPGA Altera Cyclone II

Note que na coluna I/O Standard é especificado o nível de tensão dos pinos, apesar de alimentarmos a placa com +5Vcc por padrão as GPIOs operam com 3.3V, assim como uma Raspberry Pi (internamente a FPGA utiliza apenas 1.2V). Certifique-se que os componentes conectados às GPIOs utilizam o nível adequado de tensão, embora seja possível configurar a tensão das GPIOs, a EP2C5T não suporta o nível de 5V.

Compilação

O próximo passo é a compilação. Neste procedimento o circuito é convertido para um série de configurações que devem ser enviadas para a FPGA se reconfigurar como o circuito projetado. Clique no ícone Start Compilation no menu de ferramentas. O processo é semelhante à síntese, mas mais lento (caso o circuito ainda não tenha sido sintetizado, a compilação a realizará automaticamente).

Ao fim, em caso de sucesso, um guia Compilation Report abrirá contendo informações sobre o hardware e a quantidade de recursos da FPGA gastos para configurá-lo. Este circuito requer 44 dos 4608 elementos lógicos e 6 dos 89 pinos disponíveis na EP2C.

Conheça a FPGA Altera Cyclone II

Gravação Temporária

Para realizar a gravação, tanto temporária quanto permanente, precisamos de um gravador compatível. O Gravador Altera USB Blaster é compatível com diversas FPGAs e CPLDs fabricados pela Altera.

Conheça a FPGA Altera Cyclone II

A EP2C5 Mini Board possui dois soquetes para conexão com o gravador, um deles identificado por AS e outro JTAG, na gravação temporária utiliza-se o JTAG.

Conheça a FPGA Altera Cyclone II

Para evitar danificar a FPGA ou o gravador, siga os passos abaixo para conectar o USB Blaster na EP2C Mini Board:

  1. Certifique-se que o cabo de alimentação da FPGA está desconectado;
  2. Conecte o gravador no computador através do cabo USB;
  3. Conecte o gravador na FPGA (interface JTAG);
  4. Conecte o cabo de alimentação da FPGA (5 Vcc para a EP2C).

Para desconectar, basta realizar o processo inverso:

  1. Desconecte a alimentação do dispositivo;
  2. Desconecte o gravador da FPGA;
  3. Desconecte o gravador do computador.

Com a FPGA e o gravador devidamente conectados, clique no ícone Programmer na barra de ferramentas no Quartus:

Conheça a FPGA Altera Cyclone II

Uma janela de configuração se abrirá. Na maioria das vezes o software irá detectar o gravador e ajustar as configurações automaticamente. Caso a configuração automática falhe, primeiro verifique se o campo ao lado do botão Hardware Setup indica USB-Blaster. Caso contrário, clique em Hardware Setup e selecione USB-Blaster em Available Hardware items.

Conheça a FPGA Altera Cyclone II

Na gravação temporária utiliza-se o arquivo .sof, gerado ao compilar o circuito. Caso o arquivo .sof não esteja listado na janela de programação, clique em Add File, entre na pasta output_files (dentro da pasta do projeto) e selecione o arquivo <Nome da Entidade Top-level>.sof. Marque a opção Program/Configure ao lado do nome do arquivo.

Após finalizar as configurações, clique no botão Start para iniciar (a gravação costuma ser bem rápida). Ao terminar, a barra de progresso deve mostrar 100% (Successful) e o circuito já deve começar a se comportar como o esperado.

Conheça a FPGA Altera Cyclone II

Gravação Persistente

Como dito anteriormente, as configurações da FPGA são armazenadas em memórias voláteis. Se desconectarmos a FPGA da energia, toda o configuração será revertida e será necessário programá-la novamente. A placa de desenvolvimento, no entanto, conta com um pequeno dispositivo responsável por reconfigurar a FPGA toda vez que o circuito é alimentado, este pequeno chip na parte traseira da placa:

Conheça a FPGA Altera Cyclone II

Para gravar as informações do circuito no chip, utiliza-se a interface AS ao invés da JTAG. Conecte o gravador seguindo os mesmos passos que a gravação temporária, mas utilizando o soquete AS.

Abra novamente a janela de programação e altere o Mode para Active Serial Programming. Uma mensagem de alerta irá surgir dizendo que o arquivo atual .sof é incompatível com este modo, clique em ok e logo em seguida em Add File, entre na pasta output_files e selecione o arquivo <Nome da Entidade Top-Level>.pof, os arquivos pof são utilizados na configuração persistente.

Conheça a FPGA Altera Cyclone II

Selecione as opções Program/Configure e Verify e clique em Start para iniciar a gravação, geralmente a gravação persistente é mais lenta. Ao fim do processo, em caso de sucesso, a barra de progresso deve mostrar 100% (Successful), diferente da configuração temporária o circuito não deve começar a funcionar imediatamente. Desconecte o gravador, seguindo os passos indicados, e ligue a placa novamente à energia, o circuito deve começar a funcionar, mesmo sem estar conectado ao USB Blaster.

Conheça a FPGA Altera Cyclone II

Conclusão

FPGAs são dispositivos muito interessantes que nos permitem construir praticamente qualquer Hardware Digital, com a vantagem de poder alterar posteriormente o hardware desenvolvido, permitindo a correção e atualização de hardware. Além disso, hardwares re-configuráveis permitem a construção de dispositivos computacionais mais eficientes ao ajustar o hardware à necessidade do software.

A FPGA Altera Cyclone II é uma ótima opção àqueles que estão aprendendo a utilizar FPGAs pelo seu baixo custo e, apesar ser limitada em comparação com outros modelos disponíveis no mercado, permite a implementação de circuitos complexos como processadores.

Gostou da FPGA Altera Cyclone II? Não esqueça de deixar seu comentário logo abaixo.

Faça seu comentário

Acesse sua conta e participe

2 Comentários

  1. Teve um detalhe que não entendi no lay-out do bloco ClkDiv50M: pelo código, cnt recebe cnt+1 enquanto não superar 50 milhões, ou recebe 1 caso a contagem tiver atingido 50 milhões, que está correto. Mas no lay-out, o MUX 2×1 escolhe a entrada (cnt+1) enquanto não superar 50 milhões, ou escolhe o hexa h2000000, que equivale ao decimal 3355443….Não consegui entender…

  2. Muito bom este teu post Matheus, parabéns. Esclareceu as dúvidas que eu tive na outra postagem sobre a construção do jogo PONG com FPGA. A capacidade destas FPGAs é realmente enorme, e é bem interessante a forma como se consegue viabilizar circuitos complexos através de blocos padrão mais simples. Mas por outro lado a FPGA acaba usando bem mais portas lógicas do que se fosse implementado um circuito dedicado. Um exemplo é o bloco ClkDiv50M. Um circuito dedicado implementaria ele com um contador convencional 24bits mais um mínimo de portas para resetar a contagem ao atingir 50 milhões. E dentro da FPGA ele é implementado usando um registrador 24 bits, mais um somador 24 bits, mais um comparador de igualdade 24 bits, mais um módulo LessThan 24 bits (basicamente um subtrator), mais um MUX2x1 24 bits, ou seja, deve usar 4 ou 5 vezes mais portas lógicas do que o circuito dedicado…