Teach Remote lab lessons

Teach lesson

Nios V na DE1-SoC (4/5): display HEX e temporizador

Compile e envie exemplos em C para o HEX0 e o temporizador de intervalo do Nios V e observe o comportamento de HEX0 e LEDR0 na DE1-SoC.

  • Nios V for DE1-SoC
  • 75 min
  • Graduação em Ciência ou Engenharia da Computação
  • Português (Brasil)
  • Digital systems & FPGA · Embedded systems
Nios V for DE1-SoC
Nios V for DE1-SoC · Lab details

Learning Outcomes

  • Usar periféricos validados de display e temporizador mapeados em memória no sistema Nios V fixo.

  • Explicar por que displays de sete segmentos precisam de padrões de segmentos codificados.

  • Configurar e consultar o temporizador de intervalo da FPGA em 0xFF202000.

  • Distinguir as entradas lógicas validadas NB0..NB3 via JP1/GPIO do caminho não compatível das teclas KEY da FPGAcademy no navegador.

  • Coletar evidências ao vivo do comportamento dos periféricos em uma placa DE1-SoC real.

Student activity preview

Activity Content

Preview only. In a class session, students can fill in responses and submit their work to the teacher.

1

De GPIO a periféricos

5 min

Nas lições anteriores, você usou E/S mapeada em memória com controles simples: entradas NSW do navegador, dados GPIO do JP1 e saídas LEDR. Esta lição mantém a mesma ideia, mas usa dois periféricos mais completos já incorporados ao sistema fixo da FPGA.

Um periférico é um bloco de hardware que o processador Nios V controla ao ler ou gravar um endereço específico. Você não modificará o projeto da FPGA nesta lição. Substituirá main.c por pequenos exemplos em C, compilará um arquivo ELF, enviará esse arquivo e verificará se o comportamento da placa corresponde à explicação no nível dos registradores.

Os dois exemplos obrigatórios são:

- hex_counter, que grava padrões codificados em HEX0.
- timer_blink, que configura o temporizador de intervalo e alterna LEDR0.

Para consultar o mapa completo de registradores, use o manual FPGAcademy DE1-SoC Computer with Nios V. Esta atividade apresenta o subconjunto necessário: HEX3_HEX0 em 0xFF200020 e o temporizador de intervalo em 0xFF202000.

Subconjunto do mapa de registradores Nios V com HEX3_HEX0 e o temporizador de intervalo usados pelos exemplos de contador HEX e LED temporizado.

Esta lição usa dois caminhos de registradores validados do sistema Nios V fixo: a saída do display HEX e a temporização de LED controlada pelo temporizador de intervalo.

O navegador mostra controles de botões lógicos específicos do Nios V, com os rótulos NB0..NB3. Essas são entradas validadas via JP1/GPIO, e não o registrador KEY da FPGAcademy em 0xFF200050.

Para o trabalho obrigatório desta lição, use os exemplos de HEX e temporizador abaixo. A seção opcional de botões é independente caso seja atribuída: use NB0..NB3 como entradas lógicas do JP1 e evite a nomenclatura KEY0..KEY3.

Considere um periférico pronto para o curso somente quando houver evidência ao vivo no perfil atual do laboratório LabsLand. Um registrador pode existir no sistema de referência e ainda assim não servir para uma atividade remota se o caminho do controle no navegador não estiver conectado a ele.

2

Registrador de saída HEX

22 min

Os displays HEX são displays de sete segmentos. Um dígito não é gravado como o número 3; ele é gravado como um padrão de bits que acende ou apaga segmentos individuais.

O exemplo hex_counter grava padrões de segmentos em HEX3_HEX0, no endereço 0xFF200020.

Cada byte de HEX3_HEX0 controla um display. Neste programa inicial, somente o byte menos significativo é usado; portanto, apenas HEX0 muda. Um valor como 0x3F não é o número zero no sentido habitual: é o padrão de segmentos que acende os segmentos necessários para formar 0.

Exemplos:

