Skip to content

FPGA Programming

Challenge :
Write your first FPGA program to make a doll sing. You might get some suggestions from Grody Goiterson, near Jack's elevator..
Difficulty Level :
drawing
Location :
Frost Tower Rooftop
Elf/Troll :
drawing Crunchy Squishter
drawing Crunchy Squister
Hey, could you help me get this device on the table working?
We've cobbled it together with primitive parts we've found on your home planet.
We need an FPGA though - and someone who knows how to program them.
If you haven't talked with Grody Goiterson by the Frostavator, you might get some FPGA tips there

Hints from Grody Goiterson :
1) First, did you know there are people who do this stuff for fun??
2) Prof. Petabyte guy is giving a talk about FPGAs.

Hints from Prof. Qwerty Petabyte :
If $rtoi(real_no * 10) - ($rtoi(real_no) * 10) > 4, add 1

Clicking on the terminal opens.
We see a boilerplate Verilog code with a module with 3 inputs (clk, rst and freq) and one output (wave_output).
That wave_output is assigned to wave_out which must be associated to a hardware to produce the sound.
talk by Prof. Qwerty explains this very well.

drawing

Approach

Per Prof. Qwerty, we need to create a square tone - meaning create a square wave output which takes our clock signal and uses a counter to divide the clock to match the desired frequency.

The desired frequency is what is being sent when we click on the buttons “Simulate 500Hz”, “Simulate 1KHz”, “Simulate 2KHz” to send 500Hz, 1KHz and 2KHz frequency to the Verilog program shown in the right-hand side. Clicking on “Simulate Random” sends random frequencies to the program.

There is also a note from Prof. Qwerty Petabyte about the frequency specified will always be in NNNN.DD format.
So, to be accurate (as much as we can) we need to keep the data type as “real” instead of “integer”. Its also stated square wave should have a half-duty cycle.
So, we create a new real variable for frequency to account for these and divide by 50.

real freq_real = freq / 50;

drawing drawing

The rounding (hint from Prof. Qwerty):

One tricky problem that we'll encounter is that Verilog (v1364-2005) doesn't have a built-in mechanism to round real numbers to integers, so you'll need to devise a means to do that correctly if you want your module to match frequencies accurately. Good luck and always remember: If $rtoi(real_no * 10) - ($rtoi(real_no) * 10) > 4, add 1

We first calculate the adjustment value and later check if Its greater than 4.

integer adjust = $rtoi(tone_real * 10) - ($rtoi(tone_real) * 10);

We initialize the a variable named “counter” with 32 bit value.

Every time our 125MHz goes high [always @(posedge clk)] and the counter reaches the 32 bit value, we toggle the wave and assign the counter variable the integer value of the tone.

Complete Program

// Note: For this lab, we will be working with QRP Corporation's CQC-11 FPGA.
// The CQC-11 operates with a 125MHz clock.
// Your design for a tone generator must support the following
// inputs/outputs:
// (NOTE: DO NOT CHANGE THE NAMES. OUR AUTOMATED GRADING TOOL
// REQUIRES THE USE OF THESE NAMES!)
// input clk - this will be connected to the 125MHz system clock
// input rst - this will be connected to the system board's reset bus
// input freq - a 32 bit integer indicating the required frequency
//              (0 - 9999.99Hz) formatted as follows:
//              32'hf1206 or 32'd987654 = 9876.54Hz
// output wave_out - a square wave output of the desired frequency
// you can create whatever other variables you need, but remember
// to initialize them to something!
`timescale 1ns/1ns
module tone_generator (
    input clk,
    input rst,
    input [31:0] freq,
    output wave_out
);
    // ---- DO NOT CHANGE THE CODE ABOVE THIS LINE ----
    // ---- IT IS NECESSARY FOR AUTOMATED ANALYSIS ----
    // TODO: Add your code below.
    // Remove the following line and add your own implementation.
    // Note: It's silly, but it compiles...
    // Clock frequency is 125 MHz
           integer clock = 125000000;
    // Counter for toggeling of clock
    integer counter = 0;
    // real data type to account for decimal
    // divide the frequency by 50 for the 1/2 duty cycle
    real freq_real = freq / 50;
    // Get the tone in real (to account for decimal) 
    real tone_real = clock / freq_real;
    // Convert real to int
    integer tone_int = $rtoi(tone_real);
    // Rounding as noted by Prof. Q. Petabyte
    integer adjust = $rtoi(tone_real * 10) - ($rtoi(tone_real) * 10);

    // Create a reg “wave_out_reg” and assign to the output wave_out
    // So when value of “wave_out_reg” changes It will immediately change wave_out
    reg wave_out_reg = 0;
    assign wave_out = wave_out_reg;

always @(posedge clk) begin
        if (rst) begin
        //Initialize the counter to the 32-bit integer 
            counter <= 32'h00;
       //Initialize the wave_out_reg to a bit value of zero
            wave_out_reg <= 1'b0;
        end

        else begin
            if (counter == 32'h00) begin
                wave_out_reg <= ~wave_out_reg;

                // We calculated earlier the value of adjust and put the condition per Prof. Q. Petabyte
                if (adjust > 4) begin
                    counter <= tone_int;
                end
                else
                    counter <= tone_int - 1;
            end
            else
                counter <= counter - 1;
            end
    end
endmodule

Conducted Tests and Programming the device

Simulate 500Hz frequency
drawing
Simulate 1KHz frequency
drawing
Simulate 2KHz frequency
drawing
Simulate random frequency [I had to make multiple attempts to get best-fit value]]
drawing

Once all the tests result in models which match the best-fit value, we click on the "Program Device" on the FPGA.

Program Device
drawing drawing

We have now completed the FPGA programming objective and have programmed the FPGA chip. yay!!!! Awesome work!! drawing

We can also view the item in the badge.
drawing