Gerando um relógio no FPGA em primitivas

Lendo folhas de dados sobre FPGAs, você pode encontrar sinais sobre suas frequências operacionais ... Mas



não, a história começa em 2015, quando eu me familiarizei com FPGAs. Nos meus primeiros trabalhos simples, formei o relógio de que precisava no balcão e alimentei toda a lógica (naturalmente, desde que eu precisasse do relógio mais lentamente do que o alimentado no FPGA, por exemplo, UART e SPI). Naturalmente, eles me perseguiram por isso, mas eu tinha uma desculpa simples “mas funciona!”, E tudo realmente funcionou. Desde então, o pensamento surgiu em minha mente: "De onde posso obter o sinal de temporização?"



Não há muitas opções para as fontes se fragmentarem. Pegue em um certo ClockWizard baseado em PLL ou MMCM ou forme-o em um balcão, ou imediatamente a partir da perna, por assim dizer, de ponta única. E se pegarmos o sinal do relógio gerado pelo primitivo FPGA?



Como parte deste artigo, decidi considerar três opções: um multiplexador (MUXF7), uma tabela de verdade (LUT1) e um curto-circuito entre as pernas do FPGA.



No caso de um multiplexador, a saída é alimentada ao sinal de controle e os sinais de entrada são puxados para 0 e 1.



imagem


No caso de LUT, fazemos um curto-circuito na saída e configuramos a tabela verdade inversa. Ao fornecer "1", digite zero e, ao fornecer "0", digite um.



imagem


No caso do GPIO, tudo é simples, o sinal de saída recebe o inverso do sinal de entrada:

atribuir s2 = ~ s1;


O objetivo do experimento: gerar uma frequência de três maneiras e medi-la.

Mediremos a frequência às custas dos contadores. Haverá 4 contadores: três para cada opção e um contador básico, em relação aos quais tudo será contado. E assistiremos a esses contadores através do ChipScope.



E aqui está o código inteiro do módulo:
module gen_clk(
    input clk_base,
    input s1, //gpio
    output s2 //gpio
    );

//  - 
assign s2 = ~s1;
wire clk_gpio = s1;
reg [31:0] cnt_gpio = 0;
 (* MARK_DEBUG="true" *) reg [31:0] cnt_gpio_buf = 0;