- O dígito 0 usa o padrão 0x3F.
- O dígito 1 usa o padrão 0x06.
- O dígito A usa o padrão 0x77.

  1. Abra Nios V C IDE for DE1-SoC.

  2. Substitua o código inicial pelo código de hex_counter abaixo.

  3. Clique em Build ELF (Compilar ELF) e envie o arquivo para a FPGA com Upload to FPGA.

  4. Observe HEX0 na visualização da placa por pelo menos dois dígitos diferentes.

  5. Registre se HEX0 percorre valores hexadecimais.

Use este código para hex_counter:

Selecione todo o bloco de código antes de copiá-lo para main.c; substitua todo o código inicial.

/* Computador DE1-SoC com Nios V — E/S mapeada em memória */
volatile int *HEX3_HEX0 = (int *) 0xFF200020;  /* 7 segmentos HEX3..HEX0 */

static const unsigned char HEX_CODE[16] = {
    0x3F, 0x06, 0x5B, 0x4F,
    0x66, 0x6D, 0x7D, 0x07,
    0x7F, 0x67, 0x77, 0x7C,
    0x39, 0x5E, 0x79, 0x71
};

static void delay(void)
{
    volatile int i;
    for (i = 0; i < 2000000; i++) {
    }
}

int main(void)
{
    int count = 0;

    while (1) {
        *HEX3_HEX0 = HEX_CODE[count & 0xF];
        count++;
        delay();
    }
    return 0;
}

Use a tabela para registrar o que você viu depois de enviar hex_counter. O comportamento esperado já está preenchido. Adicione dois dígitos ou padrões diferentes vistos em HEX0 e selecione passou, falhou ou incerto na coluna de resultado.

Registre uma verificação de HEX0 na placa ao vivo. Mantenha o comportamento esperado, a menos que o professor peça outro teste; anote dois dígitos ou padrões observados e selecione passou, falhou ou incerto.

Comportamento esperado Primeiro dígito ou padrão observado Segundo dígito ou padrão observado Resultado

Por que o exemplo usa uma tabela de consulta de padrões de segmentos em vez de gravar os valores inteiros 0, 1, 2 e assim por diante diretamente no registrador HEX?

3

Temporizador de intervalo

22 min

O exemplo timer_blink programa o temporizador de intervalo da FPGA no endereço-base 0xFF202000. Ele define um período, inicia o temporizador, consulta o bit de fim de período, limpa esse bit e alterna LEDR0.

O clock do temporizador é de 100 MHz; portanto, 50.000.000 de pulsos correspondem a aproximadamente meio segundo. O período de 32 bits é dividido em dois registradores de 16 bits porque a interface do temporizador armazena separadamente as metades menos e mais significativas.

Registradores do temporizador usados aqui:

- STATUS no deslocamento +0x0: o bit 0, TO, passa a 1 quando o período termina.
- CONTROL no deslocamento +0x4: STOP, START e CONT controlam se o temporizador funciona continuamente.
- PERIOD_LO no deslocamento +0x8: 16 bits menos significativos do período.
- PERIOD_HI no deslocamento +0xC: 16 bits mais significativos do período.

  1. Substitua o código C pelo código de timer_blink abaixo.

  2. Clique em Build ELF (Compilar ELF) e envie com Upload to FPGA.

  3. Observe LEDR0 por pelo menos 10 segundos.

  4. Registre pelo menos dois momentos em que o estado do LED muda.

  5. Avalie se a alternância é estável o bastante para servir como fonte de temporização.

Use este código para timer_blink:

Selecione todo o bloco de código antes de copiá-lo para main.c; substitua todo o código anterior.

/* Computador DE1-SoC com Nios V — E/S mapeada em memória */
volatile int *LEDS = (int *) 0xFF200000;  /* LEDs vermelhos */

#define TIMER_BASE      0xFF202000
#define TIMER_STATUS    (*(volatile short *)(TIMER_BASE + 0x0))
#define TIMER_CONTROL   (*(volatile short *)(TIMER_BASE + 0x4))
#define TIMER_PERIOD_LO (*(volatile short *)(TIMER_BASE + 0x8))
#define TIMER_PERIOD_HI (*(volatile short *)(TIMER_BASE + 0xC))

