Você está na página 1de 6

Machine Translated by Google

Sistemas Embarcados
Exercício de Laboratório 2
Desenvolvendo programas Linux* que se comunicam com o FPGA

Parte I
No Exercício de Laboratório 1, você foi solicitado a escrever um programa em nível de usuário para controlar as luzes LED em sua
placa da série DE. Aqui você deve escrever outro programa em nível de usuário, que mostra uma mensagem de rolagem em um
display. Se você estiver® usando placas Intel DE1-SoC ou DE10-Standard, poderá usar monitores de sete segmentos para mostrar a
mensagem de rolagem. Seu programa deve exibir a mensagem Intel SoC FPGA e rolar a mensagem da direita para a esquerda nos
monitores. As letras da mensagem podem ser construídas como

As portas de exibição de sete segmentos nos sistemas de computador DE1-SoC e DE10-Standard são ilustradas na Figura 1.

Endereço

0xFF200020 0
31 30 24 23 22 16 15 14 8 7 6 0 Registro de dados

... ... ... ... 5 6 1

4 2
HEX36-0 HEX26-0 HEX16-0 HEX06-0
3

Segmentos

0xFF200030
31 30 24 23 22 16 15 14 8 7 6 0 Registro de dados

... ...
Não utilizado

HEX56-0 HEX46-0

Figura 1: As portas de exibição de sete segmentos.

Como alternativa aos monitores de sete segmentos, você pode usar a janela do Terminal Linux*. Neste caso, você deve designar um
espaço de seis caracteres no display para mostrar a mensagem. Você pode “desenhar” uma caixa usando caracteres ASCII conforme
ilustrado abaixo:

------

| |
------

