FPGA PIANO USING VHDL On Xilink Sparta Board
Jasmine A. Roberts
Columbia University , Electrical Engineering
Roberts, FPGA Piano Using VHDL
when " 01100"
=> => => => => => => when "1 0101" => when "10110" => when "10111" => when when when when when when
"01101" "10000" "10001" "10010" "10011" "10100"
when "1 1000" => when "1 1001"
=> when "11010" => when " 11011" => when "1 1100" =>
next_div next_di v next_div next_div next_div next_div next_div next_div next_div next_div next_div next_div next_div next_div next_div
<= x" 07E9"; -<= x"0777"; <= x"07E9"; <= x"0777"; <= x"070C"; <= x"06A7"; <= x"0647";
<= <= <= <=
x"05ED"; x"0598"; x"0547";
x"04FB";
<= x"04B4"; <= x"0470"; < = x"0431"; <= x" 03F4";
B3
-- B3# -- C4b -- C4 -- C4# -- D4 -- D4# -- E4 -- F4 -- F4# -- G4 -- G4# -- A4 -- A4# -- B4
DIV=2025
F=246.9
= C4
DIV=1911
F=261.6
= B3
DIV=2025
F=246.9
DIV=1911
F=261.6
DIV=1804
F=277.1
DIV=1703
F=293.6
DIV=1607
F=311.1
DIV=1517
F=329.6
DIV=1432
F=349.1
DIV=1351
F= 370
DIV=1275
F=392.1
DIV=1204
F=415.3
DIV=1136
F=440.1
DIV=1073 DIV=1012
F=468.9
F=494.1
RESULTS
corresponding Seven_seg.vhd contains a lookup table to map each note to the corresponding bit buffer, seg_buf. It has 8 bits – 4 segment outputs. It stores this value in an 8 bits per digit. This value is updated on the rising edge of the clock. A signal cur_dig is incremented on every rising edge of the clock. If cur_dig = 00, it sets dig_now to the first 4 bits of seg_buf, or the first display. If it is 01, it sets it to the second display. Otherwise, it displays nothing. It then decodes the dig_now to the corresponding signals that are sent to the 7 -segment display, through through another lookup table. seven
Additional stimulus was added for for
test bench.
various values va lues of pb_in and switch_in and saved to the Code was added to simulate the switches to play different notes. Simulation
results below:
Roberts, FPGA Piano Using VHDL
Roberts, FPGA Piano Using VHDL
design plays a few measures of “Part of Your World” from Disney’s “The Little Mermaid. The user interface was deleted (commented out so it could still be referenced to the encode notes) and played the output note from play_position to the signal note_select in piano.vhd. The notes are played at the latch output in note_play.vhd . A cascade of elseif statements executes the notes. Contained within the elsif statement are pointers to the notes found in the note lookup table. The “temp o” of the song was controlled by the frequency in hexadecimal. A half -note is one second, and is implemented by adding 50MHz to the previous signal. A quarter-note is implemented by adding 25MHz, a whole-note by adding 100MHz . Ideally, quarter-note triplets triplets should be executed by incrementing by 16 !! 50/3), unfortunately, unfortunately, when a design using quarter-note triplets was implemented, the output was muddled. Therefore, an easier easier tempo was implemented. implemented. The solution would be to responding increase the speed of the clock used to count through the notes . The notes cor responding to the measure played are B A F C B A F C C E F. This
”
CODE
PIANO.VHD
--- piano.vhd --
FPGA Piano
library IEEE; 1164 1164 .ALL; use IEEE.STD_LOGIC_ use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; library UNISIM; ll; use UNISIM.VComponents.a UNISIM.VComponents.all;
entity piano is port ( CLK_IN pb_in switch_in SPK_N SPK_P led_out digit_out seg_out
: : : : : : : :
in std_logic; in std_logic_vector( 3 downto 0); in std_logic_vector( 7 downto 0); out std_logic; out std_l ogic; out std_logic_vector( 7 downto 0); out std_logic_vector( 3 downto 0); out std_logic_vector( 7 downto 0)
Roberts, FPGA Piano Using VHDL
);
end piano; architecture Behavioral of piano is -- Xilin x Native Components component BUFG port ( I : in std_logic; O : out std_logic); end component;
component IBUFG port ( I : in std_logic; O : out std_logic); end component;
component IBUF
port ( I : in std_logic; O : out std_logic); end
component;
component OBUF
port ( I : in std_logic; O : out std_logic); end
component; component DCM
port ( CLKIN CLKFB RST
: in : in : in
PSEN
: in
PSINCDEC : in PSCLK : in DSSEN : in CLK0 : out : out CLK90 CLK180 : out : out CLK270 CLKDV : out CLK2X : out CLK2 X180 : out CLKFX : out CLKFX180 : out STATUS : out LOCKED : out PSDONE : out
std_logic; std_logic; std_logic; _logic; _logic; std std_logic; std_logic; std_logic; std_logic; std_logic; std_log ic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic_vector ( 7 std_logic; std_logic);
downto 0);
end component;
--
My Components:
--
Clock Divider
component clk_dvd port ( CLK
: RST : DIV : EN : CLK_OUT : ONE_SHOT:
in std_logic; in std_logic; in std_logic_vector( 15 in std_logic; out std_logic; out std_logic
downto 0);
);
end component;
--
Note
decoder
component note_gen port (
CLK RST NOTE_IN DIV );
end compone nt;
: : : :
in in in out
std_logic; std_logic; std_logic_vector( 4 downto 0); std_logic_vector( 15 downto 0)
Roberts, FPGA Piano Using VHDL
process (div, sound) begin if (div = x" 0000 ") then SPK <= GND; else
SPK <= sound;
end if; end process;
-- Speaker output SPK_OBUF_INST : OBUF OBUF port map (I=>SPK, O=>SPK_N); SPK_P <= GND;
-- Input/Output Buffers loop 0 : for i in
0 to 3
pb_ibuf : IBUF dig_obuf : OBUF end generate ; loop 1 : for i in
0 to 7
swt_obuf : IBUF led_obuf : OBUF seg_obuf : OBUF
generate
port map(I => pb_in(i), O => PB(i)); port map(I => digit_l(i), O => digit_out(i)); generate
port map(I => switch_in(i), O => switch(i)); port map(I => led(i), O => led_out(i)); port map(I => seg_l(i), O => seg_out(i));
end generate ;
---
Global Clock Buffers Pad
->
DCM
CLKIN_IBUFG_INST : IBUFG port map (I=>CLK_IN, O=>CLK0);
--
DCM
->
CLK
CLK0 _BUFG_INST _BUFG_INST
: BUFG port map (I=>CLK_BUF, O=>CLK) ;
-- DCM for Clock deskew and frequency synthesis DCM_INST : DCM port map (CLKFB=>CLK, CLKIN=>CLK0,
DSSEN=>GND, PSCLK=>GND, PSEN=>GND, PSIN CDEC=>GND, RST=>RST,
CLKDV=>open, CLKFX=>open, CLKFX180 =>open, CLK0=>CLK_BUF, CLK2X=>open,
CLK2X180=>open, CLK90=>open, CLK180 =>open, CLK270 =>open,
LOCKED=>led( 0), PSDONE=>open, STATUS=>open );
Roberts, FPGA Piano Using VHDL
--
Divide 50Mh z to 1Mhz clock
DIV_ 1M : clk_dvd port map ( CLK
=> CLK,
RST
=> RST,
DIV
=> x" 0019 ",
EN
=> '1',
25
--
CLK_OUT => one_mhz, 1 ONE_SHOT => one_mhz_ ); Divide 1Mhz to Various frequencies for the notes. DIV_NOTE : clk_dvd
--
port map ( CLK
=> CLK,
RST
=> RST,
DIV EN CLK_OUT
=> => => ONE_SHOT =>
div, one_mhz_ 1 sound, div_ 1
,
);
--
Divide 1Mhz to 10k 10k
DIV_ 10 10k : clk_dvd port map ( CLK
=> CLK,
RST
=> RST,
DIV
=> x" 0032 ",
--
EN => one_mhz_ 1 CLK_OUT => open, 10 10k_ 1 ONE_SHOT => clk_ );
--
50
,
Translate Encoded Note to clock divider for
1MHz clock.
note_g en_inst : note_gen port map ( CLK => CLK, RST
=> RST,
NOTE_IN => note_in, DIV
=> div
);
-- Wire up seven -seg controller to display current note. seven_se g_inst
: seven_seg
port map ( CLK
=> CLK,
RST
=> RST,
NOTE_IN SCAN_EN DIGIT SEG
=> => => =>
note_in, 10 10 k_ 1 clk_ digit_l, seg_l
,
);
--
User Interface
note_in <= note_next; process (CLK,RST) begin if (RST = ' 1') then note_next <= (others => ' 0'); elsif (CLK'event and CLK = ' 1') then case switch is
=> note_sel <= " 0001 "; -" 01000000 " => note_sel <= " 0011 "; --
when "100000 00"
C
when
D
Roberts, FPGA Piano Using VHDL
when " 00100000 " when " 00010000 "
when "00001000" when " 00000100 " when " 00000010 " when " 00000001 " when others
=> => => => => => =>
note_sel note_sel note _sel note_sel note_sel note_sel note_sel note_sel
<= " 0101 "; -<= " 0110 "; --
E
<=
"1000 ";
G
<= <= <= <=
" 1010 "; -- A " 1100 "; -- B " 1111"; -- Play a song "00 00";
--
F
end case;
PB( 3) is the octave key. if (switch=" 00000001 ")then note_next <= " 11111"; elsif (PB( 2) = ' 1') then note_next <= PB(3) & note_sel + 1;
-- Sharp -- Add one.
--
Flat
--
Minus one.
elsif (PB( 1) = ' 1') then note_next <= PB(3) & note_sel -
1;
else
note_next <= PB(3) & note_sel; end if; end if; end process; end Behavioral; .VHD NOTE _GEN.VHD
--- note_gen.vhd --
FPGA Piano
library IEEE; use IEEE.STD_LOGIC_ 1164 1164 .ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; library UNISIM; use UNISIM.VComponents.all;
---
Note
Generator
This is a lookup table of the different n ote
values.
entity note_gen is port (
CLK RST NOTE_IN DIV
: : : :
in in in out
std_logic; std_logic; std_logic_vector( 4 downto 0); std_logic_vector( 15 downto 0)
);
end note_gen;
architecture Behavioral of note_gen is signal next_div : std_logic_vector( 15 signal clk_count: std_logic_vector( 31 begin
-- Latch Output of DIV process (CLK,RST) begin if (RST = ' 1') then
downto 0); downto 0);