Obsah:

Digitální zvukový syntetizér Basys3 FPGA: 5 kroků
Digitální zvukový syntetizér Basys3 FPGA: 5 kroků

Video: Digitální zvukový syntetizér Basys3 FPGA: 5 kroků

Video: Digitální zvukový syntetizér Basys3 FPGA: 5 kroků
Video: Syntezátor Roland SH-4d a OSC modely zvuků 2024, Listopad
Anonim
Image
Image
Digitální zvukový syntetizér Basys3 FPGA
Digitální zvukový syntetizér Basys3 FPGA
Digitální zvukový syntetizér Basys3 FPGA
Digitální zvukový syntetizér Basys3 FPGA

Tento digitální syntezátor klávesnice se sinusovými vlnami převezme uživatelské vstupy prostřednictvím řady momentálních přepínačů rozložených jako klávesnice a prostřednictvím reproduktoru bude vysílat zvukovou vlnu. Na základě uživatelských vstupů bude zařízení generovat sinusové vlny různých frekvencí od C4 do C6. Uživatel může zadávat noty od C4 až po C6 (celkem 25 not) a až čtyři klávesy současně - pokud stisknete více než čtyři klávesy, zazní čtyři nejnižší tóny.

Tento projekt provedli Ryan Morris a Mavis Tsoi pro naši třídu digitálního designu Cal Poly CPE 133:)

Krok 1: Teorie

Deska FPGA může vydávat pouze digitální signály. Jinými slovy, může produkovat pouze vysoké (3,3 V) napětí nebo nízké (0 V) napětí. Zvukové signály jsou však analogové a mohou mít nekonečně mnoho přírůstků napětí. Abychom to zvládli, použijeme k emulaci analogové vlny signál PWM (pulse width modulation). Pokud nevíte, co je PWM, podívejte se na toto:

Krok 2: Ingredience a nástroje

  • Počítač s nainstalovaným Vivado
  • Budeme používat Vivado verze 2017.2
  • Deska FPGA Basys3
  • 25 koncových spínačů SPDT (použili jsme je)
  • 30 propojovacích vodičů (jeden konec samec, druhý konec nezáleží), 12 palců
  • Nůžky na drát
  • Odstraňovače drátů
  • Náhradní drát pro pájení
  • Pájka s pryskyřičným jádrem
  • Páječka
  • Audio”samice audio konektor
  • Zesilovač/reproduktor
  • Něco, na co lze namontovat spínače (použili jsme protoboard + dřevěnou krabici)

Krok 3: Zapojení a nastavení hardwaru

Nastavení kabeláže a hardwaru
Nastavení kabeláže a hardwaru
Nastavení kabeláže a hardwaru
Nastavení kabeláže a hardwaru
Nastavení kabeláže a hardwaru
Nastavení kabeláže a hardwaru

architektura systému

Viz obrázek 1: 25 dostupných vstupů → Deska Basys3 → zesilovač a reproduktor.

Výstup

Viz obrázek 2: Deska Basys3 → 1/2palcový zvukový konektor pro ženy → reproduktor (se zesilovačem)

Vstup

Připojení pmod na desce Basys3 musí být připojeno k zemi, aby bylo vidět nízký vstup, a nebude správně fungovat, pokud zůstane ponecháno jako otevřený obvod. Z tohoto důvodu musíme používat přepínače SPDT pro všechny naše notové klíče. Přepínač SPDT v podstatě umožňuje uživateli přepínat mezi obvody po stisknutí, takže je použijeme jako „tlačítka“pro vstup nízkých (0 V) nebo vysokých (3,3 V) signálů na desku Basys3.

Každý přepínač bude mít svorku NO (normálně otevřený) připojenou k 3,3 V, NC (normálně zavřenou) svorku připojenou k GND a COM (společnou) svorku připojenou ke vstupu FPGA. Viz obrázek 3.

Protože máme 25 koncových spínačů, budou všechny sdílet společnou linku 3,3 V a společnou linku GND. Poté bude signální vedení z každého koncového spínače seskupeno do skupin po 8 a připojeno k pmod spojům na desce Basys3 pomocí propojovacích propojovacích kabelů, které lze zapnout, aby se minimalizoval monumentální nepořádek, který uděláme. Viz obrázek 4 nebo příklad prvních osmi kláves.

