Este tutorial irá descrever um método de leitura de um encoder industrial, em alta resolução, utilizando um dispositivo denominado FPGA (Field Programable Gat Array) ou, em português, Arranjo de Portas Programáveis em Campo que nada mais é do que um hardware configurável.
Esta arquitetura de trabalho é adotada por grandes empresas de dispositivos ligados a automação e controle industrial como Siemens, Rexroth Indramat, Fagor, Heidenhain dentre outras e garante que nenhum pulso provindo do encoder deixe de ser registrado e consequentemente garantindo uma melhor leitura e controle.
MATERIAIS
- (1x) Plataforma de desenvolvimento com FPGA (Xilinx ou Altera);
- (1x) Conversor de nível TTL de 5V p/ 3V3;
- (1x) Encoder de Quadratura, saída TTL (Utilizado o ROD 426 Heidenhain);
- (1x) Protoboard;
- Cabos para ligação em protoboard.
FPGA
O FPGA é um dispositivo que suporta a implementação de circuitos digitais em um arranjo de células lógicas ou blocos configuráveis, contidos em um único circuito integrado. Cada célula contém capacidade computacional para implementar funções lógicas e realizar roteamento para comunicação entre elas. O primeiro FPGA disponível comercialmente foi desenvolvido pela empresa Xilinx Inc, em 1983.
Um FPGA basicamente é constituído por blocos lógicos, blocos de entrada e saída, e chaves de interconexão. Os blocos lógicos formam uma matriz bidimensional, e as chaves de interconexão são organizadas como canais de roteamento horizontal e vertical entre as linhas e colunas dos blocos lógicos. Os canais de roteamento possuem chaves de interligação programáveis que permitem conectar os blocos lógicos de maneira conveniente, em função das necessidades de cada projeto. Na figura abaixo indicamos um exemplo de arranjo interno de um FPGA.
No interior de cada bloco lógico do FPGA existem vários modos possíveis para implementação de funções lógicas. O mais utilizado pelos fabricantes de FPGA é o bloco de memória LUT (Look-Up Table). Esse tipo de bloco lógico contém células de armazenamento que são utilizadas para implementar pequenas funções lógicas. Cada célula é capaz de armazenar um único valor lógico sendo ele zero ou um. A figura abaixo ilustra a estrutura das LUT’s e outros componentes.
Nos FPGAs disponíveis comercialmente, os blocos lógicos LUTs possuem geralmente quatro ou cinco entradas, o que permite endereçar 16 ou 32 células de armazenamento. Quando um circuito lógico é implementado em um FPGA, os blocos lógicos são programados para realizar as funções necessárias, e os canais de roteamento são estruturados de forma a realizar a interconexão necessária entre os blocos lógicos e assim sintetizar o hardware de interesse.
As células de armazenamento dos LUTs de um FPGA são voláteis, o que implica perda do conteúdo armazenado, no caso de falta de suprimento de energia elétrica. Dessa forma, o FPGA deve ser programado toda vez que for energizado. Geralmente utiliza-se uma pequena memória FLASH EEPROM (Electrically Erasable Programmable Read Only Memory) cuja função é carregar automaticamente as células de armazenamento, toda vez que o FPGA for energizado. A figura abaixo ilustra a memória EEPROM utilizada para configurar o FPGA, montada na placa Nexys 2.
A arquitetura de roteamento de um FPGA é a forma pela qual os seus barramentos e as chaves de comutação são posicionados para permitir a interconexão entre as células lógicas. Essa arquitetura deve permitir que se obtenha um roteamento completo e, ao mesmo tempo, uma alta densidade de portas lógicas. Para uma melhor compreensão dessa arquitetura é necessária a definição de alguns conceitos como:
- Pinos: entradas e saídas dos blocos lógicos.
- Conexão: ligação elétrica de um par de pinos.
- Rede: um conjunto de pinos que estão conectados.
- Segmento de trilha: segmento não interrompido por chaves programáveis.
- Bloco de Comutação: utilizado para conectar dois segmentos de trilha.
- Canal de roteamento: grupo de duas ou mais trilhas paralelas.
- Bloco de conexão: permite a conectividade das entradas e saídas de um bloco lógico com os segmentos de trilhas nos canais.
As chaves programáveis de roteamento apresentam algumas propriedades, tais como, tamanho, resistência, capacitância e tecnologia de fabricação, que afetam principalmente a velocidade e o tempo de propagação dos sinais, e definem características como volatilidade e capacidade de reprogramação. Na escolha de um dispositivo reconfigurável, esses fatores devem ser avaliados. Basicamente existem três tipos de tecnologia de programação das chaves de roteamento:
a) SRAM (Static Random Access Memory): nessa tecnologia, a chave de roteamento ou comutador é um transistor de passagem ou um multiplexador controlado por uma memória estática de acesso aleatório SRAM. Devido à volatilidade dessas memórias, os FPGAs que se utilizam dessa tecnologia precisam de uma memória externa tipo FLASH EEPROM. Essa tecnologia ocupa muito espaço no circuito integrado, entretanto é rapidamente reprogramável.
b) Antifuse: essa tecnologia baseia-se num dispositivo de dois terminais, que no estado não programado apresenta uma alta impedância (circuito aberto). Aplicando-se uma tensão, por exemplo, entre 11 e 20 Vdc, o dispositivo forma um caminho de baixa impedância entre seus terminais.
c) Gate flutuante: a tecnologia Gate flutuante baseia-se em transistores MOS (Metal Oxide Semiconductor), especialmente construído com dois gates flutuantes semelhantes aos usados nas memórias EPROM (Erasable Programmable Read Only Memory) e EEPROM (Electrical EPROM). A maior vantagem dessa tecnologia é a sua capacidade de programação e a retenção dos dados. Além disso, da mesma forma que uma memória EEPROM, os dados podem ser programados com o circuito integrado instalado na placa, característica denominada ISP (In System Programmability).
Outra vantagem em relação ao uso dos FPGA é a facilidade e versatilidade na síntese do circuito digital. Podemos utilizar a linguagem de descrição utilizando blocos digitais, VHDL ou Verilog. Este tutorial utilizou a linguagem VHDL mas a descrição a ser apresentada pode ser convertida em Verilog com o mínimo de esforço.
FPGA x Microcontroladores
Primeiramente, é importante destacar que estes são dispositivos completamente diferentes. Em um microcontrolador como o Atmel 328 utilizado na plataforma Arduino, o chip já está desenvolvido e pronto para a aplicação. O usuário simplesmente desenvolve um algoritmo em C/C++, compila e carrega em uma memória flash o arquivo .HEX resultante da compilação. Este programa ficará armazenado enquanto não houver uma reprogramação ou até que a memória seja limpa. Resumindo, obtemos controle sobre o microcontrolador através do software.
FPGA’s são dispositivos completamente diferentes. Em vez de obter um circuito já pronto, nos FPGA o usuário é que irá gerar o circuito interno a pastilha. Não há nenhum processador, memória ou periféricos já prontos a não ser que o usuário desenvolva um. Podemos desenvolver um circuito que seja simples como uma porta lógica AND ou mesmo um circuito mais complexo como um processador multicore.
Para criar os circuitos, é utilizada uma HDL (linguagem de descrição de hardware). As duas formas mais utilizadas para descrever o hardware é o VHDL ou o Verilog. Após a descrição, o usuário utiliza a ferramenta de síntese que converte o comportamento do hardware para o formato .bit que é então carregado na memória RAM do FPGA. Por isso a necessidade de uma memória externa como a indicada na figura acima. Resumindo, nos FPGA’s o controle é feito no Hardware.
Outro fato interessante sobre os FPGA’s é que quando o usuário está projetando o hardware a ser sintetizado, ele tem a possibilidade de desenvolver um processador para receber um software de uma linguagem padrão como C ou assembler. De fato, empresas que desenvolvem circuitos digitais como a Intel, nVidia e outras, utilizam um FPGA para prototipar os circuitos ou processadores antes mesmo de irem a linha de produção como um circuito dedicado.
IMPLEMENTAÇÃO
A implementação deste protótipo seguiu uma linha de abordagem onde os sinais provindos do encoder deveriam ser ajustados ao nível suportado pelo FPGA, no caso de 5V para 3V3, tratados recebendo um filtro de debaunce para eliminar ruído no acionamento e consequentemente contabilizados de acordo com número de pulsos em relação ao ponto inicial e indicados em um display de 7 seguimentos com 4 digitos de contagem. Utilizamos a linguagem de descrição de Hardware VHDL para esta implementação.
Em VHDL, a descrição de comportamento do circuito deve obedecer alguns critérios de construção para facilitar a elaboração e o entendimento de outras pessoas. Ela é dividida em módulos, sendo que cada módulo pode utilizar submódulos e deve possuir obrigatoriamente uma Entidade (Entity), que define o sentido das portas (entrada, saída, buffer, barramento entre outros) e variáveis genéricas a descrição, e uma arquitetura (Architecture) que define o comportamento do módulo.
Quando utilizamos mais de um módulo, como foi o caso deste trabalho, devemos definir uma entidade top (Top Entity) que descreve a ligação entre os módulos. A figura abaixo ilustra a hierarquia do projeto, que foi elaborado utilizando a versão Web Pack do software ISE Design Suite da Xilinx na versão v14.1.
Na imagem abaixo, é ilustrada a visualização do esquemático do sistema, onde os sub-blocos são indicados subsequentemente.
Dentro de cada módulo, representado na imagem acima, temos a descrição do comportamento individual daquele módulo. Se o mesmo utilizar um outro módulo para uma determinada tarefa, o mesmo deve ser instanciado como um módulo componente. Este procedimento indica para a ferramenta de síntese que o modulo em questão faz o uso de sinais provenientes de um módulo externo. A diretiva port map() estabelece a ligação entre os módulos. A imagem abaixo ilustra a implementação da tecnologia dentro do FPGA.
Como exemplo de aplicação, no módulo cujo o nome da entidade é Encoder_Counter e está descrita logo abaixo, o resultado da contagem dos pulsos de rotação do encoder é repassado ao conversor BCD através de um sinal interno denominado signal encoderOut. Os sinais são variáveis que podem ter seu valor alterado tanto em áreas de concorrência no processamento quanto nas áreas de processamento sequencial. Para maiores informações sobre as diretivas de síntese de hardware utilizando VHDL, recomenda-se a leitura do livro “VHDL Descrição e Síntese de Circuitos Digitais, 2 Edição, Roberdo d’Amore”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
---------------------------------------------------------------------------------- -- Company: EasyTrom Labs -- Engineer: Eduardo Avelar -- Create Date: 11:35:04 10/13/2018 -- Design Name: Leitura de Encoder e Display -- Module Name: Encoder_Counter - Behavioral ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; use IEEE.STD_LOGIC_unsigned.ALL; use IEEE.STD_LOGIC_ARITH.ALL; entity Encoder_Counter is Port ( fpga_clk : in STD_LOGIC; -- Sinal de entrada do clock (MHz) encoder_A : in STD_LOGIC; -- Sinal de entrada do encoder A encoder_B : in STD_LOGIC; -- Sinal de entrada do encoder B reset_mod : IN STD_LOGIC; -- Reset em nível baixo e assincrono ena_mod : IN STD_LOGIC; -- Habilita a conversão busy_mod : OUT STD_LOGIC; -- Indica conversao em processo milhar_mod : out STD_LOGIC_VECTOR (3 downto 0); -- Dígito Milhar do módulo Nexys 2 centenas_mod : out STD_LOGIC_VECTOR (3 downto 0); -- Dígito Centena do módulo Nexys 2 dezenas_mod : out STD_LOGIC_VECTOR (3 downto 0); -- Dígito Dezena do módulo Nexys 2 unidades_mod : out STD_LOGIC_VECTOR (3 downto 0)); -- Dígito Unidade do módulo Nexys 2 end Encoder_Counter; architecture Behavioral of Encoder_Counter is component BCD_converter IS GENERIC( bits : INTEGER := 13; -- Tamanho dos bits de contagem dos pulsos 0 - 12 = 1 a 8192 ou 0 a 8191 digits : INTEGER := 4 ); -- Numero de digitos no display do módulo PORT( clk : IN STD_LOGIC; -- Clock do sistema ( MHz) reset_n : IN STD_LOGIC; -- Reset em nível baixo ena : IN STD_LOGIC; -- Habilita a conversão binary : IN STD_LOGIC_VECTOR(bits-1 DOWNTO 0); -- Número binário para converter para BCD busy : OUT STD_LOGIC; -- Indica conversão habilitada e em processo contínuo bcd : OUT STD_LOGIC_VECTOR(digits*4-1 DOWNTO 0)); -- Resultado da conversao BCD END component; component Encoder_Rotativo_Teste is Port ( rotary_a : in STD_LOGIC; rotary_b : in STD_LOGIC; reset_n : IN STD_LOGIC; -- Reset Assincrono - LOW ena : IN STD_LOGIC; -- Habilita contagem rotate_counter_out : out STD_LOGIC_VECTOR (12 downto 0); clk : in STD_LOGIC ); end component; signal encoderOut : std_logic_vector(12 downto 0); -- Sinal para conexão entre módulos signal bcd : STD_LOGIC_VECTOR(15 DOWNTO 0); -- Sinal para conexão entre modulos armezanamento do resultado da conversão begin unidades_mod <= bcd(3 downto 0); dezenas_mod <= bcd(7 downto 4); centenas_mod <= bcd(11 downto 8); milhar_mod <= bcd(15 downto 12); -- Realiza a conexão entre os módulos BCDConv : BCD_converter port map( clk => fpga_clk, reset_n => reset_mod, ena => ena_mod, binary => encoderOut, busy => busy_mod, bcd => bcd ); -- Realiza a conexão entre os módulos Encoder_value : Encoder_Rotativo_Teste port map( clk => fpga_clk, rotary_a => encoder_A, rotary_b => encoder_B, reset_n => reset_mod, ena => ena_mod, rotate_counter_out => encoderOut ); end Behavioral; |
DESCRIÇÃO DO HARDWARE
Como mencionado anteriormente, o hardware abordado neste tutorial foi descrito utilizando a linguagem VHDL. Uma observação importante a destacar nesta etapa é que a curva de aprendizado para elaboração de sínteses de circuitos digitais é longa e trabalhosa. A linguagem VHDL não é considerada a mais simples para esta tarefa, porém, apresenta as melhores possibilidades de otimização e controle da forma como a síntese irá ocorrer.
Quando o usuário decide trabalhar com FPGA, o primeiro passo deve ser elaborar um rascunho com um esquemático representando os blocos do sistema e suas funções. Após esta etapa, deve-se iniciar a elaboração dos blocos menores do sistema, aqueles que serão utilizados por outros módulos. Sequencialmente descreve-se elaborar os módulos maiores e a entidade top, que tem como função interligar os módulos na “árvore” de hierarquia.
Uma simulação do comportamento de cada bloco, utilizando ferramenta de simulação, observando os resultados esperados, também é uma boa prática nos trabalho com FPGA.
ESQUEMA DE LIGAÇÃO
O esquema de montagem deste tutorial é bem simples levando em conta somente o lado de conexão do encoder até a Nexys 2. O diagrama está indicado na figura abaixo. Devemos atentar para a conversão de nível de tensão de 5V para 3V3 suportados pelo FPGA.
Outro ponto a ser observado é que a Nexys 2 já apresenta em seus terminais de interface externa um diodo de proteção contra ESD e resistores de proteção contra curto circuito. Outros dispositivos de proteção e filtro do sinal também seriam necessários em um projeto definitivo, que não é o escopo deste tutorial. Este esquemático pode ser observado na imagem abaixo.
E na figura abaixo, o esquema de ligação do display de 7 segmentos, das chaves, dos botões e dos LED’s retirado do manual da plataforma junto a Digilent.
ALGORÍTMO
Como mencionado anteriormente, algoritmo não é o termo mais indicado quando se trabalha com FPGA. O certo é mencionar como “Descrição do Hardware” mas como existe uma tradição neste site em indicar o tópico onde temos o código fonte como Algorítmo, assim o fazemos também neste. Observem que este sistema possui uma alta resolução nas contagens pois apanha o sinal na borda de subida e na borda de descida de cada pulso. Como o encoder é do tipo de 1024 pulsos por revolução, somente naborda de subida do sinal, se trabalharmos da forma anterior teremos 4096 pulsosem apenas uma rotação completa do eixo do encoder.
A descrição da entidade TOP está indicada abaixo. Os outros módulos estão disponíveis no repositório indicado neste link. O arquivo de construção .ucf que indica a ligação com as portas do FPGA também encontra-se neste repositório.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
---------------------------------------------------------------------------------- -- Company: EasyTrom Labs -- Engineer: Eduardo Avelar -- Create Date: 11:54:20 10/13/2018 -- Design Name: Leitura de Encoder e Display -- Module Name: Top_Encoder_Module - Behavioral ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity Top_Encoder_Module is Port ( top_enc_a : in std_logic; -- Entrada do canal A do encoder top_enc_b : in std_logic; -- Entrada do canal B do encoder top_clk : in STD_LOGIC; -- Clock da placa 50 Mhz top_reset : in STD_LOGIC; -- Reset em nível baixo top_enable : in STD_LOGIC; -- Habilita a conversão top_busy : out STD_LOGIC; -- Indica conversão em processo top_selDispA : out STD_LOGIC; -- Pino de seleção do diaplay A top_selDispB : out STD_LOGIC; -- '' '' B top_selDispC : out STD_LOGIC; -- '' '' C top_selDispD : out STD_LOGIC; -- '' '' D top_segA : out STD_LOGIC; -- Pino do segmento A top_segB : out STD_LOGIC; -- '' '' B top_segC : out STD_LOGIC; top_segD : out STD_LOGIC; top_segE : out STD_LOGIC; top_segF : out STD_LOGIC; -- '' '' G top_segG : out STD_LOGIC ); end Top_Encoder_Module; architecture Behavioral of Top_Encoder_Module is component Encoder_Counter is Port ( fpga_clk : in STD_LOGIC; -- Sinal de entrada do clock (MHz) encoder_A : in STD_LOGIC; -- Sinal de entrada do encoder A encoder_B : in STD_LOGIC; -- Sinal de entrada do encoder B reset_mod : IN STD_LOGIC; -- Reset em nível baixo ena_mod : IN STD_LOGIC; -- latches in new binary number and starts conversion busy_mod : out STD_LOGIC; -- indicates conversion in progress milhar_mod : out STD_LOGIC_VECTOR (3 downto 0); -- Dígito Milhar do módulo centenas_mod : out STD_LOGIC_VECTOR (3 downto 0); -- Dígito Centena do módulo dezenas_mod : out STD_LOGIC_VECTOR (3 downto 0); -- Dígito Dezena do módulo unidades_mod : out STD_LOGIC_VECTOR (3 downto 0)); -- Dígito Unidade do módulo end component; -- declaração do módulo para comandar o display de 7 segmentos component Segment_Driver is Port ( display_A : in STD_LOGIC_VECTOR (3 downto 0); display_B : in STD_LOGIC_VECTOR (3 downto 0); display_C : in STD_LOGIC_VECTOR (3 downto 0); display_D : in STD_LOGIC_VECTOR (3 downto 0); segA : out STD_LOGIC; segB : out STD_LOGIC; segC : out STD_LOGIC; segD : out STD_LOGIC; segE : out STD_LOGIC; segF : out STD_LOGIC; segG : out STD_LOGIC; Select_Display_A : out STD_LOGIC; Select_Display_B : out STD_LOGIC; Select_Display_C : out STD_LOGIC; Select_Display_D : out STD_LOGIC; clk : in STD_LOGIC ); end component; -- Declaração de sinais para conectar os módulos signal Ai : std_logic_vector(3 downto 0); signal Bi : std_logic_vector(3 downto 0); signal Ci : std_logic_vector(3 downto 0); signal Di : std_logic_vector(3 downto 0); signal top_milhar : std_logic_vector(3 downto 0); signal top_centena : std_logic_vector(3 downto 0); signal top_dezena : std_logic_vector(3 downto 0); signal top_unidade : std_logic_vector(3 downto 0); begin -- Estabelece o link utilizando os sinais e entradas/saídas deste módulo uut2 : segment_driver port map( display_A => Ai, display_B => Bi, display_C => Ci, display_D => Di, segA => top_segA, segB => top_segB, segC => top_segC, segD => top_segD, segE => top_segE, segF => top_segF, segG => top_segG, Select_Display_A => top_selDispA, Select_Display_B => top_selDispB, Select_Display_C => top_selDispC, Select_Display_D => top_selDispD, clk => top_clk ); uut4 : Encoder_Counter port map( fpga_clk => top_clk, encoder_A => top_enc_a, encoder_B => top_enc_b, reset_mod => top_reset, ena_mod => top_enable, busy_mod => top_busy, milhar_mod => top_milhar, centenas_mod => top_centena, dezenas_mod => top_dezena, unidades_mod => top_unidade ); -- Utiliza os sinais declarados para conexão entre a saída do modulo segment -- Driver para o modulo TOP Ai <= top_unidade; Bi <= top_dezena; Ci <= top_centena; Di <= top_milhar; end Behavioral; |
CONCLUSÃO
Neste tutorial discutimos a implementação de um sistema de leitura de encoder industrial em alta resolução utilizando um FPGA. Como mencionado anteriormente, esta arquitetura de sistema é adotada por grandes companhias de automação e fabricantes de equipamentos de posicionamento industrial e garante que nenhum pulso do encoder seja perdido, principalmente devido a velocidade de processamento das informações, que no caso desta aplicação acontecem de forma paralela, e pela versatilidade de construção do FPGA.
No próximo tutorial envolvendo FPGA, trabalharemos com a leitura de mais de um encoder e indicaremos em um display de LCD, de forma simultânea.
08/08/2021 at 03:43
Boa noite, muito bom o conteúdo do seu blog.
Você poderia subir os arquivos novamente para o link que você disponibilizou no texto?
Está retornando erro 404: “O URL solicitado não foi encontrado neste servidor.”
11/11/2021 at 09:53
Olá Jorge.
Me desculpe na demora da resposta.
Eu criei um repositorio para este projeto no github
https://github.com/Eduardo-Avelar/FPGA-Lab-01-EasyTromLabs
Espero ter ajudado.
Até mais.
28/10/2018 at 23:35
Parabéns, a sua explicação do projeto valeu por uma aula do que é e como funciona uma FPGA.
É um grande incentivo par quem quiser se aprofundar nessa tecnologia. Obrigado!
29/10/2018 at 12:22
Olá Afonso,
Obrigado pelos Elogios.
Continue acompanhando o blog e divulgue a quem achar necessário.
Abraço.
28/10/2018 at 11:24
Muito bom ! Parabéns e obrigado por compartilhar.
28/10/2018 at 22:45
Olá José Gustavo.
Obrigado pelo comentário.
Continue nos acompanhando.
Abraco.