Music box - part 1
Simple beep 
FPGAs can easily implement binary counters. Let's start with a 16-bits counter.
Starting from the 25MHz clock, we can simply "divide the clock" using the counter.
A 16 bits counter counts from 0 to 65535 (65536 different values).
The highest bit of the counter toggles at a frequency of 25000000/65536=381Hz.
The Verilog HDL code looks like this:
module music(clk, speaker);
input clk;
output speaker;
// Binary counter, 16-bits wide
reg [15:0] counter;
always @(posedge clk) counter <= counter+1;
// Use the highest bit of the counter (MSB) to drive the speaker
assign speaker = counter[15];
endmodule
|
The LSB (counter[0]) would toggle with a frequency of 12.5MHz. "counter[1]" with 6.125MHz.
And so on.
We use the MSB (bit 15) of the counter to drive the output.
Here it goes! a nice 381Hz square signal comes out of the "speaker" output.
"A" note (440Hz)
Ok, better than a random frequency, why not try to get a 440Hz signal.
That's the frequency of the "A" note.
Instead of dividing 25MHz by 65536, we need to divide by 56818.
Here we go.
module music(clk, speaker);
input clk;
output speaker;
reg [15:0] counter;
always @(posedge clk) if(counter==56817) counter <= 0; else counter <= counter+1;
assign speaker = counter[15];
endmodule
|
There is a problem though.
The frequency is 440Hz, as expected, but the output duty cycle is not 50% anymore.
The low level goes from counter=0 to counter=32767 (when bit 15 of counter is low) and then high level from 32768 to 56817.
That gives us "speaker" being high only 42% of the time.
The easiest way to get a 50% duty cycle is to add a stage that divides the output by 2.
So first we divide by 28409 (instead of 56818) and then by 2.
module music(clk, speaker);
input clk;
output speaker;
reg [14:0] counter;
always @(posedge clk) if(counter==28408) counter <= 0; else counter <= counter+1;
reg speaker;
always @(posedge clk) if(counter==28408) speaker <= ~speaker;
endmodule
|
Adding a parameter
Here's essentially the same code.
A new parameter named "clkdivider" was added, and the counter was changed into a "count-down" counter - just a matter of preference.
module music(clk, speaker);
input clk;
output speaker;
parameter clkdivider = 25000000/440/2;
reg [14:0] counter;
always @(posedge clk) if(counter==0) counter <= clkdivider-1; else counter <= counter-1;
reg speaker;
always @(posedge clk) if(counter==0) speaker <= ~speaker;
endmodule
|
>>> NEXT: Music box - part 2 >>>
This page was last updated on November 11 2006.