Memória RAM com Saída Temporizada – Placa DE0
O projeto a seguir tem como objetivo apresentar a saída de um memória implementada no FPGA Ciclone III presente na placa DE0 de forma periódica. O projeto fará a leitura dos endereços da memória de forma sequencial e sendo incrementada a cada 0,5s e a escrita pode ser feita concomitantemente com a leitura.
O projeto é implementado em VHDL e simulado com o Modelsim-Altera, por meio de testbench sendo este um exemplo de circuito sequencial.
Nesse projeto será utilizado apenas a Placa DE0®.
Descrição do Funcionamento
Para este projeto será implementado uma memória de 8 x 8, a qual poderá ser lida e escrita ao mesmo tempo. O projeto também apresentará um contador interno para temporizar a saída, de forma que a cada 0,5s incrementa o endereço de memória lido. O projeto utilizará 9 chaves, sendo 1 de chip enable e 8 para a escrita de dados, 2 botões e 8 LEDs para apresentar o dado lido.
Descrição em VHDL
Para implementar memória do projeto criou-se um tipo de varivel usando um array com 8 posições de std_logic_vector de 8 bits, formando assim a memória de 8×8. O preescaler para incrementar o endereço de saída precisa dividir por 25M, pois o clock é de 50Mhz e o objetivo é a mudança do endereço a cada 0,5s.
O Código começa com a declaração da entidade:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
entity RAM_vs3 is port ( clock, resetn, wren, cen: in std_logic; -- Entrada de Dados saida: dado: in std_logic_vector (7 downto 0); -- Leitura da memoria out std_logic_vector (7 downto 0) -- Leitura da memoria ); end entity; |
Dentro da architecture se declara o tipo memória para a utilização em seguida do sinal desse tipo, que será a memória RAM do projeto.
1 2 3 4 5 |
architecture ccomportamento of RAM_vs3 is type memoria is array (integer range 0 to 7) of std_logic_vector(7 downto 0); signal mem_ram : memoria := ( x"00", x"01", x"02", x"03", x"04", x"05", x"06", x"07"); |
O processo principal pode ser dividido em quatro partes: reset, escrita, proteção contra ruído e leitura. Primeiramente se declara as variáveis usadas no processo:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
process (clock, resetn) variable addr_write, addr_read : std_logic_vector(2 downto 0) := "111"; -- Variavel para evitar ruido de trepidacao variable conta : integer range 0 to 25000000 := 0; -- variavel usada parra preescaler variable cont: integer range 0 to 25000000; variable flag: std_logic := '0'; |
Quando o reset está pressionado são assumidos os valores padrão de inicio do programa , apresentados abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
begin if resetn = '0' then addr_write := "111"; addr_read := "111"; cont := 0; conta := 0; flag := '0'; saida |
A escrita possui quatro variáveis de controle: wren, cen, flag, conta. O signal wren (write enable) indica se foi solicitado a escrita de um dado. A variável cen (chip enable) determina se a memória está habilitada, a flag previne que em uma única requisição seja gravado um dado em mais de um endereço de memória. Por último, a variável conta tem por objetivo rejeitar o ruído de trepidação gerado ao pressionar o botão.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
elsif clock'event and clock = '1' then -- Flag serve para evitar que grave em varias posicoes de -- memória com um mesmo pulso e conta serve para evitar -- o ruido de trepidacao proveniente do push bottom if wren = '0' and cen = '0' and flag = '0' and conta = 25000000 then conta := 0; addr_write := addr_write + "001"; mem_ram (to_integer(unsigned(addr_write))) flag := '1'; elsif wren = '1' then flag := '0'; end if; |
A proteção contra ruído funciona como um delay para que possa ser feita a próxima gravação, nesse caso adotou-se 0,5s.
1 2 3 4 5 6 7 |
-- contagem para evitar ruido de trepidacao if conta < 25000000 then conta := conta + 1; end if; |
A leitura ocorre enquanto o cen está habilitado. Para a leitura há um prescaler de 25M para que o endereço lido só seja incrementado a cada 0,5s. Quando o cen não está habilitado, atribui-se alta impedância para a saída.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
if cen = '0' then cont := cont + 1; if cont = 25000000 then cont := 0; addr_read := addr_read + "001"; saida <= mem_ram(to_integer(unsigned(addr_read))); end if; else saida <= "ZZZZZZZZ"; end if; |
Simulação
Para simular o funcionamento da memória será mandado o comando de gravação de alguns dados e ler os dados gravados. Para diminuir o tempo da simulação alterou-se o topo do valor da variável responsável pela proteção contra ruído para 3. O código do testbench é composto por duas partes: a geração de clock e a simulação de leitura e escrita. Abaixo segue o processo responsável pela geração de clock:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
gera_clock: process begin for cont in 0 to 100 loop CLOCK <= '0'; wait for 1 ms; CLOCK <= '1'; wait for 1 ms; end loop; wait; end process; |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
process begin ce <= '1'; resetn <= '0'; dado <= x"00"; wren <= '1'; wait for 5 ms; |
Em seguida, atribui-se os valores de reset e cen de forma que o projeto possa funcionar.
1 2 3 4 5 6 7 |
ce <= '0'; wait for 5 ms; resetn <= '1'; wait for 5 ms; |
O passo seguinte é mandar os pulsos de escrita e de leitura para observar se o projeto funcionará como esperado. Note que há uma sequencia de pulsos de habilitação de escrita para testar a proteção contra ruído.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
wren <= '0'; wait for 1 ms; wren <= '1'; wait for 1 ms; wren <= '0'; wait for 2 ms; wren <='1'; dado <= x"AA"; wait for 1 ms; wren <= '0'; wait for 5 ms; wren <='1'; wait for 10 ms; ce <= '1'; wait for 5 ms; ce <= '0'; wait for 5 ms; dado <= x"F0"; wren <= '0'; wait for 2 ms; wren <= '1'; wait; end process; |
O resultado obtido na simulação pode ser observado pelas formas de onda abaixo:
Figura 2: Formas de onda simuladas
FIgura 3: Forma de onda simuladas (continuação).
Estrutura Física
Figura 4: Projeto implementado na placa DE0.
O projeto conta apenas com a placa DE0®, de forma a utilizar 8 LEDs representando a saída, 8 chaves para a entrada de dados, 1 chave para a entrada da habilitação de chip, 1 botão de reset, 1 botão de habiliatação de escrita e 1 pino para o clock. Para a atribuição de pinos utilizou-se o manual do usuário da placa DE0®.
Figura 5: Atribuição de pinos do projeto
Gravação e Teste
Para fazer o teste basta gravar o programa seguindo as intruções encontradas no tutorial ou no próprio manual da placa DE0. Em seguida basta dar os comandos de gravação e leitura e observar o resultado. Abaixo segue o video de operação do projeto:
Arquivos de Projeto
Links Externos
- Site oficial DE0 (Inglês).