Есть ли способ использовать ввод для определения периода времени?

Эта программа должна иметь возможность выводить синусоидальную волну на испытательный стенд, где частота выходного сигнала должна задаваться восьмибитным входом. Я понимаю, что мне нужно изменить период тактовой частоты, который соответственно изменит частоту сигнала. Код представлен ниже:

module functionGenerator(Clk,data_out, freq);
//declare input and output
    input [7:0] freq;
    input Clk;
    output [9:0] data_out;
//declare the sine ROM - 30 registers each 8 bit wide.  
    reg [9:0] sine [0:99];
//Internal signals  
    integer i;  
    reg [9:0] data_out;
//Initialize the sine rom with samples. 
    initial begin
        i = 0;
        sine[0] = 0;        sine[1] = 10;        sine[2] = 20;        sine[3] = 29;        sine[4] = 39;   
        sine[5] = 48;       sine[6] = 58;        sine[7] = 67;        sine[8] = 75;        sine[9] = 84;
        sine[10] = 92;      sine[11] = 100;      sine[12] = 107;      sine[13] = 114;      sine[14] = 120;
        sine[15] = 126;     sine[16] = 132;      sine[17] = 137;      sine[18] = 141;      sine[19] = 145;   
        sine[20] = 149;     sine[21] = 151;      sine[22] = 153;      sine[23] = 155;      sine[24] = 156;
        sine[25] = 156;     sine[26] = 156;      sine[27] = 155;      sine[28] = 153;      sine[29] = 151;
        sine[30] = 149;     sine[31] = 145;      sine[32] = 141;      sine[33] = 137;      sine[34] = 132;   
        sine[35] = 126;     sine[36] = 120;      sine[37] = 114;      sine[38] = 107;      sine[39] = 100;
        sine[40] = 92;      sine[41] = 84;       sine[42] = 75;       sine[43] = 67;       sine[44] = 58;
        sine[45] = 48;      sine[46] = 39;       sine[47] = 29;       sine[48] = 20;       sine[49] = 10;   
        sine[50] = 0;       sine[51] = -10;      sine[52] = -20;      sine[53] = -29;      sine[54] = -39;
        sine[55] = -48;     sine[56] = -58;      sine[57] = -67;      sine[58] = -75;      sine[59] = -84;
        sine[60] = -92;     sine[61] = -100;     sine[62] = -107;     sine[63] = -114;     sine[64] = -120;   
        sine[65] = -126;    sine[66] = -132;     sine[67] = -137;     sine[68] = -141;     sine[69] = -145;
        sine[70] = -149;    sine[71] = -151;     sine[72] = -153;     sine[73] = -155;     sine[74] = -156;
        sine[75] = -156;    sine[76] = -156;     sine[77] = -155;     sine[78] = -153;     sine[79] = -151;   
        sine[80] = -149;    sine[81] = -145;     sine[82] = -141;     sine[83] = -137;     sine[84] = -132;
        sine[85] = -126;    sine[86] = -120;     sine[87] = -114;     sine[88] = -107;     sine[89] = -100;
        sine[90] = -92;     sine[91] = -84;      sine[92] = -75;      sine[93] = -67;      sine[94] = -58;
        sine[95] = -48;     sine[96] = -39;      sine[97] = -29;      sine[98] = -20;      sine[99] = -10;
    end

    //At every positive edge of the clock, output a sine wave sample.
    always@ (posedge(Clk))
    begin
        data_out = sine[i];
        i = i+ 1;
        if(i == 99)
            i = 0;
    end

endmodule

Испытательный стенд

module functionGeneratror_tb();

    // Inputs
    reg Clk;
    reg freq;

    // Outputs
    wire [9:0] data_out;

    // Instantiate the Unit Under Test (UUT)
    functionGenerator uut (
        .Clk(Clk), 
        .data_out(data_out),
        .freq(freq)
    );

    //Generate a clock with 10 ns clock period.
    initial Clk = 0;
    always #5 Clk = ~Clk; // CAN I PASS IN AN INPUT HERE INSTEAD OF 5?
    initial
    #10000 $finish;

endmodule

person RytisBe    schedule 26.04.2019    source источник
comment
Используйте счетчик, чтобы разделить часы, чтобы контролировать частоту. Самая высокая частота - это деление тактовой частоты на 1, самая низкая частота - деление тактовой частоты на 255.   -  person David Cullen    schedule 27.04.2019
comment
Между прочим: в HDL вы обычно храните только 1/4 полной таблицы синусов. Остальные квадранты получаются вычитанием и использованием отрицательного оператора.   -  person Oldfart    schedule 27.04.2019


