Vous êtes sur la page 1sur 12

FPGA PIANO USING VHDL

On Xilink Sparta Board

!
Jasmine A. Roberts
Columbia University, Electrical Engineering

! !
! ! !

Roberts, FPGA Piano Using VHDL

ABSTRACT
The main intention of the project was to implement an electric piano on a Spartan 3 development board using Xilinx Integrated Software Environment. The hardware was done using VHDL encoding. By use of a piezoelectric speaker with moderately high impedance, the piano was driven directly from the FPGA. Switches output four-bit digital logic code transferred to FPGA. The VHDL description is synthesized to logic and the 8 notes corresponding to the C scale in global music theory, and mapped to the gates of the FPGA.

INTRODUCTION
The notes are encoded on switches by the following segment of code: when when when when when when when when "10000000" "01000000" "00100000" "00010000" "00001000" "00000100" "00000010" others -- C -- D -- E -- F -- G -- A -- B none

The clock used is a 50 MHz input clock, the following are the waveforms on CLK_OUT and ONE_SHOT for EN = '1' and DIV = X"32". The toggle and trigger waveforms are also presented !"#$%#&'( ! !"# !"#! ! !

DIV=X32=50, CLK=50MHz, f=0.5 MHz With a frequency of 0.5 MHz for CLK_OUT ! CLK_OUT!!!!!!!!""""!!!!""""!!!!""""!!!!"""""!!!!""""!!!!!""""! TRIGGER!!!!!!!!#!!!#!!!!#!!!#!!!!#!!!#!!!!#!!!#!!!!#!!!#!!!!#!!!! TOGGLE!!!!!!!!!!""""!!!!""""!!!!""""!!!!"""""!!!!""""!!!!!""""! ONE_SHOT!!!!!!!!!!#!!!!!!!!#!!!!!!!#!!!!!!!!#!!!!!!!#!!!!!!!!! ! !

For a 1MHz input, the output frequency as a function of divider value is . These values were verified with the values used for the note decoder to define the notes of the piano.
f = CLK / DIV * .5 ONE_SHOT frequency = F/2 when when when when when when when when when when when "00001" "00010" "00011" "00100" "00101" "00110" "00111" "01000" "01001" "01010" "01011" => => => => => => => => => => => next_div next_div next_div next_div next_div next_div next_div next_div next_div next_div next_div <= <= <= <= <= <= <= <= <= <= <= x"0EEE"; x"0E18"; x"0D4E"; x"0C8E"; x"0BDA"; x"0B30"; x"0A8E"; x"09F7"; x"0968"; x"08E1"; x"0861"; -----------C3 C3# D3 D3# E3 F3 F3# G3 G3# A3 A3# DIV=3822 DIV=3608 DIV=3406 DIV=3214 DIV=3034 DIV=2864 DIV=2702 DIV=2551 DIV=2408 DIV=2273 DIV=2145 F=130.8 F=138.6 F=146.8 F=155.6 F=164.8 F=174.6 F=185 F=196 F=207.6 F=219.9 F=233.1

Roberts, FPGA Piano Using VHDL

when when when when when when when when when when when when when when when

"01100" "01101" "10000" "10001" "10010" "10011" "10100" "10101" "10110" "10111" "11000" "11001" "11010" "11011" "11100"

=> => => => => => => => => => => => => => =>

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 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

= C4 = B3

DIV=2025 F=246.9 DIV=1911 F=261.6 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 F=468.9 DIV=1012 F=494.1

RESULTS
Seven_seg.vhd contains a lookup table to map each note to the corresponding seven-segment outputs. It stores this value in an 8-bit buffer, seg_buf. It has 8 bits 4 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 another lookup table. Additional stimulus was added for various values of pb_in and switch_in and saved to the test bench. Code was added to simulate the switches to play different notes. Simulation results below:
! ! !

Roberts, FPGA Piano Using VHDL

! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !

Roberts, FPGA Piano Using VHDL

! !

This design plays a few measures of Part of Your World from Disneys 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 tempo 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 should be executed by incrementing by 16 !! 50/3), unfortunately, when a design using quarter-note triplets was implemented, the output was muddled. Therefore, an easier tempo was implemented. The solution would be to increase the speed of the clock used to count through the notes. The notes corresponding to the measure played are B A F C B A F C C E F.
!

CODE
! ! PIANO.VHD --- piano.vhd - FPGA Piano -library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; library UNISIM; use 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_logic; 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 -- Xilinx component component; component component; component component; component component; component port ( Behavioral of piano is Native Components BUFG port ( I : in std_logic; O : out std_logic); end IBUFG port ( I : in std_logic; O : out std_logic); end IBUF OBUF port ( I : in std_logic; O : out std_logic); end port ( I : in std_logic; O : out std_logic); end : : : : : : : : : : : : : : : : : : : in in in in in in in out out out out out out out out out out out out std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic; std_logic_vector (7 downto 0); std_logic; std_logic);