Krok 4: Nastavení VHDL (Vivado)

Nastavení VHDL (Vivado)
Nastavení VHDL (Vivado)
Nastavení VHDL (Vivado)
Nastavení VHDL (Vivado)

Generátor sinusových vln a generátor PWM byly nejprve testovány, aby se ujistil, že náš koncept funguje, poté byl integrován omezovač vstupu a sčítač/řadič amplitudy. Podrobnosti o funkci a I/O každého procesního bloku jsou uvedeny na obrázku. Kód je zobrazen níže, ale je také připojen jako soubory VHD a txt. Pokud existují nesrovnalosti, přejděte k souborům VHD.

BTW: Pravděpodobně jsme měli zkrátit naše řádky, ale vkládání kódu do Instructables se také ukázalo jako docela otravné, takže mezery nejsou největší a není zvýrazněno syntaxe. Pokud máte Vivado a rádi byste se řídili kódem, důrazně vám doporučujeme soubor si stáhnout.

Nejprve se podívejme na modul generátoru sinusových vln.

knihovna IEEE; použijte IEEE. STD_LOGIC_1164. ALL; použijte IEEE. NUMERIC_STD. ALL; entity Wave_Generator is Port (Trigger: in STD_LOGIC; - Key press Freq_Cnt: in STD_LOGIC_VECTOR (15 downto 0); - Counter value = 100MHz / (Note Frequency*64 Divitions of Sine Wave) (round to nearest num) - renamed z Freq wavegenCLK: v STD_LOGIC; - Basys3 100MHz CLK WaveOut: out STD_LOGIC_VECTOR (9 až 0)); - Podepsaná amplituda konce vlny Wave_Generator; architektura Behavioral of Wave_Generator is signal i: integer range 0 to 64: = 0; -index typu banky paměti amplitudy typ paměťový_typ je pole (0 až 63) s celočíselným rozsahem -64 až 63; - vytvořit paměťovou banku (ROM) pro uchování hodnot amplitudy- zajímá se tato RAM nebo ROM … amplituda signálu: typ_paměti: = (0, 7, 13, 19, 25, 30, 35, 40, 45, 49, 52, 55, 58, 60, 62, 63, 63, 63, 62, 60, 58, 55, 52, 49, 45, 40, 35, 30, 25, 19, 13, 7, 0, -7, -13, -19, -25, -30, -35, -40, -45, -49, -52, -55, -58, -60, -62, -63, -63, -63, -62, - 60, -58, -55, -52, -49, -45, -40, -35, -30, -25, -19, -13, -7); - banka amplitudové paměti pro proces zahájení sinusové vlny (wavegenCLK, Trigger) variabilní čítač: bez znaménka (15 dolů až 0): = to_unsigned (0, 16); - čítač děliče hodin, přejmenovaný z count1 begin if (rise_edge (wavegenCLK)) then if (Trigger = '1') then- key isPress counter counter: = counter + 1; if (counter = unsigned (Freq_Cnt)) then - Freq_Cnt = 100Mhz / (note freq * 64 divitions of the sine wave) - reset counter and assign amplitude data to output counter: = to_unsigned (0, 16); WaveOut <= STD_LOGIC_VECTOR (to_signed (amplitude (i), 10)); - přírůstek i pro další čtení i <= i + 1; - resetujte i, pokud byla dokončena jedna sinusová vlna, pokud (i = 63) pak i <= 0; konec pokud; konec pokud; - (čítač = bez znaménka (Freq_Cnt)) else- klávesa není stisknuta- reset výstupu, index amplitudy a čítač WaveOut <= "0000000000"; i <= 0; čítač: = to_unsigned (0, 16); --výstupní amplituda = -64, když se nehraje žádná nota, konec pokud; - (Trigger = '1') end if; - (rise_edge (CLK)) koncový proces; konec Behaviorální;

V Basys3 vygenerujeme digitální sinusovou vlnu pomocí vnitřních hodin a ROM. Tato ROM bude ukládat 64 hodnot, které představují 64 amplitud na sinusové vlně. Viz obrázek 1. 64 hodnot, které používáme, emuluje sinusovou vlnu s docela dobrým rozlišením.