always@(posedge clk_gpio)
begin 
    if(cnt_gpio[2:0]==3'd0) cnt_gpio_buf<=cnt_gpio; 
    cnt_gpio <= cnt_gpio + 1'b1;
end

//  
wire clk_mux;
MUXF7 MUXF7_inst
(
    .O(clk_mux),
    .I0(1'b1),
    .I1(1'b0),
    .S(clk_mux)
);
reg [31:0] cnt_mux = 0;
 (* MARK_DEBUG="true" *) reg [31:0] cnt_mux_buf = 0;
always@(posedge clk_mux)
begin 
    if(cnt_mux[2:0]==3'd0) cnt_mux_buf<=cnt_mux; 
    cnt_mux <= cnt_mux + 1'b1;
end
//   
wire clk_lut;
LUT1#(
    .INIT(2'b01)
)
LUT1_inst(
    .O(clk_lut),
    .I0(clk_lut)
);
reg [31:0] cnt_lut = 0;
 (* MARK_DEBUG="true" *) reg [31:0] cnt_lut_buf = 0;
always@(posedge clk_lut)
begin 
    if(cnt_lut[2:0]==3'd0) cnt_lut_buf<=cnt_lut; 
    cnt_lut <= cnt_lut + 1'b1;
end
//         
 (* MARK_DEBUG="true" *) reg [31:0] cnt_base = 'd0;        
always@(posedge clk_base)
begin
    cnt_base <= cnt_base + 1'b1;
end    
   
endmodule




Aqui está um esquema do projeto. As primitivas são circuladas e as setas indicam o sinal que será inserido no ChipScope para análise de frequência:



imagem




Parte prática Tenho



três quadros à minha disposição:



  1. Kit de avaliação KC705



    imagem


  2. Kit de Avaliação ML507



    imagem


  3. Placa Spartan-6 XC6SLX16 chinesa



    imagem


    Olhando para o futuro
    Olhando para o futuro, direi que o último quadro não teve um resultado normal.





E agora os resultados reais



Kintex-7:



Desde que o projeto começou a ser desenvolvido, o projeto não foi escrito inteiramente de uma só vez, mas em etapas. Primeiro, conectei um LUT, adicionei sinais à depuração e comecei a assistir.



O contador da base tem um clock de 200 MHz, portanto, não é difícil calcular a frequência dos relógios gerados no saque, quantas vezes o contador delta do contador de loot é o delta do contador básico ao mesmo tempo, tantas vezes a sua frequência. Nesse caso: a frequência gerada pelo saque é de 381,55 MHz.



imagem


Agora adicionaremos um multiplexador ao projeto e, por analogia com um saque, calcularemos a frequência para ele e para o saque (afinal, algo deve mudar).



imagem


A primeira coisa que chama a atenção é o quanto o contador sacode. Isso afeta a enorme frequência do multiplexador, mas em geral fica claro que o contador está aumentando, o que significa que também pode ser obtido e contado. Eventualmente:



  • Frequência do multiplexador: 5953,89 MHz
  • Frequência de pilhagem (alterada): 379,98 MHz


Bem, no final, vamos adicionar um loop fechado de um par GPIO ao projeto. A placa KC705 possui conectores SMA J13 e J14. Aqui eu os fechei com um condutor de cerca de 10 cm de comprimento. Como resultado:



  • Frequência GPIO: 90,59 MHz
  • Frequência do multiplexador: 12994,13 MHz
  • Frequência de pilhagem: 380,18 MHz


Vamos substituir, por uma questão de experimento, o condutor por um mais longo, eu tenho um fio duas vezes mais longo. Como resultado, a frequência caiu para 85,29 MHz.



Nesta fase do experimento, pode-se notar que a frequência de operação de primitivas em FPGAs não é a mesma. No caso em que havia apenas um saque, o sintetizador escolheu o saque mais rápido e construiu um circuito em torno dele; quando o multiplexador foi adicionado, o sintetizador tentou encontrar a super posição em que o saque e o multiplexador trabalham o mais rápido possível, e esses são outros elementos e frequências que são mais lentos. Quando pinos externos foram adicionados, todo o projeto em um cristal foi basicamente realocado para essas pernas e o projeto começou a ser sintetizado em elementos próximos, por alguma razão, naquele local, as frequências do espólio e do multiplexador aumentaram visivelmente, mas não se esqueça disso, no contexto de tudo isso, para o projeto um ChipScope com profundidade de 1024 e um barramento de dados de 64 a 128 estão conectados (ele muda de projeto para projeto). Agora vamos para o próximo quadro.



Virtex-5:



Não segui o caminho anterior, adicionei imediatamente todas as três opções para gerar uma capa e verifiquei no ChipScope o que aconteceu.



imagem


A figura mostra dois rótulos X e O. Assim como seus valores nas colunas, o formato dos números é decimal não assinado. Vale a pena notar que o contador base agora conta com 100 MHz. E assim o resultado:



  • Frequência GPIO: 96,34 MHz
  • Frequência do multiplexador: 614,41 MHz
  • Frequência de pilhagem: 5761,1 MHz


Pode-se ver que nesta placa o saque acabou sendo mais rápido que o multiplexador e a frequência dos pinos acabou sendo mais alta do que na primeira placa, talvez seja porque eu conectei os dois pinos não com um condutor de 10 cm, mas com um jumper, como resultado, a linha de comunicação ficou mais curta e a frequência foi maior.



E agora a última opção com uma placa chinesa.



Spartan-6:



Existem dois contadores básicos no ChipScope, na verdade, é o mesmo contador que simplesmente não queria reconfigurar o ChipScope. Neste projeto, o contador básico tem clock de 50 MHz.



imagem


No caso deste fórum, tudo ficou muito mais complicado. Primeiramente, o projeto não queria ser sintetizado de forma alguma, da forma que foi sintetizada nas versões anteriores. Em segundo lugar, no final, tive que jogar fora o LUT, tentei substituí-lo por um de cinco, mas também não funcionou. Em geral, aqui estão os resultados:



  • Frequência GPIO: 51,77 MHz
  • Frequência do multiplexador: 3 490 504 MHz
  • Frequência de pilhagem: falha ao coletar


Os resultados no desempenho desta placa não foram nada felizes, e não apenas porque o saque não pôde ser usado como um pedaço, mas também por causa da frequência incrivelmente grande do multiplexador. Quanto ao fragmento gerado nas pernas, foi utilizado um condutor de cerca de 25 a 30 cm, no final fechado com um fio, provavelmente capacitâncias e indutâncias parasitárias foram formadas lá, o que teve seu efeito na geração do fragmento.



Conclusão



Em geral, conseguimos gerar sinais de relógio em várias primitivas e também conseguimos ver (usando o Kintex-7 como exemplo) que as primitivas têm latência diferente, dependendo de sua localização. Em meu nome, quero acrescentar que não considero o experimento realizado completamente correto, por exemplo, a largura de bit dos contadores não foi calculada, a transferência de sinal de diferentes domínios de relógio não foi levada em consideração (embora eu tenha feito o sinal no buffer ficar por vários relógios), o próprio ChipScope deve ser removido e outra maneira deve ser encontrada analise a frequência gerada.



Problemas encontrados:
Vivado ISE , . :



  • set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets -of_objects [get_cells gen_clk_inst/LUT1_inst]]
  • NET «s1» CLOCK_DEDICATED_ROUTE = FALSE;





All Articles