Se a mensagem for rolada dentro desta caixa, o efeito será semelhante em aparência ao uso de (seis) displays de sete segmentos.
Alguns comandos da janela do Terminal estão listados na Tabela 1. Por exemplo, o comando \e[2J limpa a janela do Terminal e o
comando \e[H move o cursor do Terminal para a posição inicial no canto superior esquerdo da janela. Nestes comandos \e representa
o caractere Escape. Alternativamente, pode ser especificado pelo seu código ASCII, usando a sintaxe \033. Você pode enviar esses
comandos para a janela do Terminal usando a função printf. Por exemplo, a janela do Terminal pode ser limpa chamando

1
Machine Translated by Google

printf("\e[2J"); flush (saída //limpa a janela do Terminal


padrão);

Informações adicionais sobre os comandos da janela do Terminal Linux podem ser encontradas pesquisando na Internet por
Códigos de escape VT100.

Tabela 1: Comandos ASCII da janela do terminal.

Resultado do Comando

\e7 salvar posição e atributos do cursor


\e8 restaurar a posição e os atributos do cursor
\e[H mova o cursor para a posição inicial
\e[?25l \e[? ocultar o cursor

25h \e[2J mostrar o cursor

limpar janela
\e[ccm definir cor de primeiro plano para cc1
\e[yy;xxH define a localização do cursor para linha yy, coluna xx

Para exibições de sete segmentos e para a janela do Terminal, use um atraso ao rolar a mensagem para que o
as letras mudam para a esquerda a uma velocidade razoável. Para implementar o atraso necessário você pode usar uma função de biblioteca Linux
como o nanossono.

Execute o seguinte:

1. Crie um arquivo chamado part1.ce digite seu código C neste arquivo. Se você está usando monitores de sete segmentos
ou a janela do Terminal, seu código deve ser basicamente o mesmo. Em um caso, você escreve seis caracteres por vez
da mensagem para as portas de exibição de sete segmentos e, no outro caso, você imprime esses mesmos caracteres
(dentro da caixa) na janela do Terminal.

Você deve fornecer a capacidade de pausar ou executar a operação de rolagem usando os botões KEY. O
Os registros de programação em uma porta KEY da série DE são ilustrados na Figura 2. Há um registro de dados que
reflete quais TECLAS estão pressionadas em um determinado momento. Por exemplo, se a KEY0 estiver sendo pressionada,
então o bit 0 do registro de dados será 1, caso contrário 0. O registro Edgecapture pode ser usado para verificar se uma chave
foi pressionado desde a última vez que foi examinado, mesmo que já tenha sido liberado. Se, por exemplo, TECLA0 for pressionada
então o bit 0 do registro Edgecapture se torna 1 e permanece assim mesmo se KEY0 for liberado. Para redefinir o bit
para 0, um programa deve escrever explicitamente o valor 1 nesta posição de bit do registrador Edgecapture. O
O registro Interruptmask na Figura 2 não é usado neste exercício e pode ser ignorado.

Endereço 31 30 ...
4 3 2 1 0

0xFF200050 Não utilizado CHAVE3-0 Registro de dados

Não utilizado Não utilizado

0xFF200058 Não utilizado Pedaços de máscara Registro de máscara de interrupção

0xFF20005C Não utilizado Pontas de borda Registro de captura de borda

Figura 2: A porta KEY do botão.

Para se comunicar com os KEYs e displays de sete segmentos, se aplicável, use E/S mapeada em memória como
explicado no tutorial Usando Linux em placas da série DE. O código-fonte deste tutorial para tradução
endereços físicos em endereços virtuais está incluído junto com os arquivos de projeto para este exercício de laboratório.
Você pode usar esse código-fonte como parte de sua solução.

2
Machine Translated by Google

2. Compile seu código usando um comando como gcc -Wall -o part1 part1.c.

3. Execute e teste seu programa.

parte II

No Exercício de Laboratório 1, você foi solicitado a escrever um módulo de kernel para controlar as luzes LED e exibir um dígito, seja em um
display de sete segmentos ou na janela do Terminal. O módulo do kernel respondeu às interrupções geradas pela porta do botão KEY. Aqui
você deve escrever outro módulo do kernel orientado a interrupções.

Seu módulo do kernel deve implementar um relógio em tempo real. Exiba a hora em monitores de sete segmentos, se disponíveis, e/ou na
janela do Terminal. A hora deve ser exibida no formato MM:SS:DD, onde MM são minutos, SS são segundos e DD são centésimos de
segundo. Para controlar o tempo, você deve usar um módulo de temporizador de hardware.
Os computadores da série DE incluem vários temporizadores de hardware. Para este exercício utilize um temporizador de intervalo
implementado no FPGA chamado FPGA Timer0. A interface de registro para este temporizador possui o endereço base 0xFF202000.
Conforme mostrado na Figura 3 , este temporizador possui seis registradores de 16 bits. Para usar o temporizador, você precisa escrever
um valor adequado nos registros de valor inicial do contador (um para os 16 bits superiores e outro para os 16 bits inferiores do valor do contador de 32 bits).
Para iniciar o contador, você precisa definir o bit START no registro de controle para 1. Uma vez iniciado, o temporizador fará a contagem
regressiva até 0 a partir do valor inicial no registro de valor inicial do contador. O contador recarregará automaticamente este valor e
continuará contando se o bit CONT no registro de controle for 1. Quando o contador atingir 0, ele definirá o bit TO no registro de status como
1. Este bit pode ser apagado sob controle do programa escrevendo um 0 nele. Se o bit ITO no registrador de controle for definido como 1, o
temporizador gerará uma interrupção para o processador ARM cada vez que definir o bit TO. A frequência do clock do temporizador é de
100 MHz. O ID de interrupção do temporizador é 72. Siga as instruções no tutorial Usando Linux em placas da série DE para registrar esse
ID de interrupção no kernel do Linux e garantir que ele invoque seu módulo do kernel sempre que a interrupção ocorrer.

Endereço 31 . . . 17 16 15 ... 3 2 1 0

0xFF202000 Não utilizado CORRA PARA Registro de status

0xFF202004 Não utilizado PARE COMECE CONTINUE


Registro de controle

0xFF202008 Não presente (o Valor inicial do contador (baixo)


temporizador de intervalo
possui registros de 16 bits) Valor inicial do contador (alto)
0xFF20200C

0xFF202010 Instantâneo do contador (baixo)

0xFF202014 Instantâneo do contador (alto)

Figura 3: A interface de registro FPGA Timer0.

Execute o seguinte:

1. Crie um arquivo chamado timer.c e digite seu código C neste arquivo.

2. Crie um Makefile adequado que possa ser usado para compilar seu módulo do kernel e crie o arquivo timer.ko. Insira este módulo no
kernel usando o comando insmod timer.ko. Cada vez que ocorre uma interrupção, sua rotina de serviço de interrupção deve
incrementar o valor do tempo. Quando o horário chegar a 59:59:99, deverá chegar às 00:00:00.

Se estiver usando monitores de sete segmentos, você poderá exibir continuamente a hora atualizada. Mas se estiver usando a
janela do Terminal, é melhor imprimir a hora somente quando o usuário solicitar. Sua rotina de serviço de interrupção do temporizador
deve ler o registro de dados na porta KEY e imprimir a hora sempre que KEY1 for pressionada.

3
Machine Translated by Google

Você pode remover seu módulo do kernel Linux usando o comando rmmod timer. Quando removida, sua rotina de saída
deverá limpar os displays de sete segmentos, se aplicável.

Parte III
Para esta parte você deverá escrever um módulo de kernel que implemente um cronômetro. O tempo do cronômetro deve ser
mostrado em displays de sete segmentos ou na janela do Terminal. A hora deve ser definida usando os interruptores SW e os botões
KEY em seu computador da série DE. A hora deve ser exibida no formato MM:SS:DD como foi feito na Parte II. Implemente o módulo
cronômetro usando duas fontes de interrupções: o temporizador de hardware FPGA Timer0 e a porta do botão KEY. Para cada
interrupção do cronômetro deverá decrementar o cronômetro até atingir 00:00:00.

O comportamento da rotina de serviço de interrupção para a porta KEY do botão depende de qual placa da série DE está sendo
usada. Se você estiver usando a placa DE1-SoC ou DE10-Standard, siga as instruções na Tabela 2. Para a placa DE10-Nano, que
possui menos chaves e interruptores SW, implemente as ações fornecidas na Tabela 3.

Tabela 2: Ações de interrupção para as placas DE1-SoC e DE10-Standard.

Ação CHAVE

TECLA0 Alterna o cronômetro para funcionar ou pausado TECLA1


Quando pressionada, use os valores dos interruptores SW para definir a parte DD do tempo do cronômetro.
O valor máximo é 99
TECLA2 Quando pressionada, utiliza os valores dos interruptores SW para definir a parte SS do tempo do cronômetro.
O valor máximo é 59
TECLA3 Quando pressionada, utiliza os valores dos interruptores SW para definir a parte MM do tempo do cronômetro.
O valor máximo é 59

Tabela 3: Ações de interrupção para a placa DE10-Nano.

Ação CHAVE

KEY0 Alterna o cronômetro para funcionar ou pausar KEY1 Se o


cronômetro estiver funcionando, basta imprimir a hora atual na janela do Terminal. Mas se o cronômetro estiver parado,
acerte a hora usando os valores do interruptor SW. Defina um dígito do cronômetro cada vez que a TECLA1
for pressionada, em uma sequência específica. Para a primeira pressão, defina o dígito direito de DD, para a
segunda pressão, defina o dígito esquerdo de DD, para a terceira pressão, defina o dígito direito de SS e
assim por diante. Após cada pressão da TECLA1 imprima o tempo atual do cronômetro.

Os registros de dados na porta do switch SW para as placas DE1-SoC e DE10-Standard são mostrados na Figura 4. A porta do switch
SW para a placa DE10-Nano, não mostrada na figura, possui apenas quatro switches SW0 a SW3.

Endereço

0xFF200040
31 Não utilizado 10 9 ... 0 Registro de dados

SW9 SW0

Figura 4: A porta do switch SW.

Execute o seguinte:

4
Machine Translated by Google

1. Crie um arquivo chamado stopwatch.c e digite seu código C neste arquivo.

2. Crie um Makefile adequado que possa ser usado para compilar seu módulo do kernel e crie o arquivo stopwatch.ko.
Certifique-se de que o módulo timer da Parte II já tenha sido removido do kernel, pois ele também responde às
interrupções do FPGA Timer0. Em seguida, insira o módulo cronômetro no kernel usando o comando insmod
stopwatch.ko.

Se você estiver usando monitores de sete segmentos, assim que o módulo for inserido você deverá ver o tempo
59:59:99 começar a diminuir nos monitores. Mas se você estiver usando a janela do Terminal, deverá ver o tempo do
cronômetro sempre que o usuário pressionar a TECLA1.

Você pode remover seu módulo do kernel Linux usando o comando rmmod stopwatch. Quando removida, sua rotina de saída
deverá limpar os displays de sete segmentos, se aplicável.

5
Machine Translated by Google

Direitos autorais © FPGAcademy.org. Todos os direitos reservados. FPGAcademy e o logotipo FPGAcademy são marcas registradas de
FPGAcademy.org. Este documento é fornecido "no estado em que se encontra", sem garantia de qualquer tipo, expressa ou implícita,
incluindo, entre outras, garantias de comercialização, adequação a uma finalidade específica e não violação. Em nenhum caso os autores
ou detentores de direitos autorais serão responsáveis por qualquer reclamação, dano ou outra responsabilidade, seja em uma ação
contratual, ilícita ou de outra forma, decorrente de, de ou em conexão com o documento ou o uso ou outras negociações no documento.

*Outros nomes e marcas podem ser reivindicados como propriedade de terceiros.

Você também pode gostar