Upload
phungtram
View
216
Download
0
Embed Size (px)
Citation preview
CENTRO FEDERAL DE EDUCAÇÃO TECNOLÓGICA CELSO
SUCKOW DA FONSECA – CEFET/RJ
GERADOR DE PULSOS DIGITAIS E
INTERFACE SERIAL PARA CONTROLE
IMPLEMENTADOS EM FPGA
Maurício Féo Pereira Rivello de Carvalho
Rio de Janeiro
Julho 2013
I
CENTRO FEDERAL DE EDUCAÇÃO TECNOLÓGICA CELSO
SUCKOW DA FONSECA – CEFET/RJ
GERADOR DE PULSOS DIGITAIS E
INTERFACE SERIAL PARA CONTROLE
IMPLEMENTADOS EM FPGA
Maurício Féo Pereira Rivello de Carvalho
Projeto Final apresentado em comprimento às normas do Departamento de Educação Superior do CEFET-RJ, como parte dos requisitos como obtenção do título de Engenharia Eletrônica.
Prof. Orientador: Jesse Costa
Prof. Co-Orientador: André Massafferri
Rio de Janeiro
Julho 2013
III
DEDICATÓRIA
À Deus: “Porque dEle e por Ele, e para Ele, são todas as coisas; glória, pois, a Ele eternamente. Amém.” Romanos 11:36 À minha esposa Raquel, por ser minha motivação, minha inspiração, minha alegria, minha vida.
IV
AGRADECIMENTOS
Agradeço primeiramente aos meus pais Osvaldo e Laís, pelo apoio incondicional e por terem tornado esta conquista possível. Em especial aos meus orientadores Jesse Costa e André Massafferri, pois sem eles esse trabalho não teria sido realizado. Aos amigos e colegas de faculdade, por tantas horas de aprendizado compartilhadas e os desafios que enfrentamos juntos.
V
RESUMO
No estudo de física de partículas de alta energia se faz necessário o uso de pesada
instrumentação com um número elevado de sensores e equipamentos de medição para que
todo fenômeno físico de interesse possa ser apropriadamente registrado e medido. A
eletrônica de front-end é responsável pela amplificação e digitalização dos sinais analógicos
provenientes dos sensores, e os módulos de aquisição são responsável pela aquisição e
processamento inicial destes sinais após serem digitalizados.
Quando há a necessidade de validação ou teste dos módulos de aquisição de dados, é
necessário ter a noção ou preferencialmente conhecer por completo o sinal de entrada para
inferirmos se este está sendo captado e processado corretamente pelos módulos de aquisição.
Desta necessidade surgiu a idéia do projeto de um gerador de sinais digitais com o objetivo de
simular os sinais de entrada que os módulos de aquisição receberiam em sua condição normal
de operação.
Neste contexto, foi desenvolvido e implementado em FPGA um gerador de pulsos
digitais, com parâmetros controlados por software em computador sendo estes a largura de
pulso, o período, a defasagem entre cada canal e o número de pulsos a serem enviados cada
vez que o gerador for engatilhado. Por ter sido usado estrutura FPGA, o bloco do gerador
pode ser replicado por quantos canais forem necessários dentro das limitações do FPGA. O
gerador foi implementado com sucesso e seu desempenho foi satisfatório para a aplicação em
questão, que é o teste e diagnóstico de módulos de aquisição de dados, usados em montagens
de medição de partículas de altas energias.
VI
ABSTRACT
In the study of high energy particle physics is required the use of heavy
instrumentation with a large number of sensors and measuring equipment so that all physical
phenomena of interest can be properly recorded and measured. The front-end electronics is
responsible for amplification and digitization of analog signals from the sensors and the
acquisition modules are responsible for the acquisition and initial processing of these signals
after they are digitalized.
When there is a need for validation or testing of the data acquisition modules, it is
necessary to know the input signal in order to infer whether it is being properly captured and
processed by the acquisition modules or not. From this need arose the idea of the design of a
digital signal generator in order to simulate the input signals that the acquisition modules
receive in its normal operating condition.
In this context, we developed and implemented in FPGA, a digital pulse generator
with parameters controlled by computer software, which are pulse width, period, the gap
between each channel and the number of pulses to be sent each time the generator is
triggered. Because a FPGA structure was used, the generator block can be replicated by how
many channels are needed within the limitations of the FPGA. The generator has been
successfully implemented and its performance was satisfactory for the currently application,
which is test and diagnostic of data acquisition modules used in measurement of high energy
particles.
VII
SUMÁRIO
DEDICATÓRIA .................................................................................................................................... III
AGRADECIMENTOS ........................................................................................................................... IV
RESUMO ................................................................................................................................................ V
ABSTRACT ........................................................................................................................................... VI
SUMÁRIO ............................................................................................................................................ VII
LISTA DE FIGURAS ............................................................................................................................ IX
Capítulo 1 ................................................................................................................................................ 1
1.Introdução ............................................................................................................................................ 1
1.1 Contextualização .................................................................................................................... 1
1.1.1 O CERN ................................................................................................................................ 1
1.1.2 O CBPF ................................................................................................................................. 2
1.2 Motivação e justificativa do trabalho .................................................................................... 2
1.3 Objetivo .................................................................................................................................. 4
1.4 Metodologia e Trabalho Realizado ........................................................................................ 4
Capítulo 2 ................................................................................................................................................ 6
2. Primeira Versão do Gerador........................................................................................................... 6
2.1 Especificações do Projeto ....................................................................................................... 7
2.2 Plataforma V1495 ................................................................................................................... 7
2.3 Interface de Acesso aos módulos VME ................................................................................ 10
2.3.1 Interface de Hardware ................................................................................................. 10
2.3.2 Interface de Software ................................................................................................... 12
2.4 Desenvolvimento e Funcionamento do Gerador ................................................................ 13
2.5 Software de Controle ........................................................................................................... 16
2.6 Limitações ............................................................................................................................. 16
Capítulo 3 .............................................................................................................................................. 18
3. Segunda Versão do Gerador ........................................................................................................ 18
3.1. Especificações do Projeto ..................................................................................................... 18
3.2 Placa de Desenvolvimento LX9 MicroBoard ........................................................................ 19
3.3 FPGA ...................................................................................................................................... 20
3.4 Projeto Síncrono vs Assíncrono ............................................................................................ 23
3.5 Visão Geral da Top Level Entity ............................................................................................ 24
3.6 Gerador Controlável ............................................................................................................. 26
3.6.1 Delayer .............................................................................................................................. 28
VIII
3.6.2 Pulses Counter .................................................................................................................. 29
3.6.3 Generator Unit .................................................................................................................. 31
3.7 Interface Serial UART ............................................................................................................ 32
3.7.1 Protocolo Serial................................................................................................................. 33
3.7.2 Unidade Rx ........................................................................................................................ 34
3.7.3 Unidade Tx ........................................................................................................................ 36
3.8 Entidade Top Level ............................................................................................................... 38
3.9 Software para Controle ........................................................................................................ 39
Capítulo 4 .............................................................................................................................................. 42
4. Conclusão ...................................................................................................................................... 42
Referências bibliográficas .................................................................................................................... 45
APÊNDICE ........................................................................................................................................... 46
Apêndice I: Código fonte da entidade de nível superior ................................................................... 46
Apêndice II: Código fonte do Gerador de Pulsos.............................................................................. 51
Apêndice III: Código fonte da unidade Delayer ............................................................................... 54
Apêndice IV: Código fonte da Generator Unit ................................................................................. 55
Apêndice V: Código fonte da N_Unit ............................................................................................... 56
Apêndice VI: Código fonte do Receptor UART ............................................................................... 58
Apêndice VII: Código fonte do Transmissor UART ........................................................................ 60
Apêndice VIII: Código fonte da unidade Single Pulser .................................................................... 62
IX
LISTA DE FIGURAS
Figura 1: Cadeia de aceleração do LHC ..................................................................................... 1
Figura 2: Módulo VME V1495 .................................................................................................. 8
Figura 3: Diagrama de blocos do módulo V1495....................................................................... 9
Figura 4: Parte frontal do módulo V1495. ................................................................................ 11
Figura 5: Representação em bloco simplificado do primeiro gerador...................................... 14
Figura 6: Esboço do diagrama de blocos do primeiro gerador. ................................................ 15
Figura 7: Vista superior da placa de desenvolvimento LX9 MicroBoard. ............................... 20
Figura 8: Arquitetura padrão de um FPGA moderno. .............................................................. 21
Figura 9: Diagrama de blocos da entidade de nível superior do gerador. ................................ 25
Figura 10: Representação do bloco da segunda versão do gerador. ......................................... 26
Figura 11: Diagrama de blocos da segunda versão do gerador. ............................................... 28
Figura 12: Ilustração do funcionamento do bloco delayer. ...................................................... 29
Figura 13: Ilustração do funcionamento da unidade pulses conter. ......................................... 30
Figura 14: Ilustração do funcionamento da unidade geradora. ................................................ 32
Figura 15: Placa Avnet LX9 conectada à USB pela porta UART............................................ 33
Figura 16: Configuração do protocolo UART usada no projeto. ............................................. 34
Figura 17: Diagrama de estados da máquina de estado da unidade UART receptora. ............. 35
Figura 18: Interface gráfica do aplicativo de controle do gerador. .......................................... 40
Figura 19: Verificação da saída de 4 canais utilizando um osciloscópio digital. ..................... 43
Figura 20: Software de controle do gerador. ............................................................................ 44
1
1
Capítulo 1
1.Introdução
O presente projeto descreve a idealização, projeto e implementação, e características
de funcionamento de um gerador de pulsos implementado em FPGA e controlável através de
interface serial universal assíncrona implementando o protocolo RS-232 e uma versão anterior
projetada especificamente para utilização em um módulo VME modelo V1495 de fabricação
CAEN ou similar.
1.1 Contextualização
1.1.1 O CERN
Atualmente o CERN (Centro Europeu de Pesquisa Nuclear) é um dos centros de
pesquisa de maior relevância no mundo. Nele é encontrado o LHC (Grande Colisor de
Hádrons), que é o maior acelerador de partículas já construído até o presente momento.
Figura 1: Cadeia de aceleração do LHC
2
Ao longo de um túnel de 27km de circunferência há 2 canais por onde passa, em
direções opostas, feixes de partículas. Em 4 pontos diferentes há o cruzamento destes feixes,
onde ocorrem as colisões. Nestes pontos há grande estrutural e aparato para controle das
colisões e medição dos eventos e partículas consequentes das colisões.
Nestes quatro pontos é onde ocorrem as experiências do LHC, cada uma com estrutura
e objetivos diferentes, as quais são: ALICE (Grande Colisor de Íons), ATLAS (Aparato
Toroidal do LHC), CMS (Solenoide Compacto de Múons) e LHCb (LHC-beauty).
Em cada uma dessas experiências há um grande número de sensores que geram sinais
elétricos de diversas formas representando sua medição. São milhares de sensores,
organizados em camadas, com diferentes aplicações, desde medir o nível energético de uma
partícula passante até rastrear a trajetória percorrida por dada partícula. Por trás destes
sensores há uma eletrônica muito complexa envolvida, cujo objetivo é fazer a leitura dos
sinais destes sensores, processar, filtrar os sinais de interesse e enviar os dados para serem
armazenados em computadores para mais tarde poderem ser analisados por softwares e
pessoas competentes.
A eletrônica que faz a aquisição dos dados varia de acordo com o tipo de sensor,
experiência e volume de dados. Um dos tipos existentes é o padrão VME, que são
organizados em caixas chamadas “Crate” onde são conectados módulos que desempenham
diversas funções e todos podem se comunicar entre si por um barramento que interliga todos
os módulos de um mesmo crate. Para a primeira versão do gerador foi utilizado um desses
módulo com um chip de lógica programável, para podermos configurá-lo conforme a
aplicação desejada.
1.1.2 O CBPF
O Centro Brasileiro de Pesquisas Físicas (CBPF) é um instituto de pesquisa do
Ministério da Ciência e Tecnologia (MCT) do Brasil. Atualmente é um centro de referência
em Física. Nele há vários trabalhos sendo realizados em cooperação com projetos
desenvolvidos no CERN.
1.2 Motivação e justificativa do trabalho
O Laboratório Multiusuário de Física de Altas Energias da Coordenação de Física
Experimental de Altas Energias (LAFEX), no Centro Brasileiro de Pesquisas Físicas (CBPF),
contém atualmente duas montagens experimentais vinculadas às experiências LHCb e CMS,
3
do LHC. Na montagem da experiência do LHCb está sendo montado um sistema de detecção
de múons cósmicos (partículas atômicas vindas do espaço que atingem a Terra a todo o
momento) que utilizará câmaras proporcionais e cintiladores plásticos como sensores de
detecção de partículas. Tanto para detecção de raios cósmicos como para colisão em
aceleradores de partículas como o LHC, o sinal de saída dos sensores são pulsos elétricos
analógicos que são amplificados e digitalizados por um conjunto de componentes eletrônicos
a qual chamamos de eletrônica de front-end. A estrutura usada para experimentos como os
realizados no LHCb dispõe de um grande número de sensores, de vários tipos e funções, os
quais geram milhares de sinais a cada evento, que no LHC, por exemplo, ocorre a cada 25ns
(ou a 40MHz) resultando em milhares de canais gerando pulsos na ordem dos milhões a cada
segundo. Circunstâncias como essa exigem processamento paralelo e por isso são utilizados
módulos de aquisição específicos, com alta resolução temporal e comumente baseados em
FPGA (Field Programmable Gate Arrays ou Arranjo de Portas Programável em Campo).
A montagem da experiência LHCb para detecção de raios cósmicos no CBPF conta
com sensores do tipo câmara de gás. Estes sensores são câmaras com gases que são ionizados
com a passagem de uma partícula cósmica e que ocasionam o surgimento de uma corrente
elétrica, ou seja, um sinal elétrico analógico. Este sinal analogico proveniente destes sensores
são amplificados e digitalizados pela a eletrônica de front-end do experimento. Para a
aquisição e processamento destes sinais é utilizado um crate VME de fabricação Caen em
conjunto com alguns módulos, entre eles: o módulo Bridge V1718 responsáveis pela interface
entre os módulos do crate e o computador, o módulo Scaler V830 responsável pela contagem
de pulsos emitidos em cada evento, um módulo TDC (Conversor de Tempo para Digital)
V1290 e módulos de propósito genérico V1495, que são baseados em FPGA que podem ser
programados conforme conveniência do usuário. Estes módulos podem ser configurados e ter
seus dados extraídos através da interface provida pelo módulo V1718, na qual há uma porta
USB para conexão física, drivers para acesso ao dispositivo USB pelo sistema operacional do
computador e uma biblioteca contendo diversas funções de acesso aos módulos do crate para
que o usuário possa fazer seus próprios aplicativos de controle com a finalidade de configurar
o módulo e receber e tratar os dados adquiridos pelos módulos VME.
Os módulos usados na montagem dependem de um software que os configure
apropriadamente e faça a leitura dos dados dos módulos em sincronia com a aquisição dos
dados dos eventos, e este software usualmente precisa ser desenvolvido pelo usuário para se
conformar com a aplicação para a qual o sistema está sendo usado. Devido ao fato da tarefa
de desenvolvimento deste software não se tratar de uma tarefa simples ou trivial, se faz
4
necessário realizar numerosos testes para garantir o funcionamento do software. Porém, como
no sistema há varias camadas passíveis de erro (software, interface USB, interface VME,
módulo de aquisição, eletrônica de front-end e sensores), torna-se demasiadamente difícil
atestar o bom funcionamento do sistema e saber em qual camada ocorre um erro ou, atestar se
os dados recebidos pelo software condizem com o que se deveria de fato receber. Na
aplicação da medição de raios cósmicos, por exemplo, por se tratar de eventos aleatórios e
imprevisíveis, não há como prever qual deveria ser o resultado obtido pelo módulo sem
conhecer previamente o sinal gerado pelos sensores.
Desta problemática surgiu a idéia do presente projeto, que consiste em criar um
gerador de pulsos digitais de modo a simular os pulsos digitais provenientes da eletrônica de
front-end dos sensores utilizados e dessa forma poder inferir o resultado esperado pelos
módulos de aquisição, uma vez que agora saberemos os sinais de entrada dado que estes
partirão do gerador. Com isso é possível verificar se a aquisição, processamento e leitura dos
dados do sistema estão sendo realizados de forma correta.
1.3 Objetivo
Este projeto tem como principal objetivo fornecer uma solução para o problema
proposto no item 1.1. A solução proposta é desenvolver, implementar e caracterizar um
gerador de pulsos digitais que tenha parâmetros configuráveis através do computador e
desenvolver um software com interface de usuário para controle através do computador.
Os parâmetros controlados do gerador devem conter os seguintes:
• Largura de pulso, em ciclos de clock.
• Período, em ciclos de clock.
• Defasagem em relação ao gatilho, em ciclos de clock.
• Número de pulsos a ser enviado por gatilho.
O presente trabalho não se limita somente ao problema em questão mas tem por
objetivo também tornar a solução genérica implementando-a em FPGA de forma que o
gerador de pulsos desenvolvido possa ser utilizado em qualquer plataforma FPGA para
qualquer outra aplicação que possa se tornar necessária no futuro, também documentando e
garantindo que a implementação do gerador seja uma tarefa simples para um futuro usuário.
1.4 Metodologia e Trabalho Realizado
5
O projeto da primeira versão do gerador foi realizado através do software Quartus II
da Altera, utilizando linguagem VHDL e a gravação do firmware no FPGA sendo realizado
através da interface fornecida pelo fabricante do módulo de propósito geral V1495 usado no
projeto. O software foi desenvolvido utilizando a linguagem C e usando as bibliotecas
também fornecidas pelo fabricante, para Linux.
As atualizações do firmware foram realizadas através do computador e seus resultados
testados através da leitura de um osciloscópio do laboratório do LAFEX. Após a fase de
desenvolvimento do firmware, se iniciou o desenvolvimento do aplicativo para interface com
usuário, que foi feito através do computador e testado através da leitura do osciloscópio.
Após a fase de desenvolvimento, o gerador foi ligado a um módulo tipo Scaler modelo
V830, que executa uma contagem dos pulsos recebidos em um intervalo de tempo
configurável, e foram criadas extensas rotinas de testes que consistiam em gerar várias
sequências com milhares de pulsos em cada uma, alternando os parâmetros do gerador entre
cada sequência de pulsos e fazendo a leitura através do módulo V830 para verificar se há
erros no gerador para alguma faixa de operação.
O projeto da segunda versão do gerador foi implementada numa placa de
desenvolvimento de FPGA Avnet LX9 Microboard. Os métodos de grvação do firmware são
fornecidos pela interface USB do fabricante.
Reduzindo a frequência de operação do gerador através de um divisor de frequência
implementado no próprio FPGA era possível atestar o funcionamento do gerador pelos
próprios LEDs da placa. Dessa forma foi possível testar as funções implementadas tanto no
firmware quanto no software durante o próprio desenvolvimento.
Após a fase de desenvolvimento, testamos o gerador implementado na placa LX9 em
sua frequência máxima de operação com um osciloscópio no laboratório do LAFEX variando
os parâmetros durante a leitura com o osciloscópio.
6
Capítulo 2
2. Primeira Versão do Gerador
A primeira versão do gerador foi desenvolvida no Laboratório Multiusuário de Física
de Altas Energias do LAFEX no CBPF, com o objetivo de ser uma ferramenta de teste e
diagnóstico da eletrônica de aquisição de dados das montagens experimentais presentes neste
laboratório.
Na ocasião, estava sendo implementado um método de aquisição de dados através de
alguns módulos VME da CAEN, especificamente os já mencionados V830 Scaler, V1290A
TDC e V1495 de propósito genérico. Esses módulos são responsáveis pela leitura e pré-
processamento de pulsos digitais provenientes da eletrônica de front-end dos sensores a
montagem. A implementação em questão consistia na ligação física dos módulos de aquisição
à eletrônica de front-end, na interface de comunicação entre o crate VME e o computador, e
no software para controle e leitura dos dados provenientes dos módulos de aquisição contidos
no crate VME.
O sistema completo para realizar a aquisição de dados dos sensores compreende várias
etapas e até ser corretamente configurado ou ter um software desenvolvido corretamente, fica
muito suscetível a erros de implementação. Caso isto ocorra, o diagnóstico e depuração do
erro se torna muito complexo e difícil por não sabermos em qual camada o erro ocorreu, ou
seja, dependendo da situação, não há como saber se uma leitura incoerente feita no software
em execução no computador é proveniente de falha no código ou desenvolvimento do
software, se é falha da interface USB com o crate VME, se é falha em algum dos módulos
VME ou se é ainda falha na ligação física dos módulos VME com a eletrônica de front-end.
Devido às dificuldades apresentadas e após certa análise do problema, chegamos à
conclusão que sabendo o sinal de entrada no sistema de aquisição poderíamos inferir a saída
em cada uma das etapas e, portanto, depurar com maior facilidade a causa e proveniência de
uma falha no sistema. Por consequência destas coisas foi decidido fazer um gerador de pulsos
digitais implementado em FPGA, que pudesse funcionar em um dos módulos V1495 de
propósito geral e fazer uso de toda interface já adequada para os demais módulos VME, com
o objetivo de emular os sinais que viriam da eletrônica de front-end, mas desta forma sabendo
o formato deste sinal.
7
2.1 Especificações do Projeto
Após a concepção da idéia inicial do projeto, foi feito o levantamento das exigências e
especificações que o projeto deveria ter. Estas são:
• O módulo ou placa com o FPGA a ser implementado o projeto deve ser
compatível com a interface elétrica dos módulos de aquisição usados, que neste
caso recebiam sinais com níveis de tensão especificados pelos padrões LVDS e
NIM.
• O gerador deve ser desenvolvido como um bloco a parte da entidade de nível
superior do projeto, de modo que possa ser duplicado nesta entidade para se
obter qualquer número de canais desejados.
• O gerador deve ter um sinal correspondente à saída de pulsos, um sinal de
clock, um sinal de reset e quatro vetores de 16 bits correspondentes aos
parâmetros controlados pelo usuário, que são expostos a seguir:
o Period: Tempo (em unidades de clock) entre o início de cada pulso.
o Width: Tempo (em unidades de clock) em que cada pulso permanecerá
em valor lógico alto.
o N: Número de pulsos a ser dados após cada reset.
o Delay: Tempo de atraso (em unidades de clock) em relação ao disparo
do gerado.
• O projeto deve ter um conjunto de registradores em sua entidade de nível
superior onde são guardados os parâmetros controláveis de cada gerador e deve
fornecer uma interface e método de escrita a partir de um computador.
• Deve ser possível disparar os geradores através de um sinal de entrada externo
ou através de comando pela interface de escrita nos registradores.
2.2 Plataforma V1495
O Módulo VME V1495 foi a plataforma escolhida para desenvolvimento e
implementação do projeto.
8
Figura 2: Módulo VME V1495
O V1495 é um módulo VME de uso geral aplicável para vários fins como gerador de
sinal de “gate”, gerador de sinal de “trigger”, conversor de sinais, buffers e aplicações de
9
teste, as quais podem ser diretamente customizáveis pelo usuário. A placa é gerenciada por
dois FPGAs, o Bridge e o User. O FPGA Bridge, é responsável pela interface VME e conexão
do FPGA User ao VME através do barramento local proprierário. Este também gerencia o
upload da programação para o FPGA User. O FPGA User é um FPGA modelo Altera
Cyclone EP1C20 que gerencia os canais de I/O do painel frontal e é substancialmente um
FPGA vazio que pode ser programado pelo usuário da forma como desejar.
O V1495 possui um painel frontal com 64 canais de entrada digital podendo ser
configuráveis como tipos de entrada LVDS, ECL e PECL, e podendo ser expandidos para até
162 canais. O V1495 também possui 32 canais de saída digital do tipo LVDS, podendo ser
expandido até 130 canais.
O módulo suporta a frequência máxima de 405MHz de clock para a lógica
implementada no FPGA User, possui tempos de atraso menores que 15 ns para as saídas e
entradas digitais e também LEDs programáveis.
Os canais de entrada e saída LVDS são divididos em portas de 32 canais, nomeadas A,
B e C podendo ser expandidas como D, E e F com módulos expansores. Adicionalmente
também há 2 canais NIM que podem ser configurados como entrada ou saída, compondo a
porta G.
O diagrama de blocos do módulo V1495 pode ser visto na Figura 1.
Figura 3: Diagrama de blocos do módulo V1495.
10
O módulo V1495 foi escolhido para a implementação da primeira versão do gerador
por já dispor de toda a interface necessária para cumprir com os requisitos do sistema.
2.3 Interface de Acesso aos módulos VME
2.3.1 Interface de Hardware
O módulo V1495 em sua configuração sem os módulos expansores, contém 2 portas
de entrada A e B, cada uma com 32 canais de sinal LVDS, ECL ou PECL, tendo impedância
de 100 ohm, banda passante de 200 MHz e dispostas na frente do módulo por 2 conectores
tipo Robinson Nugent P50E-068-P1-SR1-TG type, (34+34) pinos. O módulo dispõe de uma
porta de saída C, com 32 canais de sinal somente LVDS e o mesmo tipo de conector que as
portas A e B, diferindo destas somente pela banda passante de 250 MHz. O módulo também
dispõe de uma porta G de 2 canais de sinal NIM ou TTL, configuráveis entre entrada e saída,
com impedância de 50 ohm e banda passante de 250 MHz.
Podemos ver na Figura 3 o posicionamento das portas A, B, C e G.
11
Figura 4: Parte frontal do módulo V1495.
A interface de comunicação entre o módulo V1495 e o software de controle executado
em um computador é dada através do módulo tipo “bridge” V1718. O V1495 é ligado ao
barramento VME, o FPGA Bridge gerencia a comunicação entre o FPGA User e o
barramento VME. O barramento VME é gerenciado pelo módulo V1718, que deve ser único
12
para cada crate VME. O módulo V1718 possui toda interface necessária para se comunicar
com um aplicativo através da porta USB. Não devemos confundir o módulo bridge V1718
com o FPGA bridge do módulo V1495.
Explicando de maneira sucinta, a interface de hardware se resume ao computador
conectado ao V1718 usando um cabo USB como meio físico, o módulo V1718 se
comunicando com o módulo V1495 através do barramento VME e, no módulo V1495, o
FPGA Bridge gerenciando o acesso ao FPGA User através do barramento VME.
2.3.2 Interface de Software
O fabricante dos módulos fornecem os drivers necessários para comunicação do
computador com o módulo bridge V1718 e um conjunto de bibliotecas com funções de acesso
ao barramento VME.
O fabricante também fornece um firmware base de exemplo para o FPGA User onde
há uma camada de abstração de hardware. Nele as portas de I/O, os componentes mais
importantes e a pinagem associada a estes já estão declarados de modo que o usuário pode se
concentrar no desenvolvimento sem precisar ter que pesquisar quais os pinos I/O do FPGA
correspondem a cada saída ou porta do barramento da placa. Neste firmware há um código de
exemplo com uma lógica básica e um conjunto de registradores, de leitura, escrita e
leitura/escrita também com a lógica necessária para acessar esses registradores através do
barramento VME.
A interface de acesso aos registradores do firmware de exemplo do V1495 é composta
por um sinal que diz quando houve acesso do usuário e outro que dita se é de leitura ou
escrita. A cada clock ocorre a checagem do sinal de acesso do usuário, se este estiver ativo, o
registrador correspondendo ao barramento de endereço recebe o valor do barramento de dados
caso o comando seja de escrita, ou o referido registrador expõe seu conteúdo no barramento
de dados caso o comando seja de leitura. Como mencionado anteriormente há um sinal que
dita se o acesso é de escrita ou leitura. O o barramento é ligado ao barramento de dados
através de um multiplexador que é implementado pela estrutura de código “when”. Abaixo
exibimos em pseudo-código a implementação do acesso aos registradores:
13
process (clock) if (usuário_acessou) then if (tipo_acesso = escrita) then case (barramento_endereço) is when endereço_1 => registrador_1 <= barramento_dados; when endereço_N => registrador_N <= barramento_dados; end case; elsif (tipo_acesso = leitura) then case (barramento_endereço) is when endereço_1 => barramento_dados <= registrador_1; when endereço_N => barramento_dados <= registrador_N; end case; end if; end if; end process;
O envio dos sinais de controle, do valor de endereço e de dados para serem recebidos
pela dita interface ocorre através do barramento VME pelo módulo bridge V1718, este por
sua vez recebe os comandos e dados do software em execução no computador através da
interface USB.
O fabricante fornece uma biblioteca com as funções de envio dos comandos em
questão e cabe ao usuário desenvolver um software que gerencie o uso dessas funções e
forneça uma interface de usuário para que este possa controlar os registradores do módulo
V1495 através do computador.
2.4 Desenvolvimento e Funcionamento do Gerador
A primeira versão do gerador foi desenvolvida no laboratório multiusuário do
LAFEX/CBPF. Até que chegasse à versão funcional, houveram algumas tentativas e uma
série de aprimoramentos que culminaram no circuito que veio a ser a primeira versão do
gerador.
Desde o início, a idéia básica do gerador era ser um bloco que recebia os quartos
parâmetros controláveis pelo usuário (largura de pulso “width, período “period”, número de
pulsos “N” e defasagem “delay”), um sinal de reset e o clock, e gerasse os pulsos através de
um sinal de saída.
14
Figura 5: Representação em bloco simplificado do primeiro gerador.
O primeiro gerador foi implementado com todos os componentes em um único bloco,
sem sub-divisões (como foi feito na segunda versão) e por isso o desenvolvimento foi de certa
forma dificultado. Inicialmente foi usado VHDL mas por a primeira versão ser assíncrona e
envolver tantas variáveis dependentes umas das outras o desenvolvimento chegou em um
nível de complexidade impraticável. Por isso a parte principal da primeira versão do gerador
foi desenvolvido em diagrama de circuito e depois transcrito para VHDL. O esbolço pode ser
visto na Figura 5.
O gerador compreende um contador, que é um registrador de 16 bits representado no
esboço como “cont”, que conta de 0 até o valor do período gravado no registrador “period”. O
contador é zerado quando seu valor se iguala ao valor do período. Caso haja um reset, o
contador vai para seu valor inicial que é o período menos o delay mais um. Isto é feito para
que ao iniciar a contagem, o contador se atrase o valor escrito em “delay”, que é a defasagem
para dado canal.
Na saída do contador cont há um comparador que compara seu valor com a largura de
pulso width. Enquanto cont é menor que width, a saída é alta, quando cont ultrapassa width o
valor da saída do comparador é baixo. Dessa forma a largura de pulsos é dada por o número
gravado em width, em ciclos de clock. Na saída do referido comparador há um multiplexador
que permite habilitar ou desabilitar a saída do gerador. Quando ativo, a saída do gerador
recebe o valor do comparador, caso contrário recebe zero. Este multiplexador foi mais tarde
simplificado para uma simples porta AND.
15
Figura 6: Esboço do diagrama de blocos do primeiro gerador.
Usando a saída do comparador da largura de pulso como clock, temos um contador
representado no diagrama por “pulses” que conta o número de pulsos dados. Para cada pulso
gerado pelo comparador na saída de cont é incrementado 1 no valor de pulses. Quando o valor
de pulses ultrapassa o valor do registrador “N”, que guarda o número de pulsos a ser gerado
após cada reset, a saída do comparador de N desabilita a saída do gerador, tornando esta zero.
Caso o valor de N seja zero, o gerador não é cortado após atingir certo número de pulsos,
desta forma gerando pulsos indefinidamente até que seja resetado.
A entidade de nível superior do gerador foi desenvolvida a partir do firmware base de
exemplo provido pelo fabricante do módulo. Esta compreendia um número de blocos
16
geradores declarados como entidade correspondendo ao número de canais em que se queria
gerar pulsos, um grupo de 4 registradores de 16 bits para guardar os parâmetros controláveis
de cada canal e uma interface de acesso para que todos os registradores de controle fossem
acessíveis pelo usuário via software.
2.5 Software de Controle
Para que o usuário pudesse ter controle do gerador a partir do computador, assim
como programar rotinas de teste automatizadas, foi desenvolvido os softwares de controle. A
plataforma usada no desenvolvimento foi Linux (Ubuntu) e os softwares foram desenvolvidos
em linguagem C utilizando as bibliotecas com funções de acesso ao barramento VME
fornecidas pelo fabricante dos módulos.
Foi desenvolvido dois aplicativos. Um com uma interface de usuário amigável e o
outro acessado apenas por linha de comando, sendo este último para ser utilizado por scripts
no Linux.
2.6 Limitações
A maneira que executamos o projeto da primeira versão do gerador logo deixou claro
que haveriam algumas limitações.
A primeira limitação é que por a entidade de nível superior ser baseada em um
firmware de exemplo especificamente desenvolvido para o módulo V1495, a qualquer
momento que precisássemos migrar de plataforma teríamos que refazer a entidade de nível
superior.
A segunda limitação é a interface de acesso, que por depender totalmente da interface
de hardware dos módulos da CAEN e do VME, para qualquer outra aplicação o sistema
ficaria limitado, se fazendo necessário a criação de uma nova interface de acesso assim como
drivers e novos aplicativos com interface de usuário a ser executado pelo computador. Ou
seja, o sistema do gerador em sua primeira versão ficou dependente por completo da
plataforma em que foi implementado.
A terceira limitação foi o fato de ter sido desenvolvido de forma assíncrona. Apesar de
não ter ficado evidente durante as etapas de projeto do primeiro gerador, após este ter sido
concluído um estudo mais aprofundado da arquitetura do FPGA demonstrou que os sinais
usados para disparar os flip-flops do projeto assíncrono são considerados pelo FPGA como
17
sinais de clock e precisam de vias internas especiais para que seja distribuído entre todas as
células lógicas que fazem uso de tal sinal de forma otimizada, visando minimizar o atraso de
propagação. Por exemplo, imaginando que o contador principal de todos os blocos de gerador
do sistema sejam disparador por um mesmo sinal de trigger, é necessário que este sinal seja
propagado por uma via dedicada ao clock, caso contrário terá atraso de propagação e um
contador pode ser iniciado atrasado em relação aos demais.
Todas estas limitações aqui citadas a respeito da primeira versão do gerador foram
superadas com a segunda versão do gerador, cuja intensão era justamente suprimir todos esses
problemas.
18
Capítulo 3
3. Segunda Versão do Gerador
A segunda versão do gerador foi desenvolvida com o objetivo de solucionar alguns
problemas encontrados durante o desenvolvimento da primeira versão e adicionar algumas
funcionalidades e características que foram idealizadas a medida que a primeira versão do
gerador ia sendo implementado.
Essa nova versão foi desenvolvida do zero, com o objetivo de dividir o processo de
desenvolvimento em etapas simples e modulares, visando uma organização melhor para
futuras alterações, desenvolvimento, e facilitar o entendimento de quem vier a usar. O projeto
foi também todo reescrito de maneira síncrona, visando otimizar o uso em FPGAs e permitir
ao desenvolvedor ter uma percepção melhor do comportamento esperado do circuito.
A idéia de refazer toda a primeira versão do gerador partiu de uma sugestão do Prof.
Jesse Costa para adaptar o gerador de forma que ele funcionasse de forma genérica e
adaptável ao maior número possível de plataformas baseadas em FPGA a fim de poder ser
usado para outras aplicações, se não a tão específica que era o objetivo inicial. Observou-se
que seria um processo trabalhoso a adaptação do código uma vez que este não estava dividido
em partes organizadas. Por isto surgiu a idéia de refazer todo o projeto, simplificando,
otimizando e adaptando-o às novas especificações do sistema.
Para o desenvolvimento da segunda versão do projeto foi usada uma plataforma de
desenvolvimento de FPGA da Avnet, baseada em um FPGA da família Spartan-6 da Xilinx.
O principal desafio era criar o circuito de forma que seu uso fosse prático e de fácil adaptação
para qualquer plataforma, e também de forma que sua interface com o computador fosse
independente do hardware da placa em que o FPGA estivesse instalado.
3.1. Especificações do Projeto
Dada a experiência e os resultados obtidos com a primeira versão do gerador, foi
criado novas especificações para o projeto, as quais são:
• O projeto deveria ser simples e executado da forma mais trivial possível de
modo a facilitar sua implementação nas mais diversas plataformas em que
pudesse ser usado, visando tornar o projeto o mais genérico possível.
19
• O gerador deve ser desenvolvido como um bloco a parte da entidade de nível
superior do projeto, de modo que possa ser duplicado nesta entidade para se
obter qualquer número de canais desejados.
• O gerador deve ter um sinal correspondente à saída de pulsos, um sinal de
clock, um sinal de trigger, um sinal de veto e quatro vetores de 16 bits
correspondentes aos parâmetros controlados pelo usuário, que são expostos a
seguir:
o Period: Tempo (em unidades de clock) entre o início de cada pulso.
o Width: Tempo (em unidades de clock) em que cada pulso permanecerá
em valor lógico alto.
o N: Número de pulsos a ser dados após cada reset.
o Delay: Tempo de atraso (em unidades de clock) em relação ao disparo
do gerador.
• O gerador deve ser engatilhado sempre que o sinal de trigger alternar de nível
lógico baixo para alto.
• O gerador deve ter seu funcionamento cessado sempre que o sinal de veto
alternar seu nível lógico de baixo para alto.
• O projeto deve ter uma caixa de registradores em sua entidade de nível
superior onde são guardados os parâmetros controláveis de cada gerador e deve
fornecer uma interface e método de escrita a partir de um computador.
• Deve ser possível disparar e vetar os geradores através de um sinal de entrada
externo ou através de comando pela interface de escrita nos registradores.
3.2 Placa de Desenvolvimento LX9 MicroBoard
Para o desenvolvimento da segunda versão do gerador foi utilizado a placa de
desenvolvimento Avnet LX9 MicroBoard.
Esta é uma placa que possui um FPGA XC6SLX9 da família Spartan-6 do fabricante
Xilinx, 64 MB de memória SDRAM, 128 MB de memória Flash acessada por SPI, interface
ethernet de 10/100, conversor integrado USB-UART, circuito JTAG integrado acessado por
USB, 16 pinos de I/O genéricos, circuito integrado gerador de clock programável, além de ter
4 LEDs, um DIP switch de 4 bits, um botão de reset e um push-button programável como
interface de usuário.
20
Uma imagem da placa pode ser vista na Figura 6:
Figura 7: Vista superior da placa de desenvolvimento LX9 MicroBoard.
A escolha desta placa de desenvolvimento foi especialmente conveniente por conter o
circuito integrado CP2102 que é um conversor USB-UART e deste modo já é fornecido a
interface de hardware necessária para realizar a comunicação entre o aplicativo no
computador e o FPGA.
3.3 FPGA
Os FPGAs (Field Programable Logic Array) são dispositivos semicondutores que
dispõem de um circuito digital reprogramável, que pode assumir várias funções lógicas
diferentes.
Os FPGAs são compostos basicamente por três tipos de componentes: blocos de
entrada e saída (IOB), blocos lógicos configuráveis (CLB) e matriz de interconexão (Switch
Matrix).
Os CLB (Configuration Logical Blocks) são circuitos idênticos, espalhados como
células por uma grande área do FPGA formando uma matriz bidimensional, construídos pela
reunião de flip-flops e a utilização de lógica combinacional para que este bloco possa
desempenhar a função de qualquer unidade lógica básicas, de maneira que a conexão de
vários destes executandos várias funções diferentes possa formar circuitos lógicos complexos
e permitir ao usuário uma grande flexibilidade.
Os IOB (Input/Output Blocks) são circuitos responsáveis pelo interfaceamento das
saídas provenientes das saídas das combinações de CLBs. São basicamente buffers que
funcionarão como um pino bidirecional entrada e saída do FPGA.
21
A Matriz de Interconexão (Programmable Interconnect) são trilhas utilizadas para
conectas CLBs e IOBs entre si. Este terceiro grupo é composto pelas interconexões. Os
recursos de interconexões possuem trilhas para conectar as entradas e saídas dos CLBs e IOBs
para as redes apropriadas através de canais de roteamento horizontais e verticais entre as
linhas e colunas dos blocos lógicos. É através da capacidade da matriz de interconexão de
conectar vários blocos CLB entre si e à IOBs que o FPGA provê ao usuária tamanha
flexibilidade na implementação de circuitos digitais. Geralmente, a configuração é
estabelecida por programação interna de células de memória, estáticas ou dinâmicas, que
determinam funções lógicas e conexões internas implementadas no FPGA entre os CLBs e os
IOBs. O processo de escolha das interconexões é chamado de roteamento.
Figura 8: Arquitetura padrão de um FPGA moderno.
No interior dos blocos lógicos configuráveis de um FPGA existem vários modos
possíveis para implementação de funções lógicas. O mais utilizados pelos grandes fabricantes
de FPGA, como, por exemplo, a Altera, são os blocos de memória LUT (Look-Up Table).
Esse tipo de bloco lógico contém células de armazenamento que são utilizadas para
22
implementar pequenas funções lógicas. Cada célula é capaz de armazenar um único valor
lógico: zero ou um.
Nos FPGAs disponíveis comercialmente como, por exemplo, da empresa Altera Corp.,
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.
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.
O FPGA contido na placa LX9 MicroBoard é um Spartan-6 XC6SLX9 produzido pela
Xilinx. Este utiliza a lógica de LUTs (look-up table) com 6 entradas e 2 flip-flops e contém
9152 células lógicas, 2 PLLs para multiplicação do clock e um total de 200 I/Os.
Cada CLB ou Bloco Lógico Configurável da série Spartan-6 consiste em duas fatias,
arranjadas lado a lado como parte de duas colunas verticais. Há três tipos de fatias na
arquitetura Spartan-6: SLICEM, SLICEL e SLICEX. Cada fatia contém quatro LUTs, oito
flip-flops e lógica variada. Os tipos de fatia serão vistos a seguir:
SLICEM constituem 25% do total do FPGA e cada uma pode ser configurada como
uma LUT de 6 entradas e uma saída ou como duas LUTs de 5 entradas com endereços de 5
bits idênticos e duas saídas independentes. Estas LUTs podem ser usadas também como
memórias RAMs distribuídas de 64 bits, como um registrador de deslocamento de 32 bits ou
como 2 registradores de deslocamento de 16 bits com comprimento endereçável. Cada saída
da LUT pode ser registrada em um flip-flop interno à CLB.
SLICEL constituem 25% do total do FPGA e contém todos os recursos da fatia
SLICEM exceto a função de memória RAM e registradores de deslocamento.
SLICEX constituem 50% do total do FPGA e contém os mesmos recursos que a fatia
SLICEL exceto a opção de carry aritmético e os multiplexadores amplos.
23
3.4 Projeto Síncrono vs Assíncrono
Como veremos em uma descrição mais detalhada a seguir, o gerador utiliza um sinal
de clock como base de tempo e vários outros sinais como trigger de diversos contadores nos
blocos do gerador. O gerador possui um bloco para controle dos pulsos e ele todo funciona a
base de contadores que contam quantos clocks se passaram para então iniciar ou encerrar um
pulso. Tem a unidade de delay que cria uma defasagem programada em cada canal que
funciona tendo o clock do gerador como referência e há uma unidade que conta o número de
pulsos dados até o momento para controlar a quantidade de pulsos por trem. Este contadores
utilizam sinais que não são o clock principal como gatilho. O contador é engatilhado e vetado
por dois sinais externos.
A maneira mais fácil de ter sinais engatilhando sistemas ou contadores é utilizar estes
sinais como o clock de flip-flops. No entanto, o FPGA em sua arquitetura interna separa vias
dedicadas a sinais de clock, e interpreta qualquer sinal que dispare um flip-flop como sinal de
clock. Isto é porque ele julga que estes sinais que disparam os flip-flops tem requisitos de
timing muito exigentes para que todos os flip-flops sejam disparados em tempos bem
próximos.
Os sinais no FPGA podem ser propagados através das vias normais da matriz de
interconexão ou através das células lógicas, porém, estas geram atrasos nos sinais. Por este
motivo que há vias dedicadas aos sinais de clock ao longo do FPGA. O grande problema é
que não há vias suficientes para cada sinal de gatilhos dos flip-flops do gerador se este usar
vários sinais diferentes como gatilho, como discutido anteriormente.
Deste problema, surgiu a necessidade de adaptar todo o projeto para funcionar em
função somente de um único sinal de clock, de maneira síncrona. O projeto havia sido
totalmente escrito de forma assíncrona e já estava sendo implementado na placa, mas quando
se negligenciava o uso das vias especiais de clock para os sinais internos de gatilho o gerador
funcionava de maneira estável como previsto.
Por estas causas o projeto foi reescrito de forma a se tornar completamente síncrono de
forma a só precisar propagar um sinal de clock ao longo de todo o circuito.
24
3.5 Visão Geral da Top Level Entity
A Entidade de Nível Superior ou “Top Level Entity” é o bloco de maior hierarquia em
um dispositivo reprogramável.
No desenvolvimento de circuito digitais, para simplificação e otimização do trabalho
separamos as diferentes partes do circuito que desempenham uma certa função em blocos.
Todos esses blocos são interconectador na Entidade de Nível Superior. É nela onde se tem a
visão geral do que está a ser implementado no FPGA.
A segunda versão do gerador compreende os seguintes componentes:
• Divisor de Frequência
• Arquivo de Registradores (proporcional ao número de canais do gerador)
• Unidades Geradoras (uma por canal)
• Buffer de dados de entrada
• Comparador
• Receptor UART
• Transmissor UART
O diagrama de blocos do gerador pode ser visto na Figura 8.
25
Figura 9: Diagrama de blocos da entidade de nível superior do gerador.
Nos capítulos seguintes abordaremos detalhadamente cada um dos blocos que a entidade de nível superior compreende e explicaremos a relação entre eles.
26
3.6 Gerador Controlável
O coração do projeto é o bloco gerador de pulsos. Este foi projetado de modo
independente do restante do circuito para que tivesse a versatilidade de poder ser
implementado em qualquer plataforma e também poder ser duplicado dentro de um projeto
para que seja possível obter quantos canais de saída foram necessários.
O gerador é controlado por quatro parâmetros de 16 bits e 2 sinais de controle
conforme a Figura 9.
Figura 10: Representação do bloco da segunda versão do gerador.
O que o diferencia da versão anterior apresentada na Figura 4, em termos de entrada, é
a substituição do sinal “reset” pelos sinais “trigger” e “veto” que são responsáveis por
disparar e interromper o funcionamento do gerador respectivamente e um sinal de clock
adicional que é somente para a geração de pulsos. Isto permitiu um maior controle do gerador
e uma implementação mais simplificada da interface de controle. Outra grande diferença é
que este gerador é síncrono enquanto a versão antiga era assíncrono.
Esta versão possui dois clocks. Um é proveniente de um divisor de frequência externo
ao gerador e através dele pode-se criar pulsos mais longos, não ficando limitado aos pulsos
com período de 16 bits de ciclos do clock principal. Este é usado na unidade geradora de
pulsos e no atrasador. O outro é o clock principal do circuito e é usado para os circuitos que
detectam quando há mudança nos sinais. Uma vez que o circuito agora é síncrono, os
contadores não são mais disparados por sinais ligados direto na entrada de clock, mas sim de
comparadores formados por flip-flops que comparam o sinal anterior com o atual. Flip-flops
27
esses que são disparados com o clock do sistema, que deve ser o mais rápido possível e com
frequência igual ou maior ao clock do gerador.
O gerador é disparado na subida o sinal de trigger e começa a gerar após “delay”
ciclos de clock. Passado o tempo de delay, o gerador emitirá “N” pulsos de largura “width”
com distância “period” entre eles. O gerador cessará os pulsos automaticamente quando o
número de pulsos dados alcançar N ou quando o sinal de “veto” ir de zero para um. Caso “N”
seja igual a zero, o gerador emitirá pulsos indefinidamente até que ocorra a subida do sinal de
veto.
A segunda versão do gerador compreende os seguintes blocos:
• Unidade geradora (Generator Unit): Responsável pera geração dos pulsos.
• Atrasador (delayer): Responsável pelo atraso do delay.
• Contador de pulsos (Pulses Counter): Responsável por cessar a geração de
pulsos após alcançado o número de pulsos pretendido.
• Degrau: Bloco responsável por transformar a subida do VETO em um sinal
interno de degrau com o objetivo de vetar o gerador até que haja um novo
gatilho.
• Pulso: Bloco responsável por transformar a subida do TRIGGER em um pulso
interno que iniciará a operação do gerador.
O diagrama de blocos da segunda versão do gerador pode ser visto na Figura 10 (as
entradas correspondentes aos parâmetros de controle de 16 bits foram omitidas para melhor
visualização):
28
Figura 11: Diagrama de blocos da segunda versão do gerador.
3.6.1 Delayer
A unidade Delayer é responsável por atrasar o início da operação da unidade geradora.
Dessa forma é possível configurar defasagem entre diferentes canais.
O bloco de delayer recebe o parâmetro “delay” de 16 bits, um sinal de reset, o sinal de
clock do gerador e o sinal de clock do sistema. Quando é dado o trigger do gerador, um
contador começa a contar os ciclos do clock do gerador e mantém a unidade geradora
desabilitada até que o contador alcançe o número de clocks correspondente ao parâmetro
delay. Ao alcançar este, ele habilita a unidade geradora para que esta começe a emitir pulsos.
Desta forma é obtido o atraso em ciclos de clock, antes do início da operação do gerador após
um sinal de trigger.
Para que a unidade delayer haja de forma síncrona ele utiliza dois clocks. O clock do
sistema e o clock do gerador. O clock do sistema é o que engatilha cada comparação entre o
29
estado atual e o último estado do clock do gerador. Cada vez que o estado atual do clock do
gerador for 1 e o estado anterior for 0 significa que houve uma subida do clock e então o
contador é incrementado em um.
Inicialmente o próprio sinal do clock do gerador engatilhava o contador, tornando o
circuito bem mais simples. No entanto, devido a limitação do FPGA usar os sinais de gatilho
de flip-flops através das vias especiais de clock, se fez necessário a mudança.
Sempre que há um evento de subida no sinal de trigger do gerador, o contador é
zerado e volta a contar do zero. Quando o contador alcança o valor de delay, este também
cessa sua operação até que haja um novo sinal de trigger.
Abaixo na Figura 11 vemos uma ilustração da operação do bloco delayer, onde a
primeira forma de onda é o sinal de trigger do gerador, a segunda é o contador do delayer e a
terceira é a saída do gerador.
Figura 12: Ilustração do funcionamento do bloco delayer.
3.6.2 Pulses Counter
Este bloco é responsável por vetar o sinal de saída do gerador quando o número de
pulsos emitidos atingir o numero de pulsos desejado.
O bloco consiste em um contador que conta o número de pulsos emitidos. Consiste em
um registrador de 16 bits que incrementa de um sempre engatilhado quando há borda de
descida do sinal de saída do gerador. Os flip-flops do contador não são engatilhados
diretamente pelo sinal de saída do gerador devido ao problema de clock assíncrono já
mencionado anteriormente. No lugar disto, usamos um flip-flop que a cada pulso do clock
registra o sinal de saída do gerador e um comparador, que compara o valor desse flip-flop ao
valor da saída do gerador. O valor do flip-flop sempre corresponderá ao valor anterior ao
30
presente do sinal de saída do gerador. Comparando este sinal com o sinal atual podemos
atestar que houve uma mudança no sinal do gerador. Como mencionado, sempre que essa
mudança é uma borda de descida, ou seja, quando o sinal anterior é ‘1’ e o atual é ‘0’, o
contador é incrementado de uma unidade.
O bloco recebe um parâmetro de entrada de 16 bits correspondente ao número de
pulsos que deve ser emitido por cada trem de pulsos. Este valos fica guardado num
resgistrador e um comparador avalia se o numero de pulsos dados registrado no contador já
alcançou o número de pulsos a serem dados. O sinal desse comparador vai para ‘1’ quando o
contador alcança o número de pulsos a ser dado. A saída deste comparador é ligada à entrada
de veto do gerador e por isto os pulsos cessam quando a saída do comparador é setado.
Na Figura 12 podemos observar o comportamento do bloco contador de pulsos.
Figura 13: Ilustração do funcionamento da unidade pulses conter.
31
3.6.3 Generator Unit
A unidade geradora de pulsos é a responsável pela geração propriamente dita dos
pulsos, é o coração do gerador.
Esta recebe dois parâmetros de 16 bits, que são a largura de pulso ‘width’ e a distância
entre o início de cada pulso ou período ‘period’. Ambos os parâmetros são dados em ciclos de
clock e guardados em registradores externos ao gerador.
O gerador compreende um contador que conta os ciclos do clock do gerador, um
circuito comparador para indicar quando o contador alcança o valor de ‘width’ e outro para
indicar quando o contador alcança o valor de ‘period’.
Partindo do zero, o contador inicia a contagem quando ocorre a transição de subida do
sinal de trigger. Neste momento o sinal de saída do gerador vai para ‘1’ e permanece até que
o valor do contador atinja o valor especificado pelo parâmetro ‘width’. Quando isto ocorre o
sinal de saída do gerador retorna a ‘0’ e permanece até o reset do contador. O contador segue
incrementando 1 a cada ciclo de clock do gerador até que este atinja o valor do período, que é
dado pelo parâmetro ‘period’ decrescido de uma unidade. Neste momento o contador é
zerado, o sinal de saída do gerador volta a ‘1’ e o contador inicia a contagem do zero.
Desta forma a unidade geradora gera pulsos que permanecem em nível lógico alto
durante ‘width’ ciclos de clock e retorna a nível lógico baixo até que atinja ‘period’ ciclos de
clock.
O contador só permanece ativo enquanto seu sinal de reset está em nível lógico baixo.
A qualquer momento em que este sinal está em nível alto, o contador é zerado e a saída do
gerador resetada.
Na Figura 13 podemos ver um gráfico que ilustra o funcionamento da unidade
geradora.
32
Figura 14: Ilustração do funcionamento da unidade geradora.
3.7 Interface Serial UART
O programa do projeto contemplava a criação de uma interface de acesso para que o
usuário pudesse facilmente configurar o gerador a partir de um computador. A interface
escolhida para comunicação entre o circuito e um aplicativo no computador foi a UART
(Universal Assynchronous Receiver Transmitter).
Essa escolha se deu ao fato de a comunicação assíncrona só utilizar 2 pinos de IO, no
caso da unidirecional, e 3 pinos no caso da bidirecional e ser um padrão bem popular, com um
número bem grande de conversores USB-UART a baixo preço no mercado, e de fácil
desenvolvimento de softwares de acesso. Os pinos usados são um para envio de dados, um
para recebimento e um para tensão de referência. Outro fator que motivou a escolha da
interface UART foi o fato de que a placa de desenvolvimento utilizada no projeto já
compreendia um conversor USB-UART integrado, o que permitia ligar a placa diretamente na
porta USB do computador para controlar o circuito, nos poupando da necessidade de adquirir
hardware adicional para executar o projeto. A grande maioria das placas de desenvolvimento
para FPGA atuais já compreende algum tipo de circuito conversor USB-UART.
Na Figura 14 podemos ver a porta USB utilizada no projeto.
33
Figura 15: Placa Avnet LX9 conectada à USB pela porta UART.
A interface UART é dividida em 2 blocos, um responsável pela recepção dos dados e
outro responsável pelo envio.
3.7.1 Protocolo Serial
O protocolo de comunicação utilizado no projeto é o RS-232 com níveis de tensão de
0V a 3.3V.
Os dados no protocolo RS-232, na forma configurada no projeto, são enviados byte a
byte, através de um frame que compreende 10 bits. Enquanto ociosa, a linha fica com sinal
lógico 1. Para indicar o início da transmissão de um byte é enviado o chamado Start Bit que é
sempre igual a ‘0’. Em seguida são enviados os 8 bits do byte e ao final é enviado o chamado
Stop Bit, sendo este sempre ‘1’, para indicar que o byte já foi transmitido. A linha pode ou
continuar em ‘1’ indicando ociosa, ou emendar em um bit ‘0’ indicando que outro byte está
sendo recebido.
O protocolo é apresentado a seguir na Figura 15:
34
Figura 16: Configuração do protocolo UART usada no projeto.
3.7.2 Unidade Rx
A Unidade Rx é a unidade receptora UART. Ela é responsável por receber o frame de
10 bits através da porta serial, filtrar os 8 bits de dados e expô-los em uma saída paralela.
A Unidade Rx recebe dois sinais de entrada e dois de saída. Como entrada temos o
clock interno da placa e o sinal de dados proveniente do pino receptor da porta serial. Como
saída temos um sinal tipo flag que indica quando um byte foi recebido e está pronto para ser
lido, e o outro é um barramento de 8 bits por onde o byte recebido pode ser lido.
A unidade Rx compreende uma máquina de estado, um registrador de deslocamento
de 8 bits que guarda em sequência os bits recebidos, um contador para marcar o tempo de
cada bit, um contador para controlar o número de bits já recebidos, um registrador que guarda
os 8 bits recebidos ao final de cada leitura e um flip-flop que representa o flag indicador de
byte recebido.
O receptor UART foi implementado através de uma máquina de estado, contendo
quatro estados que podemos observar na imagem abaixo (Figura 16), seguido de uma
explicação sobre cada estado.
35
Figura 17: Diagrama de estados da máquina de estado da unidade UART receptora.
• Wait_Start_bit (Espera Start bit): É o estado inicial do receptor. Neste estado o
receptor fica aguardando uma transição de nível alto para nível baixo no sinal
de entrada da porta serial. No padrão RS232, uma porta em estado ocioso fica
36
em nível lógico alto constante e o que caracteriza o início da transmissão é a
transição de ‘1’ para ‘0’ no sinal durante o tempo de um bit. Isto é o que
caracteriza o “start bit”.
• Start_bit (Recebe Start bit): Logo que o start bit é identificado, o receptor entra
neste estado. Um contador é iniciado do zero e ele esperar o tempo equivalente
a um bit e meio. Isto porque no próximo estado o receptor efetuará a leitura dos
bit e é mais seguro que a leitura seja efetuada no centro da janela de tempo
entre o início e final de cada bit. Esperando um bit e meio, o start bit passará
por completo e o primeiro bit de dados estará aproximadamente na metade.
• Lendo_bits (Lê 1 bit): É o estado em que o receptor guarda o valor recebido na
porta serial. Ligado à entrada da porta serial há um registrador de
deslocamento de 8 bits que é deslocado de 1 e isto que caracteriza a leitura de
um bit. Neste estado o receptor efetua a leitura de 1 bit, incrementa um
contador de bits recebidos e espera mais o tempo equivalente a 1 bit para
efetuar a leitura do próximo, até que o número de bits contados seja 8. Ao
chegar neste ponto, o receptor seta a flag Rx_Flag, que indica que o byte
recebido está pronto para ser lido na saída do bloco receptor da UART, e
avança para o próximo estado, Stop_bit. A Rx_Flag fica em nível alto até o fim
da transmissão do stop bit.
• Stop_bit (Recebe Stop bit): Neste estado, como os 8 bits de dados já estão
guardados no registrador de deslocamento, o receptor apenas esperar a
passagem do stop bit para então voltar ao estado inicial onde fica aguardando
um novo start bit para iniciar uma nova transmissão. Ao terminar o stop bit e
voltar para o estado inicial, o receptor zera o contador e reseta a flag Rx_Flag.
3.7.3 Unidade Tx
A Unidade Tx é a unidade transmissora UART. Ela é responsável por montar e enviar
um frame de 10 bits através do pino de saída da porta serial, a partir dos 8 bits de dados de um
barramento interno.
O bloco que compõe a Unidade Tx recebe três sinais de entrada e dois de saída. Os
sinais de entrada são um sinal de clock, uma entrada paralela de 8 bits e um sinal para iniciar a
transmissão chamado de “go” . Na saída temos um sinal responsável pela transmissão dos
37
frames do protocolo serial com os bits serializados e um sinal tipo flag “Busy” para indicar se
que a porta serial está ocupada, ou seja, está em processo de envio de bits.
A unidade Tx, assim como a unidade Rx, também compreende uma máquina de
estado, no entanto, esta só tem dois estado: o em espera (Idle) e o enviando (Sending). A
unidade Tx adicionalmente compreende um registrador de 10 bits usado para montar o frame
do protocolo serial, um registrador de deslocamento e um contador de tempo que define a
velocidade de transmissão e outro que conta o número de bits enviados.
O primeiro estado, o estado “Idle”, corresponde ao período ocioso da porta serial.
Neste período o nível lógico da saída fica continuamente em ‘1’. Quando há transição do sinal
“go” de nível lógico baixo para alto, ou seja, borda de subida, a unidade Tx inicia a
transmissão. Neste momento, o byte na entrada paralela de dados da unidade Tx é guardado
no buffer interno de 10 bits “outBuff” juntos com o Start bit e o Stop bit, ambos os contadores
são zerados e a operação de envio se inicia. O flag “Busy” é setado e a máquina avança para o
próximo estado, o “Sending”.
O próximo estado é o “Sending”, responsável pelo envio do frame serial armazenado
no buffer interno “outBuff” no estado anterior. A unidade Tx desloca um bit do buffer
“outBuff” para a saída e inicia um contador que indicará quando passou o tempo equivalente a
um bit. Passado este tempo, o contador de bits enviados é incrementado de um, o contador de
tempo é reiniciado e o buffer interno é deslocado novamente, caracterizando assim a
transmissão do próximo bit. O processo é repetido até que 10 bits sejam enviados. Quando
isto ocorre, o estado da máquina retorna a “Idle” ou em espera e o flag “Busy” é resetado.
Enquanto um byte está sendo transmitido e por isto a flag “Busy” está setada, é
possível deixar agendado a transmissão do próximo byte. Se a unidade Tx estiver em estado
Idle, um pulso na entrada “go” iniciará a transmissão do byte na entrada. Se a unidade Tx
estiver em estado Sending, a transmissão do próximo byte ficará agendada e será realizada
assim que a transmissão atual for concluída. Se a unidade Tx estiver em estado Sending e já
houver um byte a ser transmitido em espera, qualquer pulso na entrada Go será ignorado.
Deste modo evitamos que haja um delay entre cada byte enviado pois o circuito utilizando a
porta serial não precisa esperar o término de cada envio para ordenar o próximo, no entando,
ainda é preciso agendar o envio de cada byte à medida que os anteriores forem sendo
enviados.
38
3.8 Entidade Top Level
Esta seção detalha a entidade de nível superior e seus componentes. Como já vimos na
seção 3.5, a segunda versão do gerador compreende os seguintes componentes:
• Divisor de Frequência
• Arquivo de Registradores (proporcional ao número de canais do gerador)
• Unidades Geradoras (uma por canal)
• Buffer de dados de entrada
• Comparador
• Receptor UART
• Transmissor UART
E seu diagrama de blocos pode ser visto na Figura 8.
A entidade de nível superior trabalha utilizando uma fonte de clock externa que é
distribuído para todos os componentes do sistema. Internamente é criado um segundo sinal de
clock, gerado a partir da divisão do clock principal, que é usado para os geradores de pulsos.
O sistema é todo síncrono, desta forma, para melhor funcionamento e precisão, é favorável
que o clock externo seja o maior possível. No entanto, não é interessante que o clock utilizado
nos geradores seja sempre o mais rápido possível, pois os geradores utilizam contadores de 16
bits, limitando a frequência mínima de operação para o clock externo dividido por 216. Por isto
foi criado um divisor de frequência para gerar um segundo clock usado somente para os
geradores. Este divisor de frequência divide em até 231 vezes o clock e é controlado por 2
registradores de 8 bits que podem ser escritos pela interface serial.
O gerador em si são blocos individuais que recebem os parâmetros do trêm de pulsos a
ser gerado e tem uma única saída, podendo ser atribuída a um pino de I/O. Desta forma
podem ser replicados para o número de canais que for necessário, respeitando os limites de
espaço e número de I/O do FPGA sendo usado. Neste projeto, os sinais de veto, trigger e
clock são compartilhados entre todos os blocos geradores.
Os blocos geradores recebem os quatro parâmetros individuais de uma caixa de
registradores, que no código VHDL é declarado como um vetor de sinais de 16 bits. Isto
significa que a caixa de registradores tem pelo menos 4 registradores para cada gerador. Nesta
mesma caixa está armazenada os registradores que controlam o divisor de frequência.
Na entidade de nível superior é também onde está a interface de escrita nos
registradores da caixa de registradores, que armazena os parâmetros dos blocos
39
geradores.Todos os bytes recebidos são armazenados em um buffer de 5 bytes e exite um
comparador para interpretar o comando que está contido neste buffer.
As seguintes operações podem ser interpretadas pela interface de escrita nos
registradores:
• Disparo dos geradores: Este comando é executado através de um pulso dado
nas entradas de trigger dos geradores e ocorre quando o comparador identifica
os bytes correspondentes pela tabela ASCII aos 5 caracteres “start” no buffer,
ou seja, para iniciar a operação dos blocos geradores, basta enviar a palavra
“start” pela porta serial.
• Veto dos geradores: Este comando é executado através de um pulso dado nas
entradas de veto dos blocos geradores e ocorre quando o comparador identifica
os bytes correspondentes pela tabela ASCII aos 4 characteres “stop” nos 4
primeiros bytes do buffer da porta serial. Para cessar a operação de todos os
blocos geradores, basta enviar a palavra “stop” pela porta serial.
• Escrita em um registrador: Este comando escreve um valor de 16 bits em um
dos registradores da caixa de registradores. Ele é executado quando o
comparador identifica os bytes correspondente pela tabela ASCII aos
caracteres ‘#’ e ‘*’ nos primeiro e último registrador do buffer da porta serial
respectivamente. Quando isto ocorre, o quarto byte do buffer será o endereço
do registrador a ser escrito e o segundo e terceiro bytes serão o dado a ser
escrito.
Desta forma é possível iniciar e cessar a operação do gerador assim como alterar
qualquer de seus parâmetros em tempo de execução pela porta serial.
3.9 Software para Controle
Para facilitar e automatizar o controle do gerador através da porta serial foi criado uma
aplicação gráfica para ambiente Windows.
O conceito da aplicação é criar uma interface fácil para automatizar o envio de
comandos para o gerador através de uma porta serial. Através desta se poderia editar os
parâmetros de cada canal e enviá-los para o gerador de forma simples.
A linguagem de programação escolhida para desenvolvimento da aplicação foi Object
Pascal e o desenvolvimento foi feito no ambiente de desenvolvimento integrado Lazarus para
Windows. Esta escolha se deu devido ao fato do desenvolvedor já ter experiência com a
40
plataforma Delphi que usa a mesma linguagem, e a escolha da plataforma Lazarus se deu por
ser uma plataforma livre e de código aberto.
Abaixo podemos ver na Figura 17 a interface gráfica de usuário do aplicativo de
controle do gerador:
Figura 18: Interface gráfica do aplicativo de controle do gerador.
Esta aplicação foi desenvolvida especificamente para testes e portanto foi
implementado somente para 4 canais.
Para iniciar o uso do aplicativo, a primeira coisa necessária a se fazer é conectar o
gerador à porta serial e selecioná-la através do combobox onde se vê escrito “Porta” na
imagem. Ao fazer isto o aplicativo abre uma conexão serial com a porta selecionada e aguarda
algum comando.
Para dar partida nos geradores, que é equivalente a escrever a palavra “start” na porta
serial, basta apertar o botão “Trigger”.
Para vetar a operação dos geradores, basta apertar o botão “Veto” e este enviará a
palavra “stop” pela porta serial, que é o comando para tal.
Para alterar qualquer dos parâmetros dos geradores, basta alterar os valores nas caixas
de texto. O valor escrito acima das colunas ditam o número do canal em que se está alterando
os parâmetros e o texto à esquerda das caixas de texto indicam quais dos quatro parâmetros
corresponde a linha de caixas de texto. Ao concluir a seleção dos valores, basta clicar em
41
“Enviar” e o aplicativo enviará o comando para a interface de escrita nos registradores do
circuito executar as alterações nos registradores correspondentes e então ter o gerador
funcionando com os parâmetros passados.
É importante notar que os parâmetros são passados em série pela porta serial, portanto
quando é feito alteração em vários valores diferentes, os comandos serão enviados um a um e
os registradores serão também alterados um a um em diferentes instantes de tempo. Se o
gerador estiver em funcionamento durante a passagens destes comandos pode ocorrer a perda
de sincronia entre os diferentes canais. Por isso recomenda-se para o gerador clicando em
“Veto”, efetuar a mudanças nos parâmetros alterando as caixas de texto e clicando em
“Enviar” e por último clicar em “Trigger” para retornar a operação do gerador com os novos
parâmetros.
A caixa de texto na parte inferior da janela é responsável pelo valor do divisor de
frequência. Ao alterá-la e clicar em “Enviar” os registradores que controlam o divisor de
frequência serão atualizados e o gerador passará a operar sob nova frequência de clock.
O aplicativo também não atualiza os valores do geradores desnecessariamente, isto é,
caso você clique no botão “Enviar” sem ter efetuado nenhuma alteração nos valores das
caixas de texto, este não realizará ação alguma. Caso uma ou mais caixas de texto tenham
sido alteradas, somente os comandos referentes aos registradores correspondentes aos
parâmetros alterados serão enviados, de forma a tornar o processo mais rápido e minimizar o
uso desnecessário da porta serial.
42
Capítulo 4
4. Conclusão
Muitos dos testes foram sendo realizados junto com as etapas de desenvolvimento do
projeto. A placa Microboard LX9 tem botões e LEDs os quais tornavam possível um
diagnóstico se tais funções implementadas estavam funcionais.
Logo na fase inicial do desenvolvimento foi feito o divisor de frequência para que
dividisse o clock para um período de um segundo, com o objetivo de tornar visível através dos
LEDs da placa o formato de onda que o circuito estava gerando.
Quando a etapa de desenvolvimento foi concluída, era possível visualizar que os
diferentes segmentos do gerador estavam funcionando. Os seguintes itens foram testados,
dividindo a frequência para que o período do clock fosse um segundo e observando os
resultados através dos LEDs:
• Diferentes valores de período.
• Diferentes valores de largura de pulso.
• Diferentes valores do número de pulsos por trem de pulsos.
• Diferentes valores de defasagem entre canais.
• Taxa de perda de bytes da porta serial.
• Diferentes valores para o divisor de frequência.
Nenhum dos testes apresentaram qualquer inconsistência no funcionamento do
gerador.
A seguir todos os itens foram retestados sem uso do divisor de clock, sendo este o
maior possível, no caso, 100MHz, e a saída do circuito foi visualizada em osciloscópio.
Novamente nenhum dos testes apresentou qualquer inconsistência no circuito, sendo o
resultado de todos conforme o esperado.
43
Figura 19: Verificação da saída de 4 canais utilizando um osciloscópio digital.
Na Figura 18 podemos verificar um dos testes realizados com osciloscópio e na Figura
19 a configuração usada no software de controle.
44
Figura 20: Software de controle do gerador.
Podemos observar que a largura de pulso está configurada como 1 ciclo de clock em
todos os canais e o período total como 4 ciclos de clock. O número de pulsos está configurado
para zero, que significa infinitos pulsos, e em Delay observamos que cada canal está defasado
um do outro de 1 ciclo de clock. Vemos na imagem do osciloscópio que está coerente com o
esperado.
É importante notar que não houve a intenção de caracterizar a qualidade do sinal, o
nível de ruído, jitter e tempos de subida e descida, uma vez que o projeto é caracterizado
somente pelo circuito digital a ser implementado no FPGA e não a placa ou interface
eletrônica utilizada. Portanto, os itens citados são características somente do FPGA utilizado,
da placa de desenvolvimento e da forma com que foi medida utilizando o osciloscópio. Estes
não refletem a qualidade do projeto em si, mas só da plataforma em que foi implementado.
45
Referências bibliográficas
[1] CAEN Electronic Instrumentation. Mod. V1495 General Purpose VME Board. Itália:
2012, 41 p.
[2] CAEN Electronic Instrumentation. Mod. V820/V830, 32 ch. Latching/Multievent
Latching scaler. Itália: 2007, 48 p.
[3] CAEN Electronic Instrumentation. Mod. V1718 VME USB Bridge. Itália: 2007, 62 p.
[4] Avnet Microboard LX9 Getting Started. Disponível em: <http://www.em.avnet.com/en-
us/design/drc/Pages/Xilinx-Spartan-6-FPGA-LX9-MicroBoard.aspx> Acessao em 12 de
Fevereiro de 2013.
[5] XILINX. Spartan-6 FPGA Data Sheet. 2011, 89 p.
46
APÊNDICE
Apêndice I: Código fonte da entidade de nível superior
---------------------------------------------------------------------------------- -- Maurício Féo Rivello - [email protected] -- Projeto Final de engenharia. -- Interface para o Gerador de Pulsos Digitais ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity Placa_LX9 is Port ( --clk_40 : in STD_LOGIC; -- clock 40 MHz --clk_67 : in STD_LOGIC; -- clock 66.7 MHz clk_100 : in STD_LOGIC; -- clock 100 MHz --J4 : out STD_LOGIC_VECTOR (7 downto 0); -- I/Os (7 downto 0) J5 : out STD_LOGIC_VECTOR (3 downto 0); -- I/Os (7 downto 0) Led : out STD_LOGIC_VECTOR (3 downto 0); DIP : in STD_LOGIC_VECTOR (1 downto 0); -- In (3 downto 0) --BTN : in STD_LOGIC; -- Botão Serial_Rx : in STD_LOGIC; Serial_Tx : out STD_LOGIC ); end Placa_LX9; ------------------------------------------------------------------------------ architecture Behavioral of Placa_LX9 is COMPONENT pulse_gen2 PORT( width : IN std_logic_vector(15 downto 0); period : IN std_logic_vector(15 downto 0); N : IN std_logic_vector(15 downto 0); delay : IN std_logic_vector(15 downto 0); clock : IN std_logic; clk_gen : in std_logic; trigger : IN std_logic; veto : IN std_logic; pulse_out : OUT std_logic ); END COMPONENT;
47
COMPONENT UART_Rx PORT( clock : IN std_logic; Serial_Rx : IN std_logic; inByte : OUT std_logic_vector(7 downto 0); Rx_Flag : OUT std_logic ); END COMPONENT; COMPONENT UART_Tx PORT( ByteIn : IN std_logic_vector(7 downto 0); clock : IN std_logic; Go : IN std_logic; Busy : OUT std_logic; Rx_Out : OUT std_logic ); END COMPONENT; signal gen_out : std_logic_vector(3 downto 0); signal cont : integer range 0 to 2147483647 := 0; ----------------------------- Sinais do gerador -- signal clk_div, clk_gen : std_logic; signal trigger : std_logic := '0'; signal veto : std_logic := '1'; signal SW_trigger, SW_veto: std_logic; ----------------------------- Sinais da interface -- type reg_array16 is array (255 downto 0) of std_logic_vector (15 downto 0); signal reg : reg_array16 := ( 0 => X"0001", 1 => X"0004", 2 => X"0000", 3 => X"0000", 4 => X"0001", 5 => X"0004", 6 => X"0000", 7 => X"0001", 8 => X"0001", 9 => X"0004",10 => X"0000",11 => X"0002", 12 => X"0001",13 => X"0004",14 => X"0000",15 => X"0003", 200 => X"05F5", 201 => X"E100", OTHERS => X"0000" ); signal Rx_Flag : std_logic_vector(2 downto 0); signal Rx_Byte : std_logic_vector(7 downto 0); signal Tx_Busy : std_logic; signal Tx_Byte : std_logic_vector(7 downto 0);
48
signal Tx_Send : std_logic; type reg_array8 is array (4 downto 0) of std_logic_vector (7 downto 0); signal Rx_Buff : reg_array8 := ( OTHERS => X"00" ); constant Num_Canais : integer := 3; -- Numero de canais do gerador signal clk_divider : std_logic_vector(30 downto 0); --signal clk_divider : integer range 1 to 2147483647 := 1; ------------------------------------------------------------------------------ begin ---------------------------------------------------- Frequency divider clk_gen <= clk_100 when (reg(201)®(200)=X"00000001") else clk_div; clk_divider <= reg(201) & reg(200)(15 downto 1); frequency_divider: process (clk_100) begin if rising_edge(clk_100) then if (cont < to_integer(unsigned(clk_divider))-1) then cont <= cont+1; --clk_div<= clk_div; else cont <= 0; clk_div <= not clk_div; end if; end if; end process; ---------------------------------------------------- Gerador trigger <= DIP(0) or SW_trigger; veto <= DIP(1) or SW_veto; Gerando_canais: for k in 0 to Num_Canais generate begin Inst_pulse_gen2: pulse_gen2 PORT MAP( width => reg(4*k+0), period => reg(4*k+1), N => reg(4*k+2), delay => reg(4*k+3), clock => clk_100, clk_gen => clk_gen,
49
trigger => trigger, veto => veto, pulse_out => gen_out(k) ); end generate; J5 <= gen_out; Led <= gen_out; ---------------------------- Interface Registradores On_Serial_Rx : process(clk_100) begin if rising_edge(clk_100) then Rx_Flag(2 downto 1) <= Rx_Flag(1 downto 0); if std_match(Rx_Flag,"-01") then Rx_Buff <= Rx_Buff (3 downto 0) & Rx_Byte; Tx_byte <= Rx_Byte; Tx_Send <= '1'; elsif std_match(Rx_Flag,"01-") then if (Rx_Buff(4)&Rx_Buff(3)&Rx_Buff(2)&Rx_Buff(1)&Rx_Buff(0)=X"7374617274") then -- "start" SW_trigger <= '1'; SW_veto <= '0'; elsif (Rx_Buff(3)&Rx_Buff(2)&Rx_Buff(1)&Rx_Buff(0)=X"73746F70") then -- "stop" SW_trigger <= '0'; SW_veto <= '1'; elsif (Rx_Buff(4)=X"23")and(Rx_Buff(0)=X"2A") then -- "#---*" reg(to_integer(unsigned(Rx_Buff(1)))) <= Rx_Buff(3)&Rx_Buff(2); else SW_trigger <= '0'; SW_veto <= '0'; end if; else
50
Tx_Send <= '0'; end if; end if; end process; Inst_UART_Rx: UART_Rx PORT MAP( clock => clk_100, Serial_Rx => Serial_Rx, inByte => Rx_Byte, Rx_Flag => Rx_Flag(0) ); Inst_UART_Tx: UART_Tx PORT MAP( ByteIn => Tx_Byte, clock => clk_100, Go => Tx_Send, Busy => Tx_Busy, Rx_Out => Serial_Tx ); end Behavioral;
51
Apêndice II: Código fonte do Gerador de Pulsos
---------------------------------------------------------------------------------- -- Maurício Féo Rivello - [email protected] -- Projeto Final de engenharia. -- Gerador de Pulsos Digitais ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity pulse_gen2 is Port ( width : in STD_LOGIC_VECTOR (15 downto 0); period : in STD_LOGIC_VECTOR (15 downto 0); N : in STD_LOGIC_VECTOR (15 downto 0); delay : in STD_LOGIC_VECTOR (15 downto 0); clock : in STD_LOGIC; clk_gen : in STD_LOGIC; trigger : in STD_LOGIC; veto : in STD_LOGIC; pulse_out : out STD_LOGIC); end pulse_gen2; architecture Behavioral of pulse_gen2 is signal trig: std_logic_vector (1 downto 0):="00"; signal vet : std_logic_vector (1 downto 0):="00"; signal vetado : std_logic; signal delaying : std_logic; COMPONENT Delay_unit PORT( clock : IN std_logic; clk_gen : IN std_logic; reset : IN std_logic; delay : IN std_logic_vector(15 downto 0); delaying : OUT std_logic ); END COMPONENT; signal gen_out : std_logic; signal reset : std_logic;
52
signal gen_reset : std_logic; COMPONENT Gen_unit PORT( width : IN std_logic_vector(15 downto 0); period : IN std_logic_vector(15 downto 0); clk_gen : IN std_logic; reset : IN std_logic; gen_out : OUT std_logic ); END COMPONENT; signal N_vet : std_logic; COMPONENT N_unit PORT( N : IN std_logic_vector(15 downto 0); gen_out : IN std_logic; clock: IN std_logic; reset : IN std_logic; N_vet : OUT std_logic ); END COMPONENT; begin vet(0) <= veto; trig(0) <= trigger; pulse_out <= gen_out; gen_reset <= delaying or vetado or N_vet or reset; reset_process : process (clock) begin if rising_edge(clock) then trig(1) <= trig(0); vet(1) <= vet(0); if trig="01" then reset<='1'; vetado<='0'; elsif vet="01" then vetado<='1'; else reset<='0'; end if;
53
end if; end process; delayer: Delay_unit PORT MAP( clock => clock, clk_gen => clk_gen, reset => reset, delay => delay, delaying => delaying ); Generator_unit: Gen_unit PORT MAP( width => width, period => period, clk_gen => clk_gen, reset => gen_reset, gen_out => gen_out ); N_unit_inst: N_unit PORT MAP( N => N, gen_out => gen_out, clock => clock, reset => reset, N_vet => N_vet ); end Behavioral;
54
Apêndice III : Código fonte da unidade Delayer
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity Delay_unit is Port ( clock : in STD_LOGIC; clk_gen : in STD_LOGIC; reset : in STD_LOGIC; delay : in STD_LOGIC_VECTOR (15 downto 0); delaying : out STD_LOGIC); end Delay_unit; architecture Behavioral of Delay_unit is signal clkIn : STD_LOGIC_VECTOR (1 downto 0):= "00"; signal cont : STD_LOGIC_VECTOR (15 downto 0):= X"0000"; begin clkIn(0) <= clk_gen; process (clock) begin if (falling_edge(clock)) then clkIn(1) <= clkIn(0); if (reset = '1') then cont <= X"0000"; delaying <= '1'; else if (clkIn(1)='0') and (clkIn(0)='1') then if (cont<delay) then cont <= std_logic_vector(unsigned(cont)+1); delaying <= '1'; else cont <= cont; delaying <= '0'; end if; end if; end if; end if; end process; end Behavioral;
55
Apêndice IV: Código fonte da Generator Unit
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity Gen_unit is Port ( width : in STD_LOGIC_VECTOR (15 downto 0); period : in STD_LOGIC_VECTOR (15 downto 0); clk_gen : in STD_LOGIC; reset : in STD_LOGIC; gen_out : out STD_LOGIC); end Gen_unit; architecture Behavioral of Gen_unit is signal cont : STD_LOGIC_VECTOR (15 downto 0); begin process (clk_gen) begin if (clk_gen='1' and clk_gen'event) then if (reset='0') then if (cont<width) then gen_out <= '1'; else gen_out <= '0'; end if; if (unsigned(cont)<unsigned(period)-1) then cont <= std_logic_vector(unsigned(cont) + 1); else cont <= X"0000"; end if; else cont <= X"0000"; gen_out <= '0'; end if; end if; end process; end Behavioral;
56
Apêndice V: Código fonte da N_Unit
---------------------------------------------------------------------------------- -- Maurício Féo Rivello - [email protected] -- Projeto Final de engenharia. -- Gerador de Pulsos Digitais ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity N_unit is Port ( N : in STD_LOGIC_VECTOR (15 downto 0); gen_out : in STD_LOGIC; clock: in STD_LOGIC; reset : in STD_LOGIC; N_vet : out STD_LOGIC); end N_unit; architecture Behavioral of N_unit is signal gen : std_logic_vector (1 downto 0); signal cont : std_logic_vector (15 downto 0); signal output : std_logic; begin N_vet <= output; gen(0) <= gen_out; process (clock) begin if (falling_edge(clock)) then gen(1) <= gen(0); if (reset = '1') then output<='0'; cont <= X"0000"; else if (gen(1)='0') and (gen(0)='1') then cont <= std_logic_vector(unsigned(cont) + 1); end if; if (cont = N) and (N /= X"0000") then output<='1'; end if; end if; end if; end process;
58
Apêndice VI: Código fonte do Receptor UART
---------------------------------------------------------------------------------- -- Maurício Féo Rivello - [email protected] -- -- www.engenheirando.com -- -- Porta serial p/ Baud rate de 9600 bps com clock de 100MHz -- P/ usar clock/BR diferente, observar comentários abaixo ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity UART_Rx is Port ( clock : in STD_LOGIC; Serial_Rx : in STD_LOGIC; inByte : out STD_LOGIC_VECTOR (7 downto 0); Rx_Flag : out STD_LOGIC); end UART_Rx; architecture Behavioral of UART_Rx is signal cont : integer range 0 to 16000:= 0; -- observar o limite ao mudar o clock / baud rate signal bitsRecebidos : integer range 0 to 8:=0; signal inBits : std_logic_vector (7 downto 0); signal Rx_Antes : std_logic; type Estados is (Wait_Start_bit, Start_bit, Lendo_bits, Stop_bit); signal Estado : Estados; begin UART_Rx : process (clock) begin if rising_edge(clock) then Rx_Antes <= Serial_Rx; case Estado is ---------------------------------------------------------- when Wait_Start_bit => if (Rx_Antes = '1') and (Serial_Rx = '0') then Estado <= Start_bit; cont<=0; end if; ---------------------------------------------------------- when Start_bit => if (cont<15417) then -- 15417 = Clock / BaudRate * 1.5 cont<=cont+1; else
59
bitsRecebidos<=0; Estado <= Lendo_bits; end if; ---------------------------------------------------------- when Lendo_bits => if (bitsRecebidos<8) then if (cont<10417) then -- 10417 = Clock / BaudRate cont <= cont+1; else cont <=0; bitsRecebidos <= bitsRecebidos+1; inBits <= Serial_Rx & inBits(7 downto 1); end if; else inByte <= inBits; Rx_Flag <= '1'; Estado <= Stop_bit; end if; ---------------------------------------------------------- when Stop_bit => if (cont<5208) then -- Metade de 10417! cont<=cont+1; else cont<=0; Rx_Flag <= '0'; Estado <= Wait_Start_Bit; end if; ---------------------------------------------------------- when others => Estado <= Estado; end case; end if; end process; end Behavioral;
60
Apêndice VII: Código fonte do Transmissor UART
---------------------------------------------------------------------------------- -- Maurício Féo Rivello - [email protected] -- -- www.engenheirando.com -- -- Porta serial p/ Baud rate de 9600 bps com clock de 100MHz -- P/ usar clock/BR diferente, observar comentários abaixo ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity UART_Tx is Port ( ByteIn : in STD_LOGIC_VECTOR (7 downto 0); clock : in STD_LOGIC; Go : in STD_LOGIC; Busy : out STD_LOGIC; Rx_Out : out STD_LOGIC); end UART_Tx; architecture Behavioral of UART_Tx is signal outBuff : std_logic_vector (9 downto 0); -- envia do zero ao 7 do byte signal Go_Antes : std_logic:='0'; signal cont : integer range 0 to 11000:=0; -- observar o limite ao mudar o clock / baud rate signal bits_Sent : integer range 0 to 10:=0; type Estados is (Idle, Sending); signal Estado : Estados; signal Byte_em_Espera : boolean := false; begin UART_Tx : process (clock) begin if rising_edge(clock) then Go_Antes <= Go; case Estado is ---------------------------------------------------------- when Idle => Rx_Out <= '1'; if ((Go = '1')and(Go_Antes = '0')) or Byte_em_Espera then Byte_em_Espera <= false; outBuff <= '1' & ByteIn (7 downto 0) & '0'; -- stop + byte + start
61
cont <= 0; bits_Sent <= 0; Estado <= Sending; Busy <= '1'; end if; ---------------------------------------------------------- when Sending => Rx_Out <= outBuff(0); if ((Go = '1')and(Go_Antes = '0')) then Byte_em_Espera <= true; end if; if (bits_Sent<10) then if (cont<10417) then --10417 cont<=cont+1; else cont <= 0; bits_Sent <= bits_Sent+1; outBuff <= '0' & outBuff(9 downto 1); end if; else Estado <= Idle; Busy <= '0'; end if; ---------------------------------------------------------- when others => Estado <= Estado; end case; end if; end process; end Behavioral;
62
Apêndice VIII : Código fonte da unidade Single Pulser
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Single_Pulser is
Port ( trigger : in STD_LOGIC;
clock : in STD_LOGIC;
pulse : out STD_LOGIC);
end Single_Pulser;
architecture Behavioral of Single_Pulser is
signal QA: std_logic := '0';
signal QB: std_logic := '0';
begin
pulse <= QB;
process (trigger, QB)
begin
if QB='1' then
QA <= '0';
elsif (trigger'event and trigger='1') then
QA <= '1';
end if;
end process;
process (clock)
begin
if (clock'event and clock ='1') then
QB <= QA;
end if;
end process;
end Behavioral;