Ответы (2)


always #5 Clk = ~Clk;

Этот оператор является частью вашей тестовой среды, а не UUT. Вы не должны его менять; ожидается, что тактовая частота останется постоянной.

Ваш functionGenerator модуль в настоящее время не использует вход freq. Вам нужно будет придумать способ контролировать, как быстро синтезатор проходит через массив sine на основе значения freq. Это может включать в себя выполнение менее одного шага за clk период или выполнение нескольких шагов за период, в зависимости от ваших требований.

person Community    schedule 26.04.2019

Это типичный случай, когда генератор накопителя фазы используется для генерации адреса ПЗУ для вывода нового отсчета.

Примерно так: фазовый аккумулятор здесь имеет ширину 14 бит, и мы используем 6 старших битов, чтобы получить синусоидальную волну из 64 выборок. Выходная частота такой синусоидальной волны составляет CLK * freq / 16384.

Фактически, в ПЗУ всего 16 ячеек, так как ему нужно хранить только четверть синусоидальной волны. Биты с 3 по 0 из вычисленного адреса из фазового аккумулятора используются для адресации ПЗУ, а биты с 5 по 4 используются для определения того, в каком квадранте мы находимся, поэтому может потребоваться инвертировать фактический адрес и / или фактический выход. может потребоваться отрицание.

module FunctionGenerator (
  input wire clk,
  input wire [7:0] freq, // frequency of output signal is: clk * freq / 16384
  output reg signed [9:0] out
  );

  reg signed [9:0] quartersin[0:15];
  // Generate initial values with this little C program:
  //   #include <stdio.h>
  //   #include <math.h>
  // 
  //   #define PI 3.141592654
  // 
  //   int main()
  //   {
  //     int i;
  //     
  //     for (i=0;i<16;i++)
  //     {
  //         printf ("    quartersin[%2d] = %d;\n", i, (int)(511*sin(i*2*PI/64.0)));
  //     }
  //
  //     return 0;
  //   }
  initial begin
    quartersin[ 0] = 0;
    quartersin[ 1] = 50;
    quartersin[ 2] = 99;
    quartersin[ 3] = 148;
    quartersin[ 4] = 195;
    quartersin[ 5] = 240;
    quartersin[ 6] = 283;
    quartersin[ 7] = 324;
    quartersin[ 8] = 361;
    quartersin[ 9] = 395;
    quartersin[10] = 424;
    quartersin[11] = 450;
    quartersin[12] = 472;
    quartersin[13] = 488;
    quartersin[14] = 501;
    quartersin[15] = 508;
  end

  reg [13:0] phaseacum = 14'h0000;
  reg [3:0] indx;
  always @(posedge clk) begin
    phaseacum <= phaseacum + {6'b000000, freq};
    if (phaseacum[13] == 1'b0)  // if in quadrants 0 or 1, out as is
      out <= quartersin[indx];
    else
      out <= -quartersin[indx];  // if in quadrants 2 or 3, negate out
  end

  always @* begin
    if (phaseacum[12] == 1'b0)   // which quadrant am I ?
      indx = phaseacum[11:8];  // if in quadrant 0 or 2
    else
      indx = ~phaseacum[11:8]; // else, in quadrant 1 or 3
    endcase
  end
endmodule

Можно использовать минимальный тестовый стенд, чтобы позволить этому генератору функций работать около тысячи тактов, а затем передать вывод в GTKWave и отобразить его как аналоговый вывод:

`timescale 1ns / 1ns

module tb;
  reg clk;
  reg [7:0] freq;
  wire [9:0] out;

  FunctionGenerator uut (
    .clk(clk),
    .freq(freq),
    .out(out)
  );

  initial begin
    $dumpfile("dump.vcd");
    $dumpvars(1,uut);

    clk = 1'b0;
    freq = 8'd16;  // aprox. 1 kHz sine wave for a 1 MHz clk

    repeat (2000) begin
      @(posedge clk);
    end
    $finish;
  end

  always begin
    clk = #500 ~clk;  // a 1 MHz clock
  end
endmodule

Это результат, смоделированный с помощью iverilog / GTKWave:

Имитация вывода GTKWave

person mcleod_ideafix    schedule 27.04.2019