FPGA Debug Board - Frankenstein. Sounds and music
Today we have the most New Year's series about FPGAs and Frankie's debug board. Previous Series 1 , 2 .
We already transmitted tones over the radio using our Frankenstein board. Now try to play sounds and music.
To do this, connect a regular speaker to the FPGA. A generator at 25.175 MHz is connected to Frankie. If we divide this frequency to the range of audible frequencies and apply to the output of the FPGA, then we can hear the sound. Me frequency we can get different sounds.
Testing the sound quality will be the best listener in the house - Masha. The frequency range of 60 KHz - this is not a joke to you! )))
Wiring diagram
To play the sound, I use the speaker from the connoisseur constructor (I didn’t find another on the move). I connect the speaker to the FPGA pin through a resistor with a resistance of 470 Ohms.

Simple sound
FPGAs easily fit binary counters. Therefore, even Frankie will cope with such a task. For example, a 16-bit counter will count from 0 to 65535. Having our 25.175 MHz and 16-bit counter, we can get sound with a frequency of 25175000/65536 = 384.14 Hz
module epm7064_test(clk, audio);
input wire clk;
output wire audio;
// двоичный счетчик на 16 бит
reg [15:0] counter;
always @(posedge clk) counter <= counter+1;
// выведем старший бит счетчика на динамик
assign audio = counter[15];
endmoduleNote "LA" of the first octave (440 Hz)
We got a random frequency in the audio range. Now you can try to get a frequency equal to 440 Hz. This is the frequency of the “A” note of the first octave.
For this, instead of dividing the clock frequency by 65536, we must divide the frequency value of the clock generator by 57216 (27175000 Hz / 440 Hz).
module epm7064_test(clk, audio);
input wire clk;
output wire audio;
// двоичный счетчик на 16 бит
reg [15:0] counter; initial counter <= 16'd0;
always @(posedge clk) begin
if(counter==57216) begin
counter <= 0;
end else begin
counter <= counter + 1'b1;
end
end
assign audio = counter[15];
endmoduleBut there is a problem in this implementation. Although the frequency is 440 Hz, the signal duty cycle is not equal to 50%. A low level is displayed at counter values from 0 to 32767, and a high level is from 32767 to 56817. It turns out that the speaker is in the unit only 42% of the time. The easiest way to get a duty cycle of 50% is to add another division by two. That is, first at 28608, and then another 2.
module epm7064_test(clk, audio);
input wire clk;
output audio;
// двоичный счетчик на 15 бит
reg [14:0] counter; initial counter <= 15'd0;
always @(posedge clk) begin
if(counter==28608) begin
counter <= 0;
end else begin
counter <= counter + 1'b1;
end
end
reg audio;
always @(posedge clk) if(counter==28608) audio <= ~audio;
endmoduleOf course, this is hardly distinguishable by ear.
To make the code more flexible, you can add the clkdivider parameter. Changing the direction of the count in the counter to the opposite is just a matter of preference. There will be no difference in the resources used by FPGAs.
module epm7064_test(clk, audio);
input wire clk;
output audio;
parameter clkdivider = 25175000/440/2;
reg [14:0] counter; initial counter <= 15'd0;
always @(posedge clk) begin
if(counter==0) begin
counter <= clkdivider - 1'b1;
end else begin
counter <= counter - 1'b1;
end
end
reg audio;
always @(posedge clk) if(counter==0) audio <= ~audio;
endmoduleAmbulance siren
Now let's try to alternate two different tones. To do this, use a
counter (let's call it tone) for 24 bits, to obtain a frequency of the order of 1.5 Hz.
We will use this signal to switch between two frequencies.
module epm7064_test(clk, audio);
input wire clk;
output audio;
parameter clkdivider = 25175000/440/2;
reg [14:0] counter; initial counter <= 15'd0;
reg [23:0] tone; initial tone <= 24'd0;
always @(posedge clk) tone <= tone+1;
always @(posedge clk) begin
if(counter==0) begin
counter <= (tone[23] ? clkdivider-1 : clkdivider/2-1);
end else begin
counter <= counter - 1'b1;
end
end
reg audio;
always @(posedge clk) if(counter==0) audio <= ~audio;
endmoduleNow let's try to make a police siren. First, change the tone counter so that it has only 23 bits to double the frequency (the most significant bit will change at a frequency of about 3 Hz).
Now you need to come up with a trick to get a “saw”. Take bits 15 through 21 from the tone counter. It will look like this: tone[21:15]. These 7 bits will give us a value from 0 to 127, which will increase at a certain speed. As soon as the value reaches 127, it will reset to 0 and begin to rise again. In order to get a decreasing value, we can invert these bits. It will look like this: (~tone[21:15]). This will get values that go down from 127 to 0, and then everything repeats.
In order to get a saw, which gradually grows, and then gradually decreases, we
take a bit tone[22].
wire [6:0] ramp = (tone[22] ? tone[21:15] : ~tone[21:15]);
// это все равно, что
// "if tone[22]=1 then ramp=tone[21:15] else ramp=~tone[21:15]"But such a saw is not yet ready for use in our project.
The value of the saw varies from 7'b0000000to 7'b1111111. In order to get the values from which we could already get the sound, we will add 2 more bits '01'on the left and six bits '000000'on the right to the word values of the saw .
wire [14:0] clkdivider = {2'b01, ramp, 6'b000000};Thus, we get a constantly changing clkdivider value in the range from 15'b010000000000000to 15'b011111111000000, or in the hexadecimal system from 15'h2000to 15'h3FC0, or in decimal 8192 to 16320. At a generator frequency of 25.175 MHz we get a siren sound from 771 Hz to 1537 Hz.
module epm7064_test(clk, audio);
input wire clk;
output audio;
reg [14:0] counter; initial counter <= 15'd0;
reg [23:0] tone; initial tone <= 24'd0;
always @(posedge clk) tone <= tone+1;
wire [6:0] ramp = (tone[22] ? tone[21:15] : ~tone[21:15]);
wire [14:0] clkdivider = {2'b01, ramp, 6'b000000};
always @(posedge clk) begin
if(counter==0) begin
counter <= clkdivider;
end else begin
counter <= counter - 1'b1;
end
end
reg audio;
always @(posedge clk) if(counter==0) audio <= ~audio;
endmoduleAnd we got a quick siren. But a real siren changes its speed from fast to slow. We can take bits tone[21:15]for a quick saw, and bits tone[24:18]for a saw with a lower frequency.
wire [6:0] fastsweep = (tone[22] ? tone[21:15] : ~tone[21:15]);
wire [6:0] slowsweep = (tone[25] ? tone[24:18] : ~tone[24:18]);
wire [14:0] clkdivider = {2'b01, (tone[27] ? slowsweep : fastsweep), 6'b000000};To do this, you need to increase the capacity of the tone counter.
module epm7064_test(clk, audio);
input wire clk;
output audio;
reg [14:0] counter; initial counter <= 15'd0;
reg [27:0] tone; initial tone <= 28'd0;
always @(posedge clk) tone <= tone+1;
wire [6:0] ramp = (tone[22] ? tone[21:15] : ~tone[21:15]);
wire [6:0] fastsweep = (tone[22] ? tone[21:15] : ~tone[21:15]);
wire [6:0] slowsweep = (tone[25] ? tone[24:18] : ~tone[24:18]);
wire [14:0] clkdivider = {2'b01, (tone[27] ? slowsweep : fastsweep), 6'b000000};
always @(posedge clk) begin
if(counter==0) begin
counter <= clkdivider;
end else begin
counter <= counter - 1'b1;
end
end
reg audio;
always @(posedge clk) if(counter==0) audio <= ~audio;
endmodulePlay the melody
And now, in honor of the upcoming new year, let's try to play a song about the Christmas tree. Let's look for notes and videos to understand how this song is played.
In order to play a sequence of notes, we need to create a sequencer that will issue the number of the desired note at the right time. We convert this note value to a constant for the frequency divider to get the corresponding note.
Judging by the video, we need only one octave + 1. In principle, we don’t need all the notes.
And you need only 7 notes that are used in the song. Therefore, 3 bits are enough to store the note number. It would be more correct, of course, to say not the number of the note, but the number of the tone or frequency in the melody.
So, we have notes in the melody: before, re, mi, fa, salt, la and until the next octave. We will number them accordingly. The sequence is as follows:
соль 5
ми ми 3 3
соль 5
ми ми 3 3
соль фа ми ре до 5 4 3 2 1
ля до(+1) ля
соль ми ми
соль фа ми ре доI will draw a time chart.
Using a secret tabular processor, we calculate the frequencies of notes and the values of the dividers, slightly rounding them.

Now that all the calculations are completed, we describe the logic.
Frequency divider by note number:
wire [15:0] clkdivider =
(note_num == 0) ? 16'd0 :
(note_num == 1) ? 16'b1011101111110000 :
(note_num == 2) ? 16'b1010011101110000 :
(note_num == 3) ? 16'b1001010100110000 :
(note_num == 4) ? 16'b1000110011010000 :
(note_num == 5) ? 16'b0111110101110000 :
(note_num == 6) ? 16'b0110111111000000 :
(note_num == 7) ? 16'b0101111000000000 : 16'd0;Judging by the picture, the sequencer we get in 64 steps. To do this, increase the capacity of the tone counter.
reg [27:0] tone; initial tone <= 28'd0;
always @(posedge clk) tone <= tone + 1'b1;
wire [5:0] step_num = tone[26:(26-5)]; // 6 бит это от 0 до 63Convert from sequencer step number number to note number:
wire [2:0] note_num =
(step_num == 0) ? 5 : // 1
(step_num == 1) ? 5 : // 2
(step_num == 2) ? 0 : // 3
(step_num == 3) ? 0 : // 4
(step_num == 4) ? 3 : // 5
(step_num == 5) ? 0 : // 6
(step_num == 6) ? 3 : // 7
(step_num == 7) ? 0 : // 8
(step_num == 8) ? 5 : // 9
(step_num == 9) ? 5 : // 10
(step_num ==10) ? 0 : // 11
(step_num ==11) ? 0 : // 12
(step_num ==12) ? 3 : // 13
(step_num ==13) ? 0 : // 14
(step_num ==14) ? 3 : // 15
(step_num ==15) ? 0 : // 16
... и т. д.module epm7064_test(clk, audio);
input wire clk;
output audio;
reg [15:0] counter; initial counter <= 16'd0;
reg [27:0] tone; initial tone <= 28'd0;
always @(posedge clk) tone <= tone + 1'b1;
wire [5:0] step_num = tone[26:(26-5)];
wire [2:0] note_num =
(step_num == 0) ? 5 : // 1
(step_num == 1) ? 5 : // 2
(step_num == 2) ? 0 : // 3
(step_num == 3) ? 0 : // 4
(step_num == 4) ? 3 : // 5
(step_num == 5) ? 0 : // 6
(step_num == 6) ? 3 : // 7
(step_num == 7) ? 0 : // 8
(step_num == 8) ? 5 : // 9
(step_num == 9) ? 5 : // 10
(step_num ==10) ? 0 : // 11
(step_num ==11) ? 0 : // 12
(step_num ==12) ? 3 : // 13
(step_num ==13) ? 0 : // 14
(step_num ==14) ? 3 : // 15
(step_num ==15) ? 0 : // 16
(step_num ==16) ? 5 : // 17
(step_num ==17) ? 0 : // 18
(step_num ==18) ? 4 : // 19
(step_num ==19) ? 0 : // 20
(step_num ==20) ? 3 : // 21
(step_num ==21) ? 0 : // 22
(step_num ==22) ? 2 : // 23
(step_num ==23) ? 0 : // 24
(step_num ==24) ? 1 : // 25
(step_num ==25) ? 1 : // 26
(step_num ==26) ? 1 : // 27
(step_num ==27) ? 1 : // 28
(step_num ==28) ? 0 : // 29
(step_num ==29) ? 0 : // 30
(step_num ==30) ? 0 : // 31
(step_num ==31) ? 0 : // 32
(step_num ==32) ? 6 : // 33
(step_num ==33) ? 6 : // 34
(step_num ==34) ? 0 : // 35
(step_num ==35) ? 0 : // 36
(step_num ==36) ? 7 : // 37
(step_num ==37) ? 0 : // 38
(step_num ==38) ? 6 : // 39
(step_num ==39) ? 0 : // 40
(step_num ==40) ? 5 : // 41
(step_num ==41) ? 5 : // 42
(step_num ==42) ? 0 : // 43
(step_num ==43) ? 0 : // 44
(step_num ==44) ? 3 : // 45
(step_num ==45) ? 0 : // 46
(step_num ==46) ? 3 : // 47
(step_num ==47) ? 0 : // 48
(step_num ==48) ? 5 : // 49
(step_num ==49) ? 0 : // 50
(step_num ==50) ? 4 : // 51
(step_num ==51) ? 0 : // 52
(step_num ==52) ? 3 : // 53
(step_num ==53) ? 0 : // 54
(step_num ==54) ? 2 : // 55
(step_num ==55) ? 0 : // 56
(step_num ==56) ? 1 : // 57
(step_num ==57) ? 1 : // 58
(step_num ==58) ? 1 : // 59
(step_num ==59) ? 1 : // 60
(step_num ==60) ? 0 : // 61
(step_num ==61) ? 0 : // 62
(step_num ==62) ? 0 : // 63
(step_num ==63) ? 0 : // 64
0;
wire [15:0] clkdivider =
(note_num == 0) ? 16'd0 :
(note_num == 1) ? 16'b1011101111110000 :
(note_num == 2) ? 16'b1010011101110000 :
(note_num == 3) ? 16'b1001010100110000 :
(note_num == 4) ? 16'b1000110011010000 :
(note_num == 5) ? 16'b0111110101110000 :
(note_num == 6) ? 16'b0110111111000000 :
(note_num == 7) ? 16'b0101111000000000 : 16'd0;
always @(posedge clk) begin
if(counter==0) begin
counter <= clkdivider;
end else begin
counter <= counter - 1'b1;
end
end
reg audio;
always @(posedge clk) if(counter==0) audio <= ~audio;
endmoduleLet's start test auditions
I think Masha approves;) ^ _ ^
conclusions
As it turned out, the FPGA for 64 cells is able to act as a sound generator for an alarm siren. The project with a melody about a small Christmas tree, took 61 cells out of 64. And this means that there are still resources, they can be used and created, for example, a musical doorbell (hi 90s!).
Source Codes: https://github.com/UA3MQJ/epm7064_audio
When writing an article, the ideas and source codes of the article from fpga2fun - Music Box were used .