Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
15772 Discussions

Creating square waves of varying frequencies

Honored Contributor II

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, 

0 Kudos
2 Replies
Honored Contributor II

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. 



Honored Contributor II

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