#define TIMER_TO        0x1
#define TIMER_CONT      0x2
#define TIMER_START     0x4
#define TIMER_STOP      0x8

int main(void)
{
    const unsigned int half_second = 50000000u;  /* clock do temporizador: 100 MHz */
    int led = 0;

    TIMER_CONTROL = TIMER_STOP;
    TIMER_PERIOD_LO = (short)(half_second & 0xFFFFu);
    TIMER_PERIOD_HI = (short)((half_second >> 16) & 0xFFFFu);
    TIMER_STATUS = 0;  /* limpar TO */
    TIMER_CONTROL = TIMER_CONT | TIMER_START;

    while (1) {
        if ((TIMER_STATUS & TIMER_TO) != 0) {
            TIMER_STATUS = 0;  /* limpar TO */
            led ^= 1;
            *LEDS = led;
        }
    }
    return 0;
}

Use a tabela para registrar a alternância controlada pelo temporizador. Mantenha a janela de 10 segundos, a menos que o professor solicite um teste mais longo. Na coluna de evidência, escreva o que mudou, por exemplo, apagado -> aceso -> apagado, e selecione passou, falhou ou incerto.

Registre uma observação do temporizador. Use uma janela de 10 segundos, descreva as mudanças de estado observadas em LEDR0 e selecione passou, falhou ou incerto.

Janela de observação (s) Mudanças de estado observadas em LEDR0 Comportamento esperado Resultado

Qual é a diferença entre esta alternância controlada pelo temporizador e um laço de espera por software? Mencione os registradores de período, o bit de fim de período e uma razão pela qual um temporizador de hardware pode ser útil em software embarcado.

4

Uma pequena modificação no periférico

18 min

Escolha um dos exemplos validados e faça uma mudança pequena e observável.

Exemplos:

- Em hex_counter, mude a sequência para contar somente valores hexadecimais pares.
- Em hex_counter, controle dois dígitos HEX em vez de apenas HEX0.
- Em timer_blink, mude o período para que LEDR0 alterne mais rápido ou mais devagar.
- Em timer_blink, alterne outro bit de LED.
- Trabalho opcional com botões: leia os bits 0 a 3 do JP1 por meio de NB0..NB3 e mostre-os em LEDR0..LEDR3.

  1. Escolha o exemplo de HEX ou de temporizador.

  2. Faça uma pequena alteração no código.

  3. Compile e envie o arquivo ELF.

  4. Observe a placa e registre como o comportamento mudou.

Envie as linhas de código alteradas e identifique qual registrador mapeado em memória cada linha afeta.

Mantenha a modificação pequena o bastante para validá-la em uma única sessão da placa. Uma boa entrega altera um comportamento e pode ser verificada com uma ou duas observações.

Envie uma nota de observação concisa: o que mudou, o que você esperava ver e o que a placa ao vivo mostrou.

5

Opcional: botões lógicos NB

Os botões lógicos NB0..NB3 foram validados nos bits 0 a 3 do registrador de dados JP1. Eles servem para um exercício rápido de consulta, mas não correspondem à porta KEY3..KEY0 da FPGAcademy.

Padrão mínimo em C:

volatile int *LEDS = (int *) 0xFF200000;
volatile int *JP1 = (int *) 0xFF200060;
volatile int *JP1_DIR = (int *) 0xFF200064;

*JP1_DIR = 0;
while (1) {
    *LEDS = (*JP1) & 0xF;   // NB0..NB3 -> LEDR0..LEDR3
}

Por que este exercício opcional lê os bits 0 a 3 do JP1 em vez de ler o registrador KEY da FPGAcademy em 0xFF200050?

Se você executar o exercício opcional, registre um botão NB que pressionou e o bit de LED que mudou.

6

Prepare o projeto final

8 min

O projeto final deve usar NSW0..NSW9 e LEDR0..LEDR9, além de pelo menos um periférico de extensão validado nesta lição.

Qual periférico de extensão você provavelmente usará no projeto final?

Descreva um comportamento do projeto final que combine NSW/LEDR com o periférico de extensão escolhido. Inclua o endereço ou os endereços de registradores que pretende usar.