Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
8 years ago

Creating square waves of varying frequencies

Hi all,

I'm currently trying to produce sound via an Audio Controller by creating square waves that change in frequency depending on which switch on the FPGA is flipped. I'm able to get sound, but for some reason that I can not figure out all except for one note (A4 at 440Hz) are outputting the wrong tone. I've done some pretty extensive research and have come up dry as to what the problem is :( I'm dividing the Audio CODEC Chip Clock (clocked at 48kHz) for various Duty Cycles to produce the correct frequency. Here's a snippet of my code:


// Positive and negative amplitude parameters for square wave
parameter pos_amp = 32'h7FFFFFFF;
parameter neg_amp = 32'h80000000;
// Determines channel_audio_out via dac_out
wire signed  channel_audio_out = dac_out ? pos_amp : neg_amp;
 
// Seperate 8-bit counter for each note
reg  ac_counter_C4;
reg  ac_counter_D4;
reg  ac_counter_E4;
reg  ac_counter_F4;
reg  ac_counter_G4;
reg  ac_counter_A4;
reg  ac_counter_B4;
reg clear_audio_out_memory;     // To clear audio_out buffer when no SW is flipped
reg write_audio_out;        // To signal when to write to audio_out buffer
reg dac_out;         // Determines pos_amp or neg_amp for channel_audio_out
// Determines dac_out via ac_counter's (AUD_XCK dividers)
always@(posedge AUD_XCK) // 48kHz
beginclear_audio_out_memory <= 1'b0;
if (SW == 1'b1) // C4 --- f = 261.626 Hz --- Duty Cycle = 184
begin
ac_counter_C4 <= ac_counter_C4 + 1'b1;
if (ac_counter_C4 >= 8'd183)
ac_counter_C4 <= 8'd0;
write_audio_out <= 1'b1;
if (ac_counter_C4 < 8'd92)
dac_out <= 1'b1;
else
dac_out <= 1'b0;
end
else if (SW == 1'b1) // D4 --- f = 293.665 Hz --- Duty Cycle = 164
begin
ac_counter_D4 <= ac_counter_D4 + 1'b1;
if (ac_counter_D4 >= 8'd163)
ac_counter_D4 <= 8'd0;
write_audio_out <= 1'b1;
if (ac_counter_D4 < 8'd82)
dac_out <= 1'b1;
else
dac_out <= 1'b0;
end
...etc for all notes...
else // NO SWITCH ON --- DEFAULT STATE
begin
     
ac_counter_C4 <= 1'd0;
ac_counter_D4 <= 1'd0;
ac_counter_E4 <= 1'd0;
ac_counter_F4 <= 1'd0;
ac_counter_G4 <= 1'd0;
ac_counter_A4 <= 1'd0;
ac_counter_B4 <= 1'd0;
     write_audio_out <= 1'b0;
clear_audio_out_memory <= 1'b1;
dac_out <= 1'b0;
end
end

I'd also like to add that the fact that I have no reset is not a problem (that I'm aware), I have it in a different part of my code.

If anyone could help me figure out where I went wrong it would be much appreciated,

Thanks!

2 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I suspect you have a subtle typo somewhere. However, it's not evident in the code you've posted.

    A more general observation - a counter per note is fine. However, you're controlling and selecting each counter based on your switched. May I suggest running the note counters continuously, each with their own 'dac_out' signal, and selecting which one you wish to pipe to the DAC. This will simplify your code greatly. Simpler code leaves less room for error.

    Alternatively, a single counter, and single 'dac_out' signal, but with selectable wrap points based on note selection.

    Either way, I'm sure the simpler code that would result, from either method, will help.

    Cheers,

    Alex
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Have you simulated your design to see what's actually going on?

    Dan