Music Box From Fpga4fun
Music Box From Fpga4fun
Music Box From Fpga4fun
html
Xilinx and their University Program Altera and their University Program Lattice and their University Program Actel QuickLogic
Other links
A repository of many FPGA-FAQs, created from the comp.arch. pga newsgroup. Lots of FPGA links on this ePanarama page. The page has a nasty popup though. The opencores.org site, with its growing collection of pro!ects. Some nice con erence papers an" articles from An"raka#s site, plus other nice pages like $ultiplication in FPGAs and %istri&ute" Arithmetic. The FPGA Arca"e site, with old popular games recreated in FPGAs. uild your own FPGA!"ased Logic Analy'er. Also from the same author, FreeP() freeware P# layout software. The Open(ollector %ata&ase, a compilation of open hardware tools $ designs. The Alien *laughter ++ video game on an FPGA. $y,%L, an open source package that lets you use Python as an hardware description and verification language.
The latest fun is to put a custom #P% inside an FPGA. road su"&ect. Try these links' The FPGA (PU we" site, and their X*O( #P% pro&ect. The (%-. so t (PU core, a synthesi(a"le )*!"it #P% with development tools.
A nice list of Open +Ps / Open (ores. The Leon-0 SPA+# core. The 1ios-++ #P%, with many pro!ects and links from the #ornell %niversity.
Music box
,ere we teach our FPGA how to play sounds and music. -e start "y generating a single tone. Then slowly more fun stuff like producing a police siren and play a tune. .ou can listen to the sound produced "y clicking on the speaker icon. For e/ample here0s the 1police siren1 .
The hardware
A Pluto "oard, a speaker and a )23 resistor are used for this pro&ect.
The oscillator provides a fi/ed fre4uency to the FPGA. The FPGA divides the fi/ed fre4uency to drive an 56. The 56 is connected to a speaker through a )23 resistor. y changing the 56 fre4uency, the FPGA produces different sounds.
input clkC output speakerC >> inary counter, )*!"its wide reg D)8':E counterC al2ays F<pose"ge clk= counter G? counterH)C >> %se the highest "it of the counter <9S = to drive the speaker assign speaker ? counterD)8EC en"mo"ule The LS <counterD:E= would toggle with a fre4uency of )7.89,(. 1counterD)E1 with *.)789,(. And so on. -e use the 9S <"it )8= of the counter to drive the output. ,ere it goesI a nice ;@),( s4uare signal comes out of the 1speaker1 output.
A""ing a parameter
,ere0s essentially the same code. A new parameter named 1clkdivider1 was added, and the counter was changed into a 1count!down1 counter ! &ust a matter of preference. mo"ule music<clk, speaker=C input clkC output speakerC parameter clkdivider ? 78::::::>JJ:>7C reg D)J':E counterC al2ays F<pose"ge clk= i <counter??:= counter G? clkdivider!)C else counter G? counter!)C reg speakerC al2ays F<pose"ge clk= i <counter??:= speaker G? NspeakerC en"mo"ule
Am&ulance siren
Let0s alternate 7 tones. -e first use a 7J "its counter 1tone1 to produce a slow s4uare wave. The 9S "it <toneD7;E= toggles with a fre4uency of a"out ).8,(. Then we use this "it to switch "etween 7 fre4uencies for the main counter, and that alternates "etween the 7 tones. ,ere comes the am"ulanceI mo"ule music<clk, speaker=C input clkC output speakerC parameter clkdivider ? 78::::::>JJ:>7C reg D7;':E toneC al2ays F<pose"ge clk= tone G? toneH)C reg D)J':E counterC al2ays F<pose"ge clk= i <counter??:= counter G? <toneD7;E O clkdivider!) ' clkdivider>7!)=C else counter G? counter!)C reg speakerC al2ays F<pose"ge clk= i <counter??:= speaker G? NspeakerC en"mo"ule
Police siren
That "ecomes serious now. -e need to generate a ramp that sounds like a police siren. -e start with my 1tone1 counter. -e use only 7; "its to make it twice as fast <9S toggles at around ;,(=. Then here comes the trick to get an up!ramp. -e e/tract "its )8 through "it 7) of the tone counter, like that' toneD7)')8E. This gives us K "its, that go from : to )7K at some medium speed. After it reaches )7K, it rolls "ack to : and up again. To get a down!ramp. -e invert the same "its, like that' <NtoneD7)')8E=. This gives us K "its again,
that go down from )7K to :. To switch "etween the up!ramp and the down!ramp, we use toneD77E. As soon as the up!ramp hits )7K, we switch to the down!ramp, until it goes to :, and then "ack to the up!ramp... 2ire D*':E ramp ? <toneD77E O toneD7)')8E ' NtoneD7)')8E=C >> That means >> 1if toneD77E?) then ramp?toneD7)')8E else ramp?NtoneD7)')8E1 5f this ramp "usiness does not make sense to you, we have a more detailed e/planation here. So 1ramp1 value goes from K0"::::::: to K0"))))))). To get a usa"le value to produce a sound, we pad it with the 7 "its 0:)0 up front, and the * "its 0::::::0 in the "ack. 2ire D)J':E clkdivider ? P70":), ramp, *0"::::::QC This way, 1clkdivider1 have a value ranging from )80":)::::::::::::: to )80":))))))))::::::, or in he/ )80h7::: to )80h;F#:, or in decimal @)M7 to )*;7:. -ith a 789,( input clock, that produces 1speaker1 from K*8,( to )878,(. That gives us a high pitch siren. mo"ule music<clk, speaker=C input clkC output speakerC reg D77':E toneC al2ays F<pose"ge clk= tone G? toneH)C 2ire D*':E ramp ? <toneD77E O toneD7)')8E ' NtoneD7)')8E=C 2ire D)J':E clkdivider ? P70":), ramp, *0"::::::QC reg D)J':E counterC al2ays F<pose"ge clk= i <counter??:= counter G? clkdividerC else counter G? counter!)C reg speakerC al2ays F<pose"ge clk= i <counter??:= speaker G? NspeakerC en"mo"ule
,igh-spee" pursuit
Row let0s go in high!speed pursuit. The siren is sometimes slow, sometimes fast. So 1toneD7)')8E1 gives us a fast ramp, while 1toneD7J')@E1 gives us a slow one. 2ire D*':E fastsweep ? <toneD77E O toneD7)')8E ' NtoneD7)')8E=C 2ire D*':E slowsweep ? <toneD78E O toneD7J')@E ' NtoneD7J')@E=C 2ire D)J':E clkdivider ? P70":), <toneD7KE O slowsweep ' fastsweep=, *0"::::::QC The complete code looks like this. mo"ule music<clk, speaker=C
input clkC output speakerC reg D7K':E toneC al2ays F<pose"ge clk= tone G? toneH)C 2ire D*':E fastsweep ? <toneD77E O toneD7)')8E ' NtoneD7)')8E=C 2ire D*':E slowsweep ? <toneD78E O toneD7J')@E ' NtoneD7J')@E=C 2ire D)J':E clkdivider ? P70":), <toneD7KE O slowsweep ' fastsweep=, *0"::::::QC reg D)J':E counterC al2ays F<pose"ge clk= i <counter??:= counter G? clkdividerC else counter G? counter!)C reg speakerC al2ays F<pose"ge clk= i <counter??:= speaker G? NspeakerC en"mo"ule
Playing notes
Row we0d like to play a tune. -e need a way to play notes, like on a key"oard. 5f we use * "its to encode a note, we can get *J notes. There are )7 notes per octaves, so *J notes gives us more than 8 octaves, more than enough for a little tune.
*tep -.
To play a range of increasing notes, we instantiate a 7@ "its counter, from which we e/tract the * most significant "its, to give us the * "its of the note we want to play. reg D7K':E toneC al2ays F<pose"ge clk= tone G? toneH)C 2ire D8':E fullnote ? toneD7K'77EC -ith a 789h( clock, each note lasts )*Kms and it takes ):.*s to play all *J notes.
*tep 0.
-e divide the 1fullnote1 "y )7. That gives us the octave <8 octaves, so ; "its are enough, since it goes from : to J= and the note <from : to )), so J "its=. 2ire D7':E octaveC 2ire D;':E noteC "ivi"e8&y-0 div"y)7<.numer<fullnoteD8':E=, .4uotient<octave=, .remain<note==C .ou can see that we instantiate a su"!module called 1divideS"y)71 which takes case of the division. Betails are shown later.
*tep 9.
To go from one octave to the ne/t, fre4uency is multiplied "y 171. Tasy to do in hardware, we do that in step J. To go from one note to the ne/t, fre4uency is multiplied "y 1).:8MJ1. Rot really easy to do in hardware. So we use a look!up ta"le with pre!calculated values. -e divide the main clock "y 8)7 for note A, "y J@; for note AU, "y J8* for note ... +emem"er, dividing "y a lower value gives us a higher fre4uency>higher note, that0s what we want. al2ays F<note= case<note= :' clkdivider ? 8)7!)C >> A )' clkdivider ? J@;!)C >> AU> " 7' clkdivider ? J8*!)C >> ;' clkdivider ? J;)!)C >> # J' clkdivider ? J:*!)C >> #U>B" 8' clkdivider ? ;@J!)C >> B *' clkdivider ? ;*7!)C >> BU>T" K' clkdivider ? ;J7!)C >> T @' clkdivider ? ;7;!)C >> F M' clkdivider ? ;:J!)C >> FU>G" ):' clkdivider ? 7@K!)C >> G ))' clkdivider ? 7K)!)C >> GU>A" )7' clkdivider ? :C >> should never );' clkdivider ? :C >> should never )J' clkdivider ? :C >> should never )8' clkdivider ? :C >> should never en"case
al2ays F<pose"ge clk= i <counterSnote??:= counterSnote G? clkdividerC else counterSnote G? counterSnote!)C Tvery time 1counterSnote1 e4uals :, that gives us a tick for the ne/t stage' the octave divider.
*tep 5.
6k, we need now to take care of the octave. For the lowest octave, we divide 1counterSnote1 "y 78*. For octave ), we divide "y )7@... and so on... reg DK':E counterSoctaveC al2ays F<pose"ge clk= i <counterSnote??:= &egin i <counterSoctave??:= counterSoctave G? <octave??:O788'octave??)O)7K'octave??7O*;'octave??;O;)'octave??JO )8'K=C else counterSoctave G? counterSoctave!)C en" reg speakerC al2ays F<pose"ge clk= i <counterSnote??: $$ counterSoctave??:= speaker G? NspeakerC The full code is here'
mo"ule music<clk, speaker=C input clkC output speakerC reg D7K':E toneC al2ays F<pose"ge clk= tone G? toneH)C 2ire D8':E fullnote ? toneD7K'77EC 2ire D7':E octaveC 2ire D;':E noteC "ivi"e8&y-0 div"y)7<.numer<fullnoteD8':E=, .4uotient<octave=, .remain<note==C reg D@':E clkdividerC al2ays F<note= case<note= :' clkdivider ? 8)7!)C >> A )' clkdivider ? J@;!)C >> AU> " 7' clkdivider ? J8*!)C >> ;' clkdivider ? J;)!)C >> # J' clkdivider ? J:*!)C >> #U>B" 8' clkdivider ? ;@J!)C >> B *' clkdivider ? ;*7!)C >> BU>T" K' clkdivider ? ;J7!)C >> T @' clkdivider ? ;7;!)C >> F M' clkdivider ? ;:J!)C >> FU>G" ):' clkdivider ? 7@K!)C >> G ))' clkdivider ? 7K)!)C >> GU>A" )7' clkdivider ? :C >> should never );' clkdivider ? :C >> should never )J' clkdivider ? :C >> should never )8' clkdivider ? :C >> should never en"case
reg D@':E counterSnoteC al2ays F<pose"ge clk= i <counterSnote??:= counterSnote G? clkdividerC else counterSnote G? counterSnote!)C reg DK':E counterSoctaveC al2ays F<pose"ge clk= i <counterSnote??:= &egin i <counterSoctave??:= counterSoctave G? <octave??:O788'octave??)O)7K'octave??7O*;'octave??;O;)'octave??JO )8'K=C else counterSoctave G? counterSoctave!)C en" reg speakerC al2ays F<pose"ge clk= i <counterSnote??: $$ counterSoctave??:= speaker G? NspeakerC en"mo"ule
The 1divide "y )71 module takes a * "its value <numerator= and divides it "y )7 <denominator=. That gives us a ; "its 4uotient <:..8= and a J "its remainder <:..))=. -e tried to use the FPGA vendor provided 1divide1 function, "ut it is optimi(ed for general divide, while here the denominator is fi/ed. So a specific divide function was made. To divide "y )7, the trick is to divide "y J first, then "y ;. Bividing "y J is trivial' we remove 7 "its out of the numerator, and copy it to the remainder. So we are left with *!7?J "its to divide "y the value 1;1. That0s easily done with a lookup ta"le. mo"ule divideS"y)7<numer, 4uotient, remain=C input D8':E numerC output D7':E 4uotientC output D;':E remainC reg D7':E 4uotientC reg D;':E remainS"it;S"it7C assign remain ? PremainS"it;S"it7, numerD)':EQC >> the first 7 "its are copied through al2ays F<numerD8'7E= >> and &ust do a divide "y 1;1 on the remaining "its case<numerD8'7E= :' &egin 4uotient ? :C remainS"it;S"it7 ? :C en" )' &egin 4uotient ? :C remainS"it;S"it7 ? )C en" 7' &egin 4uotient ? :C remainS"it;S"it7 ? 7C en" ;' &egin 4uotient ? )C remainS"it;S"it7 ? :C en" J' &egin 4uotient ? )C remainS"it;S"it7 ? )C en" 8' &egin 4uotient ? )C remainS"it;S"it7 ? 7C en" *' &egin 4uotient ? 7C remainS"it;S"it7 ? :C en" K' &egin 4uotient ? 7C remainS"it;S"it7 ? )C en" @' &egin 4uotient ? 7C remainS"it;S"it7 ? 7C en" M' &egin 4uotient ? ;C remainS"it;S"it7 ? :C en" ):' &egin 4uotient ? ;C remainS"it;S"it7 ? )C en" ))' &egin 4uotient ? ;C remainS"it;S"it7 ? 7C en" )7' &egin 4uotient ? JC remainS"it;S"it7 ? :C en" );' &egin 4uotient ? JC remainS"it;S"it7 ? )C en" )J' &egin 4uotient ? JC remainS"it;S"it7 ? 7C en" )8' &egin 4uotient ? 8C remainS"it;S"it7 ? :C en" en"case en"mo"ule
A tune
Let0s play a tune nowI 5t0s easy, &ust a matter of using a +69 to hold the notes. reg D;:':E toneC al2ays F<pose"ge clk= tone G? toneH)C 2ire DK':E fullnoteC musicSrom rom<.inclock<clk=, .outclock<clk=, .address<toneD7M'77E=, .4<fullnote==C The 1musicSrom1 is generated "y your FPGA vendor tool. For e/ample, Altera0s Vuartus and its 1megafunction1 generator produces these iles.
-e also want that the tune pauses after the +69 ends the 1fullnote1 of value : is a 4uiet note. so we change the last line of the previous design from al2ays F<pose"ge clk= i <counterSnote??: $$ counterSoctave??:= speaker G? NspeakerC into al2ays F<pose"ge clk= i <counterSnote??: $$ counterSoctave??: $$ toneD;:E??: $$ fullnoteI ?:= speaker G? NspeakerC The rest of the design stays the same. #an you recogni(e the tuneO
Digital oscilloscope
A digital oscilloscope has many advantages over its analog counterpart, like the a"ility to capture single events, and to display what happens "efore the trigger. .ou can "uild a digital oscilloscope simply "y hooking an AB# and an FPGA together. This particular design uses an )::9,( flash AB#, so we are "uilding an )::9SPS <mega!samples!per! seconds= oscilloscope. This oscilloscope design is interesting "ecause it shows how powerful and useful modern FPGAs can "e. ut if you are new to FPGA technology, keep that in mind this is not the easiest design to understand on this site.
HDL design
6r how to create the oscilloscope logic inside the FPGA.
,%L part - ! F5F6!"ased design. ,%L part 0 ! +A9!"ased design. ,%L part 9 ! Trigger mechanism. ,%L part 5 ! 9ore functionality.
Hardware
This design was created using the ;1<1 Flashy &oar"s. See also the 3han"s-on3 page on how to "uild a simple oscilloscope.
Software
A software is provided with the 2RWR "oards.
,istory= eatures= screen shots. See also inter erence patterns on 2RWR.com
*creenshot
,ere0s the view of a 7K9,( signal, sampled at )::9,( and reconstructed using the 1sample e4uivalent time1 techni4ue.
Links
,ow to "uild a "igital oscilloscope "ased on the AB#:@:J and 6penGL A nice Oscilloscope FAQ site with lots of information. ,o2 oscilloscopes 2ork from )>; Precision. Pro&ing ,igh-*pee" %igital %esigns from *ignal (onsulting= +nc.