VGA para FPGA
Figura 1 – Foto do projeto.
Nesta página será apresentado um método de apresentar imagens de um FPGA para um monitor através de uma porta VGA. Para tal tarefa, será feita uma breve explicação do funcionamento da sincronização VGA, um método de enviar imagens e ler ler a memória. Uma vez implementado, o projeto permite apresentar qualquer imagem, desde que esteja no formato adequado, isto nos permite uma grande variedade de aplicações.
Figura 2 – Imagem mostrada na tela
O projeto a seguir é um exemplo de circuito lógico sequencial, descrito em VHDL e simulado no software ModelSim®-Altera, através de um test bench.
Os dispositivos necessários para a implementação do projeto são:
- Uma placa ALTERA DE0.
- Uma interface serial-VGA.
- Um monitor com entrada VGA.
Funcionamento da porta VGA
Sincronização
Uma tela no modo VGA é dividida em linhas, cada linha é dividido em pontos (pixels). Geralmente a tela 480 linhas e cada uma com 640 pixels que só podem ser acesos um por vez. Para formamos uma imagem, usamos o efeito da persistência da visão, também usado no projto Multiplexação de 6 algarismos.
Para “enganar” a visão, faremos o monitor apresentar 60 quadros a cada segundo (60 hz), por isso deveremos sincronizar o FPGA com o mesmo, para podermos controlar o que será apresentado.
Para a sincronização com o monitor, precisamos enviar dois pulsos de sincronismo um vertical e um horizontal. O horizontal, apresentado na Figura 2, indica para o monitor que acabou a linha na qual ele estava mostrando os pixels e que ele deve passar para a próxima.
Figura 3 – Sincronismo Horizontal
O vertical, apresentado na Figura 3, indica para o monitor que acabou a tela e que ele deve começar a próxima.
Figura 4 – Sincronismo Vertical
Cada pixel apresentará 12 bits para a cor, no modelo RGB que serão enviados através da porta.
Para mais informações sobre o funcionamento da porta VGA , clique aqui.
VGA para FPGA
Blocos do projeto
Para facilitar o entendimento, o projeto foi dividido em componentes como mostra a Figura 5.
Figura 5 – Blocos do projeto
Sincronismo
Componente que envia os sinais de sincronismo para o monitor.
O componente possui um contador de pulsos de clock para marcar o tempo. A DE0 possui um clock de 50MHz, fazemos a contagem de pulsos até completar uma linha, seguindo os tempos de sincronismo apresentados na Figura 3.
Tempo(us) |
Pulsos de Clock |
25,17 | 1258 |
26,11 | 1306 |
29,88 | 1494 |
31,77 | 1588 |
O trecho de código abaixo, apresenta o método utilizado para a sincronização dos sinais responsáveis pelo sincronismo horizontal.
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 |
If (cont_x >= H_max) then -- H_max = 1588 cont_x <= "00000000000"; Else cont_x <= cont_x + "00000000001"; End if; -- O Horiz_Sync deve permanecer em nível lógico alto por 27,06 us -- então em baixo por 3,77 us If (cont_x <= 1494) and (cont_x >= 1306) Then Horiz_Sync <= '0'; ELSE Horiz_Sync <= '1'; End if; -- Ajusta o tempo do Video_on_H If (cont_x <= 1258) Then video_on_H <= '1'; ELSE video_on_H <= '0'; End if; |
Quando a contagem chega ao fim da linha incrementa-se a contagem de linhas. Os sinais de sincronismo são enviados de acordo com os tempos apresentados na Figura 4.
Tempo(ms) |
Contagem de Linhas |
15,250 | 479 |
15,700 | 495 |
15,764 | 496 |
16,764 | 528 |
O trecho de código abaixo, apresenta o método utilizado para a sincronização dos sinais responsáveis pelo sincronismo vertical.
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 |
If (cont_y >= V_max) and (cont_x >= 736) then cont_y <= "00000000000"; Elsif (cont_x = H_Max) Then cont_y <= cont_y + "00000000001"; End if; -- Generate Vertical Sync Signal If (cont_y <= 496) and (cont_y >= 495) Then -- Gera sinal de sincronismo vertical Vert_Sync <= '0'; ELSE Vert_Sync <= '1'; End if; -- Ajusta o tempo do Video_on_V If (cont_y <= 479) Then video_on_V <= '1'; ELSE video_on_V <= '0'; End if; |
Esse componente também envia a posição que está sendo escrita no monitor.
1 2 3 4 5 6 7 |
Linha <= cont_y; Pixels <= "0" & cont_x(10 downto 1); -- Utilizo cont_x descartandando o último bit para dividir por 2 a frequencia -- De forma com que o clock seja semelhante ao do monitor. |
Memória
A memória foi implementada através de uma megafunção da Altera.
Na memória, está um arquivo .mif(Memory Initialization File) que possui o mapeamento da imagem a ser mostrada na tela. O arquivo .mif é indicado através do MegaWizard, como mostra a figura a Figura 6.
Figura 6 – Janela da Megafunção.
O número de bits para o endereço é igual a quantidade de bits do número de pixels que quer se mostrar mais o número de bits de Linhas a serem mostradas [P+L].
VGA
Parte das variáveis Pixels e Linhas,recebidas do componente Sincronismo, são enviadas pro componente Memória o tamanho do endereço:
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 |
Enderecamento: process(Linha,Pixels,clock) begin Address <= NOT Linha(6 downto 0) & Pixels(7 downto 0); -- Enviando endereços para a memória: if (Pixels <= 255) and (Linha <= 127) then -- utilizo pixels de 8 até 1 descartandando o último bit. -- isso divide a frequencia por 2 de forma com que o clock seja semelhante ao do monitor. RGB <= RGB_temp; else RGB <= "000000000000"; end if; end Process Enderecamento; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Cores:process (clock,RGB,Video_on) begin if (Video_on = '0') Then red <= "0000"; green <= "0000"; blue <= "0000"; else red <= RGB(11 downto 8); green <= RGB( 7 downto 4); blue <= RGB( 3 downto 0); end if; end Process Cores; |
Implementação do Projeto
Análise e Síntese
A Figura 7 apresenta o resultado da Análise e Síntese do projeto.
Figura 7 – Resultado da Análise e Síntese
Pinagem
Os pinos devem ser selecionados da seguinte forma:
Figura 8 – Pinagem do projeto
Clique na imagem para ampliá-la.
O utilizador deve estar atento à tensão de saída, a mesma deve ser ajustada, caso contrário, se permanecer em 2,5V o monitor parecerá meio apagado.
Simulação
O Testbench simula 3600000 pulsos de clock e mantém o Resetn em ‘1’.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
geraclock: process begin clock wait for 10ns; -- Agora, comeca a oscilar: for cont in 0 to 3600000 loop clock wait for 10 ns; end loop; wait; -- Parando este processo... end process; comportamento: process begin RESETn wait for 50 ns; RESETn wait; end process; |
As Figuras abaixo apresentam os tempos que foram simulados.
Clique nas imagens para ampliá-las.
Sincronismo Horizontal:
Tempo de descida HSYNC
Tempo de subida HSYNC
Tempo de subida VIDEO_ON_H
Sincronismo Vertical:
Tempo de descida VIDEO_ON_V
Tempo de descida VSYNC
Tempo de subida VSYNC
Tempo de subida VIDEO_ON_V
Arquivos do Projeto
Para o download do projeto completo, clique aqui.
O arquivo está no formato “zip”, e inclui, entre outros:
– O arquivo de projeto do Quartus , no formato “.qpf”
– A descrição no formato VHDL , no formato”.vhd”