Pomocí interních hodin počítáme do hodnoty, která představuje rychlost hodin dělenou frekvencí vlny, kterou chceme a 64: Clk div = 100MHz / (Freq * 64) Pokaždé, když náš čítač dosáhne této hodnoty, zavoláme na číslo z ROM a odešlete ji z našeho modulu generátoru vln. Frekvence naší vlny bude záviset na tom, jak rychle tyto amplitudy nazýváme.

Budeme mít 25 dílčích modulů, každý spojený s jednou frekvencí/poznámkou.

Zde je zbývající část kódu, který volá moduly generátoru sinusových vln:

knihovna IEEE; použijte IEEE. STD_LOGIC_1164. ALL; použijte IEEE. NUMERIC_STD. ALL; entita Two_Octave_Synth je Port (CLK: v STD_LOGIC; O4: v STD_LOGIC_VECTOR (11 až 0); O5: ve STD_LOGIC_VECTOR (12 až 0); výstup: mimo STD_LOGIC); konec Two_Octave_Synth; architektura Behavioral of Two_Octave_Synth is component Wave_Generator is Port (Trigger: in STD_LOGIC; Freq_Cnt: in STD_LOGIC_VECTOR (15 downto 0); wavegenCLK: in STD_LOGIC; WaveOut: out STD_LOGIC_VECTOR (9 downto 0)); koncová složka; --------------------------- výstupní signály z generátoru vln ------------------ ----- signál WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveE5, WaveE5, WaveE5, WaveE5 WaveAs5, WaveB5, WaveC6: podepsáno (9 až 0); -------------------------------- pro logiku výběru not -------------- ------ signál C4, Cs4, D4, Ds4, E4, F4, Fs4, G4, Gs4, A4, As4, B4, C5, Cs5, D5, Ds5, E5, F5, Fs5, G5, Gs5, A5, As5, B5, C6: bez znaménka (4 až 0); signál cntC4, cntCs4, cntD4, cntDs4, cntA5, cntA5: bez znaménka (4 až 0); chyba signálu: STD_LOGIC; ----------------------------------- pro přidání sinusových vln ----------- --------------- signál Wave0, Wave1, Wave2, Wave3: podepsáno (9 až 0); --signály z výstupního signálu modulu generátoru vln WaveSum: STD_LOGIC_VECTOR (9 až 0); -signál pro součet sinusových vln (kompliment 2 -512 až 511) signál positiveWaveSum: STD_LOGIC_VECTOR (9 až 0); -nepodepsáno 0 až 1023, pro použití v generátoru PWM ----------------------------------- pro generování PWM ------------------------------- signál ping_length: unsigned (9 downto 0): = unsigned (positiveWaveSum); --signal off_length: unsigned (6 downto 0): = to_unsigned (127, 7) -unsigned (WAVE); signál PWM: bez znaménka (9 až 0): = to_unsigned (0, 10); začít Note_C4: Mapa portu Wave_Generator (Trigger => O4 (0), Freq_Cnt => X "1755", wavegenCLK => CLK, podepsáno (WaveOut) => WaveC4); --5973, 261,63 Hz Note_Cs4: Mapa portu Wave_Generator (Trigger => O4 (1), Freq_Cnt => X "1606", wavegenCLK => CLK, signováno (WaveOut) => WaveCs4);-5638, 277,18 Hz Poznámka_D4: Mapa portu Wave_Generator (Trigger => O4 (2), Freq_Cnt => X "14C9", wavegenCLK => CLK, signováno (WaveOut) => WaveD4); --5321, 293,66 Hz Note_Ds4: Mapa portu Wave_Generator (Trigger => O4 (3), Freq_Cnt => X "139F", wavegenCLK => CLK, signováno (WaveOut) => WaveDs4);-5023, 311,13 Hz Note_E4: Mapa portu Wave_Generator (Trigger => O4 (4), Freq_Cnt => X "1285", wavegenCLK => CLK, signováno (WaveOut) => WaveE4); --4741, 329,63 Hz Poznámka_F4: Mapa portu Wave_Generator (Trigger => O4 (5), Freq_Cnt => X "117B", wavegenCLK => CLK, signováno (WaveOut) => WaveF4); --4475, 349,23 Hz Note_Fs4: Mapa portu Wave_Generator (Trigger => O4 (6), Freq_Cnt => X "1080", wavegenCLK => CLK, signováno (WaveOut) => WaveFs4);-4224, 369,99 Hz Note_G4: Mapa portu Wave_Generator (Trigger => O4 (7), Freq_Cnt => X "0F92", wavegenCLK => CLK, signováno (WaveOut) => WaveG4); --3986, 392,00 Hz Note_Gs4: Mapa portu Wave_Generator (Trigger => O4 (8), Freq_Cnt => X "0EB3", wavegenCLK => CLK, signováno (WaveOut) => WaveGs4);-3763, 415,30 Hz Note_A4: Mapa portu Wave_Generator (Trigger => O4 (9), Freq_Cnt => X "0DE0", wavegenCLK => CLK, podepsáno (WaveOut) => WaveA4); --3552, 440,00 Hz Poznámka_As4: Mapa portu Wave_Generator (Trigger => O4 (10), Freq_Cnt => X "0D18", wavegenCLK => CLK, signováno (WaveOut) => WaveAs4);-3352, 466,16 Hz Poznámka_B4: Mapa portu Wave_Generator (Trigger => O4 (11), Freq_Cnt => X "0C5C", wavegenCLK => CLK, signováno (WaveOut) => WaveB4); --3164, 493,88 Hz -------------------------------------------- ---------------------------------------------------------- --------------------------- Note_C5: Mapa portu Wave_Generator (Trigger => O5 (0), Freq_Cnt => X "0BAB", wavegenCLK => CLK, podepsáno (WaveOut) => WaveC5); --2987, 523,25 Hz Note_Cs5: Mapa portu Wave_Generator (Trigger => O5 (1), Freq_Cnt => X "0B03", wavegenCLK => CLK, signováno (WaveOut) => WaveCs5);-2819, 554,37 Hz Poznámka_D5: Mapa portu Wave_Generator (Trigger => O5 (2), Freq_Cnt => X "0A65", wavegenCLK => CLK, signováno (WaveOut) => WaveD5); --2661, 587,33 Hz Note_Ds5: Mapa portu Wave_Generator (Trigger => O5 (3), Freq_Cnt => X "09D0", wavegenCLK => CLK, signováno (WaveOut) => WaveDs5);-2512, 622,25 Hz Note_E5: Mapa portu Wave_Generator (Trigger => O5 (4), Freq_Cnt => X "0943", wavegenCLK => CLK, signováno (WaveOut) => WaveE5); --2371, 659,25 Hz Poznámka_F5: Mapa portu Wave_Generator (Trigger => O5 (5), Freq_Cnt => X "08Be", wavegenCLK => CLK, signováno (WaveOut) => WaveF5); --2238, 698,46 Hz Note_Fs5: Mapa portu Wave_Generator (Trigger => O5 (6), Freq_Cnt => X "0840", wavegenCLK => CLK, signováno (WaveOut) => WaveFs5);-2112, 739,99 Hz Note_G5: Mapa portu Wave_Generator (Trigger => O5 (7), Freq_Cnt => X "07CA", wavegenCLK => CLK, signováno (WaveOut) => WaveG5); --1994, 783,99 Hz Note_Gs5: Mapa portu Wave_Generator (Trigger => O5 (8), Freq_Cnt => X "075A", wavegenCLK => CLK, signováno (WaveOut) => WaveGs5);-1882, 830,61 Hz Note_A5: Mapa portu Wave_Generator (Trigger => O5 (9), Freq_Cnt => X "06F0", wavegenCLK => CLK, signováno (WaveOut) => WaveA5); --1776, 880,00 Hz Note_As5: Mapa portu Wave_Generator (Trigger => O5 (10), Freq_Cnt => X "068C", wavegenCLK => CLK, signováno (WaveOut) => WaveAs5);-1676, 932,33 Hz Note_B5: Mapa portu Wave_Generator (Trigger => O5 (11), Freq_Cnt => X "062E", wavegenCLK => CLK, signováno (WaveOut) => WaveB5); --1582, 987,77 Hz Poznámka_C6: Mapa portu Wave_Generator (Trigger => O5 (12), Freq_Cnt => X "05D6", wavegenCLK => CLK, signováno (WaveOut) => WaveC6); --1494, 1046,5 Hz ------------ logika výběru not ------------ C4 <= "0000" & O4 (0); Cs4 <= "0000" & O4 (1); D4 <= "0000" & O4 (2); Ds4 <= "0000" & O4 (3); E4 <= "0000" & O4 (4); F4 <= "0000" & O4 (5); Fs4 <= "0000" & O4 (6); G4 <= "0000" & O4 (7); Gs4 <= "0000" & O4 (8); A4 <= "0000" & O4 (9); As4 <= "0000" & O4 (10); B4 <= "0000" & O4 (11); C5 <= "0000" & O5 (0); Cs5 <= "0000" & O5 (1); D5 <= "0000" & O5 (2); Ds5 <= "0000" & O5 (3); E5 <= "0000" & O5 (4); F5 <= "0000" & O5 (5); Fs5 <= "0000" & O5 (6); G5 <= "0000" & O5 (7); Gs5 <= "0000" & O5 (8); A5 <= "0000" & O5 (9); As5 <= "0000" & O5 (10); B5 <= "0000" & O5 (11); C6 <= "0000" & O5 (12); cntC4 <= C4; cntCs4 <= C4 + Cs4; cntD4 <= C4 + Cs4 + D4; cntDs4 <= C4 + Cs4 + D4 + Ds4; cntE4 <= C4 + Cs4 + D4 + Ds4 + E4; cntF4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4; cntFs4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4; cntG4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4; cntGs4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4; cntA4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4; cntAs4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4; cntB4 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4; cntC5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5; cntCs5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5; cntD5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5; cntDs5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5; cntE5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5; cntF5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5; cntFs5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5; cntG5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5; cntGs5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5 + Gs5; cntA5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5 + Gs5 + A5; cntAs5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5 + Gs5 + A5 + As5; cntB5 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5 + Gs5 + A5 + As5 + B5; cntC6 <= C4 + Cs4 + D4 + Ds4 + E4 + F4 + Fs4 + G4 + Gs4 + A4 + As4 + B4 + C5 + Cs5 + D5 + Ds5 + E5 + F5 + Fs5 + G5 + Gs5 + A5 + As5 + B5 + C6; Výběr: WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5 WaveB5, WaveC6) begin if (cntC6 = "00000") then --------------- pokud nejsou generovány žádné signály Wave0 <= "0000000000"; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 <= "0000000000"; else if (O4 (0) = '1') then ------------------- note C4 playing Wave0 Wave0 Wave1 error Wave0 Wave1 Wave2 error Wave0 Wave1 Wave2 Wave3 error Wave0 Wave1 Wave2 Wave3 error Wave0 Wave1 Wave2 Wave3 error Wave0 Wave1 Wave2 Wave3 error Wave0 Wave1 Wave2 Wave3 error Wave0 Wave1 Wave2 error Wave0 Wave1 Wave2 wave3 Wave2 Wave3 error Wave0 Wave1 Wave2 Wave3 error Wave0 Wave1 Wave2 Wave3 error Wave0 Wave1 Wave2 Wave3 error Wave0 Wave1 Wave2 error Wave0 Wave1 Wave2 error3 = WaveC6; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave1 <= WaveC6; Wave2 <= "0000000000"; Wave3 Wave2 <= WaveC6; Wave3 Wave3 error Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave2 <= "0000000000"; Wave3 Chyba Wave3 <= '1'; koncový případ; konec pokud; konec pokud; konečný proces; ------------- sinusový sčítač -------------------- WaveSum <= STD_LOGIC_VECTOR (Wave0 + Wave1 + Wave2 + Wave3); --------- aby byla sinusová vlna pozitivní pro pwm --------------------- positiveWaveSum <= ne WaveSum (9) & WaveSum (8 až 0); ------------- PWM generátor --------------------- proces (CLK)-variabilní počet: bez znaménka (1 až 0): = to_unsigned (0, 2); begin if (rise_edge (CLK)) then --count: = count + 1; --if (count = to_unsigned (4, 2)) then --count: = to_unsigned (0, 2); --if (PWM = to_ if (PWM <délka ping) pak výstup <= '1'; jinak výstup <= '0'; konec pokud; PWM <= PWM + 1; délka ping <= bez znaménka (positiveWaveSum); --end if; end if; end process; end Behavioral;

4 Selector Selector Nejsložitější částí tohoto projektu je výběr pouze čtyř frekvencí. Udělali jsme to s IF příkazy Lotta a místo proměnných jsme použili signály, aby bylo možné proces simulovat a ladit. Zkoušeli jsme jiné metody pomocí proměnných a FOR smyček, ale narazili jsme na chyby za běhu. Nakonec jsme se tedy rozhodli, že pokud to bude fungovat, necháme to na pokoji. Neopravovat, co není rozbitý amirit?

Čtyři výstupní vlny jsou označeny Wave0, Wave1, Wave2, Wave3 - to je to, co se sečte a vytvoří konečný výstup.

Při pohledu na kód uvidíte spoustu signálů označených C4, Cs4, D4, Ds4 atd. Jedná se o 5bitové signály, které vezmou odpovídající spoušť z O4 (oktáva 4) nebo O5 (oktáva 5) a vytvoří je. 5bitové pro přidání.

Dále proměnné cntC4, cntCs4 atd. Představují, kolik not nižších než cílová nota bylo odehráno, včetně cílové noty. Pokud se například hraje na C4, E4, G4, A#4 a D5 (akord C9), cntC4 bude 1, cntE4 bude 2, cntG4 bude 3 atd.

Poté, kdykoli zazní nota, bude zkontrolován počet pro cílovou notu, aby se zjistilo, kam se má signál noty připojit. Pokud se například hraje nota D5 (což znamená, že O5 (2) je vysoká) a cntD5 je 3, pak se aktuálně hrají 3 noty, přičemž 2 tóny jsou nižší než D5, takže připojíme waveD5 k Wave2 (třetí vlna) počítání signálu z Wave0). Alternativně, pokud je cntD5 5, pak se aktuálně hraje 5 not, přičemž 4 noty jsou nižší než D5, takže waveD5 necháme viset a nic s tím neuděláme.