DCM CLKIN CLKFB RST PSEN PSINCDEC PSCLK DSSEN CLK0 CLK90 CLK180 CLK270 CLKDV CLK2X CLK2X180 CLKFX CLKFX180 STATUS LOCKED PSDONE end component; -- My Components:

-- Clock Divider component clk_dvd port ( CLK : in std_logic; RST : in std_logic; DIV : in std_logic_vector(15 downto 0); EN : in std_logic; CLK_OUT : out std_logic; ONE_SHOT: out std_logic ); end component; -- Note decoder component note_gen port ( CLK : in RST : in NOTE_IN : in DIV : out ); end component;

std_logic; std_logic; std_logic_vector(4 downto 0); std_logic_vector(15 downto 0)

Roberts, FPGA Piano Using VHDL

-- 7-Segment Display for Notes component seven_seg port ( CLK : in std_logic; RST : in std_logic; NOTE_IN : in std_logic_vector(4 downto 0); SCAN_EN : in std_logic; DIGIT : out std_logic_vector(3 downto 0); SEG : out std_logic_vector(7 downto 0) ); end component; -- Signals signal CLK after DCM and BUFG signal CLK0 from pad signal CLK_BUF after IBUF signal GND signal RST signal PB after ibufs signal digit_l MUX before obuf signal switch switches after ibufs signal led ibufs signal seg_l segment select before : std_logic; : std_logic; : std_logic; : std_logic; : std_logic; : std_logic_vector(3 downto 0); : std_logic_vector(3 downto 0); : std_logic_vector(7 downto 0); : std_logic_vector(7 downto 0); : std_logic_vector(7 downto 0); obuf. -- 50MHz clock -- 50MHz clock -- 50MHz clock

-- Pushbuttons -- 7-seg digit -- Toggle -- LEDs after -- 7-seg

signal one_mhz : std_logic; -- 1MHz Clock signal one_mhz_1 : std_logic; -- pulse with f=1 MHz created by divider signal clk_10k_1 : std_logic; -- pulse with f=10kHz created by divider signal div : std_logic_vector(15 downto 0); -- variable clock divider for loadable counter signal note_in : std_logic_vector(4 downto 0); -- output of user interface. Current Note signal note_next : std_logic_vector(4 downto 0); -- Buffer holding current Note signal note_sel : std_logic_vector(3 downto 0); -- Encoding of switches. signal div_1 : std_logic; -- 1MHz pulse signal sound : std_logic; -- Output of Loadable Clock Divider. Sent to Speaker if note is playing. signal SPK : std_logic; -- Output for Speaker fed to OBUF begin GND <= '0'; RST <= PB(0); led(1) <= RST; running.

-- push button 1 is assigned the reset -- The led "on" indicates the program is

-- Combinational logic to turn the sound on and off

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 port map (I=>SPK, O=>SPK_N); SPK_P <= GND; -- Input/Output Buffers loop0 : for i in 0 to 3 generate pb_ibuf : IBUF port map(I => dig_obuf : OBUF port map(I => end generate ; loop1 : for i in 0 to 7 generate swt_obuf : IBUF port map(I => led_obuf : OBUF port map(I => seg_obuf : OBUF port map(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 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, PSINCDEC=>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 );

pb_in(i), O => PB(i)); digit_l(i), O => digit_out(i)); switch_in(i), O => switch(i)); led(i), O => led_out(i)); seg_l(i), O => seg_out(i));

Roberts, FPGA Piano Using VHDL

-- Divide 50Mhz to 1Mhz DIV_1M : clk_dvd port map ( CLK RST DIV EN CLK_OUT ONE_SHOT );

clock => => => => => => CLK, RST, x"0019", -- 25 '1', one_mhz, one_mhz_1

-- Divide 1Mhz to Various frequencies for the notes. DIV_NOTE : clk_dvd port map ( CLK => CLK, RST => RST, DIV => div, EN => one_mhz_1, CLK_OUT => sound, ONE_SHOT => div_1 ); -- Divide 1Mhz to 10k DIV_10k : clk_dvd port map ( CLK RST DIV EN CLK_OUT ONE_SHOT );

=> => => => => =>

CLK, RST, x"0032", -- 50 one_mhz_1, open, clk_10k_1 to clock divider for 1MHz clock. CLK, RST, note_in, div

-- Translate Encoded Note note_gen_inst : note_gen port map ( CLK => RST => NOTE_IN => DIV => );

-- Wire up seven-seg controller to display current note. seven_seg_inst : seven_seg port map ( CLK => CLK, RST => RST, NOTE_IN => note_in, SCAN_EN => clk_10k_1, DIGIT => digit_l, SEG => 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 when "10000000" => note_sel <= "0001"; -- C when "01000000" => note_sel <= "0011"; -- D

Roberts, FPGA Piano Using VHDL

when "00100000" when "00010000" when "00001000" when "00000100" when "00000010" when "00000001" when others end case;

=> => => => => => =>

note_sel note_sel note_sel note_sel note_sel note_sel note_sel

<= <= <= <= <= <= <=

"0101"; "0110"; "1000"; "1010"; "1100"; "1111"; "0000";

-------

E F G A B Play a song

-- Sharp -- Add one. 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; -- 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; NOTE_GEN.VHD --- note_gen.vhd - FPGA Piano -library IEEE; use IEEE.STD_LOGIC_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 note values. entity note_gen is port ( CLK RST NOTE_IN DIV ); end note_gen;

: : : :

in in in out

std_logic; std_logic; std_logic_vector(4 downto 0); std_logic_vector(15 downto 0)

architecture Behavioral of note_gen is signal next_div : std_logic_vector(15 downto 0); signal clk_count: std_logic_vector(31 downto 0); begin -- Latch Output of DIV process (CLK,RST) begin if (RST = '1') then

Roberts, FPGA Piano Using VHDL

DIV <= x"0000"; clk_count <= x"00000000"; elsif (CLK'event and CLK='1') then if(next_div/=x"FFFF") then DIV <= next_div; elsif(next_div=x"FFFF" and clk_count<x"2FAF080") then --50MHz/ 1 sec B4 DIV <=x"03F4"; clk_count <= clk_count+1; elsif(next_div=x"FFFF" and clk_count<x"5F5E100") then --100MHz/ 1 sec A4 DIV <= x"0470"; clk_count <= clk_count+1; elsif(next_div=x"FFFF" and clk_count<x"8F0D180") then --150MHz/ 1 sec F4 DIV <= x"0598"; clk_count <= clk_count+1; elsif(next_div=x"FFFF" and clk_count<x"BEBC200") then --200MHz/ 1 sec C4 DIV <= x"0777"; clk_count <= clk_count+1; elsif(next_div=x"FFFF" and clk_count<x"EE6B280") then --250MHz/ 1 sec B4 DIV <=x"03F4"; clk_count <= clk_count+1; elsif(next_div=x"FFFF" and clk_count<x"11E1A300") then --300MHz/ 1 sec A4 DIV <=x"0470"; clk_count <= clk_count+1; elsif(next_div=x"FFFF" and clk_count<x"14DC9380") then --350MHz/ 1 sec F4 DIV <=x"0598"; clk_count <= clk_count+1; elsif(next_div=x"FFFF" and clk_count<x"17D78400") then --400MHz/ 1 sec C4 DIV <=x"0777"; clk_count <= clk_count+1; elsif(next_div=x"FFFF" and clk_count<x"1AD27480") then --450MHz/ 1 sec C4 DIV <=x"0777"; clk_count <= clk_count+1; elsif(next_div=x"0598" and clk_count<x"1DCD6500") then --500MHz/ 1 sec F4 DIV <=x"0598"; clk_count <= clk_count+1; elsif(next_div=x"FFFF" and clk_count<x"20C85580") then --550MHz/ 1 sec E4 DIV <=x"05ED"; clk_count <= clk_count+1; elsif(next_div=x"FFFF" and clk_count<x"26BE3680") then --650MHz/ 2 sec F4 DIV <=x"0598"; elsif(next_div=x"FFFF" and clk_count<x"E01D0C0") then -275MHz/ 2 sec clk_count <= x"00000000"; end if;

Roberts, FPGA Piano Using VHDL

end if; end process; -- Lookup Table process (NOTE_IN) begin case NOTE_IN is when "00000" => next_div <= x"0000"; when "00001" => next_div <= x"0EEE"; when "00010" => next_div <= x"0E18"; when "00011" => next_div <= x"0D4E"; when "00100" => next_div <= x"0C8E"; when "00101" => next_div <= x"0BDA"; when "00110" => next_div <= x"0B30"; when "00111" => next_div <= x"0A8E"; when "01000" => next_div <= x"09F7"; when "01001" => next_div <= x"0968"; when "01010" => next_div <= x"08E1"; when "01011" => next_div <= x"0861"; when "01100" => next_div <= x"07E9"; when "01101" => next_div <= x"0777"; when "10000" => next_div <= x"07E9"; when "10001" => next_div <= x"0777"; when "10010" => next_div <= x"070C"; when "10011" => next_div <= x"06A7"; when "10100" => next_div <= x"0647"; when "10101" => next_div <= x"05ED"; when "10110" => next_div <= x"0598"; when "10111" => next_div <= x"0547"; when "11000" => next_div <= x"04FB"; when "11001" => next_div <= x"04B4"; when "11010" => next_div <= x"0470"; when "11011" => next_div <= x"0431"; when "11100" => next_div <= x"03F4"; when "11111" => next_div <= x"FFFF"; when others => next_div <= x"0000"; end case; end process; end Behavioral; !

----------------------------

C3 C3# D3 D3# E3 F3 F3# G3 G3# A3 A3# B3 B3# = C4 C4b = B3 C4 C4# D4 D4# E4 F4 F4# G4 G4# A4 A4# B4 B4

Vous aimerez peut-être aussi