Příkazy IF se poté opakují, aby pokryly případy pro všech 25 poznámek.

Sčítač amplitudy

Poté, co jsou vybrány nejnižší 4 vlny, musíme je sečíst. Důvod, proč přidáme pouze čtyři poznámky dohromady, je ten, že myšlenka PWM, kterou používáme pro náš výstup, může mít pouze určité rozlišení, dokud PWM běží příliš pomalu a reproduktor nezačne přijímat čtvercovou vlnu PWM. Pokud bychom například použili rozlišení 8192 (13 bitů), každý z těchto 8192 bodů musí odpovídat stoupající hraně palubních hodin. Takže 100MHz / 8192 = 12,2kHz, což je dobře v dosahu lidského sluchu.

Vlastní přidání amplitud je velmi jednoduché, jen se musíte ujistit, že může běžet opravdu rychle.

PWM výstup

Pracovní cyklus PWM bude v tomto okamžiku představovat amplitudu naší výstupní vlny. Pokud například máme rozsah amplitudy 0 až 128, 0 by byl 0%pracovní cyklus, 64 by bylo 50%, 128 by bylo 100%atd. Tento PWM poběží extrémně rychle (náš je 97,6 kHz), tak rychle, že reproduktor nerozpozná jednotlivé čtvercové vlny a místo toho se podívá na průměrné napětí a vytvoří náš „analogový“signál.

Soubor omezení

Možná jste připojili svůj hardware jinak, takže se ujistěte, že soubor omezení odpovídá.

Krok 5: Stažení kódu

Níže je kód, a to ve formátu.txt i.vhd pro Vivado. Wave_Generator je submodul generátoru vln a Two_Octave_Synth je nejlepší modul se vším ostatním.

Doporučuje: