Cuprins:

Sintetizator audio digital Basys3 FPGA: 5 pași
Sintetizator audio digital Basys3 FPGA: 5 pași

Video: Sintetizator audio digital Basys3 FPGA: 5 pași

Video: Sintetizator audio digital Basys3 FPGA: 5 pași
Video: FPGA Nexys A7 100T - Basic Audio Synthesizer 2024, Iulie
Anonim
Image
Image
Sintetizator audio digital Basys3 FPGA
Sintetizator audio digital Basys3 FPGA
Sintetizator audio digital Basys3 FPGA
Sintetizator audio digital Basys3 FPGA

Acest sintetizator digital cu tastă cu undă sinusoidală va prelua intrările utilizatorului printr-o serie de comutatoare momentane dispuse ca o tastatură și va emite o undă audio printr-un difuzor. Pe baza intrărilor utilizatorului, dispozitivul va genera unde sinusoidale de diferite frecvențe de la C4 la C6. Utilizatorul poate introduce note de la C4 până la C6 (25 de note în total) și până la patru taste simultan - dacă sunt apăsate mai mult de patru taste, vor fi redate cele mai mici patru tonuri.

Acest proiect a fost realizat de Ryan Morris și Mavis Tsoi pentru clasa noastră de design digital Cal Poly CPE 133:)

Pasul 1: Teorie

O placă FPGA poate emite doar semnale digitale. Cu alte cuvinte, poate produce doar o tensiune ridicată (3,3V) sau o tensiune mică (0V). Cu toate acestea, semnalele audio sunt analogice și pot avea infinit de multe creșteri de tensiune. Pentru a rezolva acest lucru, vom utiliza un semnal PWM (modul de lățime a impulsului) pentru a emula o undă analogică. Dacă nu știți ce este PWM, verificați acest lucru:

Pasul 2: Ingrediente și instrumente

  • Computer cu Vivado instalat
  • Vom folosi versiunea Vivado 2017.2
  • Placa Basys3 FPGA
  • 25 de comutatoare de limită SPDT (le-am folosit)
  • 30 fire jumper (un capăt tată, celălalt capăt nu contează), 12 inch
  • Freze de sârmă
  • Decapanti de sârmă
  • Sârmă de rezervă pentru lipit
  • Sudură cu miez de rășină
  • Ciocan de lipit
  • Jack”mufă audio feminină
  • Amplificator / difuzor
  • Ceva pentru a monta comutatoarele (am folosit protoboard + cutie de lemn)

Pasul 3: Configurare cablare și hardware

Cablare și configurare hardware
Cablare și configurare hardware
Cablare și configurare hardware
Cablare și configurare hardware
Cablare și configurare hardware
Cablare și configurare hardware

Arhitectura sistemului

Vezi Figura 1: 25 de intrări disponibile → Placă Basys3 → amplificator și difuzor.

Ieșire

Vezi Figura 2: Placă Basys3 → Jack audio feminin de 1/2 → Difuzor (cu amplificator)

Intrare

Conexiunile pmod de pe placa Basys3 trebuie să fie conectate la masă pentru a vedea o intrare redusă și nu vor funcționa corect dacă sunt lăsate ca un circuit deschis. Din acest motiv, trebuie să folosim comutatoare SPDT pentru toate tastele noastre de notă. Un comutator SPDT permite utilizatorului să comute între circuite atunci când este apăsat, așa că le vom folosi ca „butoane” pentru a introduce semnale joase (0V) sau mari (3,3V) pe placa Basys3.

Fiecare comutator va avea terminalul NO (normal deschis) conectat la 3,3V, terminalul NC (normal închis) conectat la GND și terminalul COM (comun) conectat la intrarea FPGA. Vezi Figura 3.

Deoarece avem 25 de comutatoare de limită, toate vor partaja o linie comună de 3,3V și o linie comună GND. Apoi, linia de semnal de la fiecare întrerupător de limită va fi grupată în grupuri de 8 și conectată la conexiunile pmod de pe placa Basys3 folosind fire jumper care se pot închide pentru a minimiza mizeria monumentală pe care o vom face. Vezi Figura 4 sau un exemplu al primelor opt taste.

Pasul 4: Configurare VHDL (Vivado)

Configurare VHDL (Vivado)
Configurare VHDL (Vivado)
Configurare VHDL (Vivado)
Configurare VHDL (Vivado)

Generatorul de unde sinusoidale și generatorul PWM au fost testate mai întâi pentru a se asigura că conceptul nostru a funcționat, apoi limitatorul de intrare și sumatorul / schimbătorul de amplitudine au fost integrate. Detaliile funcției și I / O ale fiecărui bloc de proces sunt prezentate în figură. Codul este prezentat mai jos, dar este atașat și ca fișiere VHD și txt. Dacă există discrepanțe, mergeți cu fișierele VHD.

BTW: probabil că ar fi trebuit să ne facem liniile mai scurte, dar încorporarea codului pe Instructables s-a dovedit a fi destul de enervant de tratat, astfel încât spațiul nu este cel mai mare și nu există evidențierea sintaxei. Dacă aveți Vivado și doriți să urmați codul, vă recomandăm să descărcați fișierul.

În primul rând, să ne uităm la modulul Sine Wave Generator.

bibliotecă IEEE; utilizați IEEE. STD_LOGIC_1164. ALL; utilizați IEEE. NUMERIC_STD. ALL; entitatea Wave_Generator este Port (Trigger: în STD_LOGIC; - Apăsați tasta Freq_Cnt: în STD_LOGIC_VECTOR (15 până la 0); din Freq wavegenCLK: în STD_LOGIC; - Basys3 100MHz CLK WaveOut: out STD_LOGIC_VECTOR (9 până la 0)); - Amplitudinea semnată a capătului de undă Wave_Generator; arhitectură Comportamentul Wave_Generator este semnalul i: intervalul întreg de la 0 la 64: = 0; - indexul amplitudinii tip de banc de memorie memory_type este matricea (0 până la 63) în intervalul întreg -64 până la 63; - creați un banc de memorie (ROM) pentru a păstra valorile amplitudinii - această RAM sau ROM se întreabă doar … amplitudinea semnalului: memory_type: = (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); - banc de memorie de amplitudine pentru procesul sinusoidal de început (wavegenCLK, Trigger) contor variabil: nesemnat (15 până la 0): = to_unsigned (0, 16); - contor divizor de ceas, redenumit din count1 începe if (rising_edge (wavegenCLK)) atunci if (Trigger = '1') atunci - tasta este apăsată counter: = counter + 1; if (contor = nesemnat (Freq_Cnt)) atunci - Freq_Cnt = 100Mhz / (nota frecv * 64 diviziuni ale undei sinusoidale) - resetează contorul și atribuie date de amplitudine contorului de ieșire: = to_unsigned (0, 16); WaveOut <= STD_LOGIC_VECTOR (to_signed (amplitudine (i), 10)); - creșterea i pentru următoarea lectură i <= i + 1; - resetează i dacă o undă sinusoidală a fost finalizată dacă (i = 63) atunci i <= 0; incheie daca; incheie daca; - (contor = nesemnat (Freq_Cnt)) altceva - tasta nu este apăsată - resetați ieșirea, indicele de amplitudine și contorul WaveOut <= "0000000000"; i <= 0; contor: = to_unsigned (0, 16); --Amplitudine de ieșire = -64 când nu se redă nicio notă, dacă; - (Trigger = '1') sfârșit dacă; - (rising_edge (CLK)) finalizează procesul; final Comportamental;

Vom genera o undă sinusoidală digitală în Basys3 utilizând ceasul intern și un ROM. Acest ROM va stoca 64 de valori care reprezintă 64 de amplitudini pe o undă sinusoidală. Vezi Figura 1. Cele 64 de valori pe care le folosim emulează o undă sinusoidală cu o rezoluție destul de bună.

Folosind ceasul intern, numărăm la o valoare care reprezintă viteza ceasului împărțită la frecvența undei dorite și 64: Clk div = 100MHz / (Freq * 64) De fiecare dată când contorul nostru atinge acea valoare, apelăm un număr de la ROM-ul și trimiteți-l din modulul nostru generator de unde. Frecvența undei noastre va depinde de cât de repede numim aceste amplitudini.

Vom avea 25 de sub-module, fiecare asociat cu o singură frecvență / notă.

Iată restul codului care apelează modulele Sine Wave Generator:

bibliotecă IEEE; utilizați IEEE. STD_LOGIC_1164. ALL; utilizați IEEE. NUMERIC_STD. ALL; entitatea Two_Octave_Synth este Port (CLK: în STD_LOGIC; O4: în STD_LOGIC_VECTOR (11 până la 0); O5: în STD_LOGIC_VECTOR (12 până la 0); ieșire: out STD_LOGIC); end Two_Octave_Synth; arhitectura Comportamentul Two_Octave_Synth este component Wave_Generator este Port (Trigger: în STD_LOGIC; Freq_Cnt: în STD_LOGIC_VECTOR (15 până la 0); wavegenCLK: în STD_LOGIC; WaveOut: out STD_LOGIC_VECTOR (9 până la 0); componenta finală; --------------------------- semnalele de ieșire de la generatorul de unde ------------------ ----- semnal WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveG5, WaveGs5, WaveA WaveAs5, WaveB5, WaveC6: semnat (9 până la 0); -------------------------------- pentru logica de selectare a notelor -------------- ------ semnal 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: nesemnat (4 până la 0); semnal cntC4, cntCs4, cntD4, cntDs4, cntE4, cntF4, cntFs4, cntG4, cntGs4, cntA4, cntAs4, cntB4, cntC5, cntCs5, cntD5, cntDs5, cntE5, cnt5, cnt5, cnt5, cnt5, cnt5, cnt5, cnt5, cnt5: nesemnat (4 până la 0); eroare de semnal: STD_LOGIC; ----------------------------------- pentru adăugarea undelor sinusoidale ----------- --------------- semnal Wave0, Wave1, Wave2, Wave3: semnat (9 până la 0); - semnale de la semnalul de ieșire al modulului Wave Generator WaveSum: STD_LOGIC_VECTOR (9 până la 0); - semnal pentru unde sinusoidale însumate (compliment 2 de la -512 la 511) semnal pozitiv WaveSum: STD_LOGIC_VECTOR (9 până la 0); - nesemnat de la 0 la 1023, pentru utilizare în generatorul PWM ----------------------------------- pentru generarea PWM ------------------------------- semnal ping_length: unsigned (9 downto 0): = unsigned (positiveWaveSum); --signal off_length: unsigned (6 downto 0): = to_unsigned (127, 7) - nesemnat (WAVE); semnal PWM: nesemnat (9 până la 0): = to_unsigned (0, 10); începe Note_C4: harta portului Wave_Generator (Trigger => O4 (0), Freq_Cnt => X "1755", wavegenCLK => CLK, semnat (WaveOut) => WaveC4); --5973, 261,63 Hz Note_Cs4: Harta portului Wave_Generator (Trigger => O4 (1), Freq_Cnt => X "1606", wavegenCLK => CLK, semnat (WaveOut) => WaveCs4); - 5638, 277,18 Hz Note_D4: Harta portului Wave_Generator (Trigger => O4 (2), Freq_Cnt => X "14C9", wavegenCLK => CLK, semnat (WaveOut) => WaveD4); --5321, 293,66 Hz Notă_Ds4: Hartă port port Wave_Generator (Trigger => O4 (3), Freq_Cnt => X "139F", wavegenCLK => CLK, semnat (WaveOut) => WaveDs4); - 5023, 311,13 Hz Notă_E4: Harta portului Wave_Generator (Trigger => O4 (4), Freq_Cnt => X "1285", wavegenCLK => CLK, semnat (WaveOut) => WaveE4); --4741, 329,63 Hz Notă_F4: Harta portului Wave_Generator (Trigger => O4 (5), Freq_Cnt => X "117B", wavegenCLK => CLK, semnat (WaveOut) => WaveF4); --4475, 349,23 Hz Note_Fs4: Harta portului Wave_Generator (Trigger => O4 (6), Freq_Cnt => X "1080", wavegenCLK => CLK, semnat (WaveOut) => WaveFs4); - 4224, 369,99 Hz Note_G4: Harta portului Wave_Generator (Trigger => O4 (7), Freq_Cnt => X "0F92", wavegenCLK => CLK, semnat (WaveOut) => WaveG4); --3986, 392,00 Hz Note_Gs4: Harta portului Wave_Generator (Trigger => O4 (8), Freq_Cnt => X "0EB3", wavegenCLK => CLK, semnat (WaveOut) => WaveGs4); - 3763, 415,30 Hz Note_A4: Harta portului Wave_Generator (Trigger => O4 (9), Freq_Cnt => X "0DE0", wavegenCLK => CLK, semnat (WaveOut) => WaveA4); --3552, 440,00 Hz Note_As4: Harta portului Wave_Generator (Trigger => O4 (10), Freq_Cnt => X "0D18", wavegenCLK => CLK, semnat (WaveOut) => WaveAs4); - 3352, 466,16 Hz Note_B4: Harta portului Wave_Generator (Trigger => O4 (11), Freq_Cnt => X "0C5C", wavegenCLK => CLK, semnat (WaveOut) => WaveB4); --3164, 493,88 Hz -------------------------------------------- -------------------------------------------------- --------------------------- Notă_C5: harta portului Wave_Generator (Trigger => O5 (0), Freq_Cnt => X "0BAB", wavegenCLK => CLK, semnat (WaveOut) => WaveC5); - 2987, 523,25 Hz Notă_Cs5: Harta portului Wave_Generator (Trigger => O5 (1), Freq_Cnt => X "0B03", wavegenCLK => CLK, semnat (WaveOut) => WaveCs5); - 2819, 554,37 Hz Notă_D5: Harta portului Wave_Generator (Trigger => O5 (2), Freq_Cnt => X "0A65", wavegenCLK => CLK, semnat (WaveOut) => WaveD5); --2661, 587,33 Hz Note_Ds5: Harta portului Wave_Generator (Trigger => O5 (3), Freq_Cnt => X "09D0", wavegenCLK => CLK, semnat (WaveOut) => WaveDs5); - 2512, 622,25 Hz Note_E5: Harta portului Wave_Generator (Trigger => O5 (4), Freq_Cnt => X "0943", wavegenCLK => CLK, semnat (WaveOut) => WaveE5); --2371, 659,25 Hz Notă_F5: Harta portului Wave_Generator (Trigger => O5 (5), Freq_Cnt => X "08Be", wavegenCLK => CLK, semnat (WaveOut) => WaveF5); --2238, 698,46 Hz Note_Fs5: Harta portului Wave_Generator (Trigger => O5 (6), Freq_Cnt => X "0840", wavegenCLK => CLK, semnat (WaveOut) => WaveFs5); - 2112, 739,99 Hz Note_G5: Harta portului Wave_Generator (Trigger => O5 (7), Freq_Cnt => X "07CA", wavegenCLK => CLK, semnat (WaveOut) => WaveG5); --1994, 783,99 Hz Notă_Gs5: Harta portului Wave_Generator (Trigger => O5 (8), Freq_Cnt => X "075A", wavegenCLK => CLK, semnat (WaveOut) => WaveGs5); - 1882, 830,61 Hz Notă_A5: Harta portului Wave_Generator (Trigger => O5 (9), Freq_Cnt => X "06F0", wavegenCLK => CLK, semnat (WaveOut) => WaveA5); --1776, 880,00 Hz Note_As5: Harta portului Wave_Generator (Trigger => O5 (10), Freq_Cnt => X "068C", wavegenCLK => CLK, semnat (WaveOut) => WaveAs5); - 1676, 932,33 Hz Note_B5: Harta portului Wave_Generator (Trigger => O5 (11), Freq_Cnt => X "062E", wavegenCLK => CLK, semnat (WaveOut) => WaveB5); --1582, 987,77 Hz Notă_C6: Harta portului Wave_Generator (Trigger => O5 (12), Freq_Cnt => X "05D6", wavegenCLK => CLK, semnat (WaveOut) => WaveC6); --1494, 1046,5 Hz ------------ logică de selectare a notelor ------------ 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; Selecție: proces (WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveG5, Wave5s, WaveB5, WaveC6) începe dacă (cntC6 = "00000") atunci --------------- dacă nu sunt generate semnale Wave0 <= "0000000000"; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 <= "0000000000"; altceva dacă (O4 (0) = '1') atunci ------------------- nota C4 a jucat 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 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 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 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 Wave3 error Wave0 < = WaveC6; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave1 <= WaveC6; Wave2 <= "0000000000"; Wave3 Wave2 <= WaveC6; Wave3 Wave3 eroare Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave2 <= "0000000000"; Wave3 Wave3 eroare <= '1'; caz final; incheie daca; incheie daca; sfarsitul procesului; ------------- sumator sinusoidal -------------------- WaveSum <= STD_LOGIC_VECTOR (Wave0 + Wave1 + Wave2 + Wave3); --------- face val sinusoidal pozitiv pentru pwm --------------------- pozitiv WaveSum <= not WaveSum (9) & WaveSum (8 downto 0); ------------- Generator PWM --------------------- proces (CLK) - număr variabil: nesemnat (1 până la 0): = to_unsigned (0, 2); începeți dacă (rising_edge (CLK)) atunci --count: = count + 1; --if (count = to_unsigned (4, 2)) then --count: = to_unsigned (0, 2); --if (PWM = to_ if (PWM <ping_length) then output <= '1'; else output <= '0'; end if; PWM <= PWM + 1; ping_length <= unsigned (positiveWaveSum); --end if; end if; end process; end Comportamentale;

4 Selector de note Cea mai dificilă parte a acestui proiect este selectarea a doar patru frecvențe. Am făcut-o cu o mulțime de instrucțiuni IF și am folosit semnale în loc de variabile, astfel încât procesul să poată fi simulat și depanat. Am încercat alte metode folosind variabile și bucle FOR, dar am întâmpinat erori de rulare. Deci, în cele din urmă, am decis că, dacă funcționează, îl vom lăsa în pace. Nu remediați ce nu este rupt amiritul?

Cele patru unde de ieșire sunt etichetate Wave0, Wave1, Wave2, Wave3 - acestea sunt cele care vor fi adăugate împreună pentru a forma ieșirea finală.

Privind codul, veți vedea o grămadă de semnale etichetate C4, Cs4, D4, Ds4 etc. Acestea sunt semnale de 5 biți care iau declanșatorul corespunzător de la O4 (octava 4) sau O5 (octava 5) și le fac 5 biți pentru adăugare.

În continuare variabilele cntC4, cntCs4, etc reprezintă câte note mai mici decât nota țintă au fost redate, inclusiv nota țintă. De exemplu, dacă se joacă C4, E4, G4, A # 4 și D5 (coarda C9) cntC4 va fi 1, cntE4 va fi 2, cntG4 va fi 3 etc.

Apoi, ori de câte ori este redată o notă, contorul pentru nota țintă va fi examinat pentru a vedea unde să agățați semnalul notei. De exemplu, dacă nota D5 este redată (ceea ce înseamnă că O5 (2) este ridicată) și cntD5 este 3, atunci sunt redate în prezent 3 note, cu 2 note mai mici decât D5, deci vom lega waveD5 la Wave2 (a treia undă numărarea semnalului din Wave0). Alternativ, dacă cntD5 este 5, atunci sunt redate în prezent 5 note, cu 4 note mai mici decât D5, așa că vom lăsa waveD5 suspendat și nu vom face nimic cu el.

Declarațiile IF sunt apoi repetate pentru a acoperi cazurile pentru toate cele 25 de note.

Sumator de amplitudine

După ce sunt selectate cele mai mici 4 unde, trebuie să le adăugăm împreună. Motivul pentru care vom adăuga doar patru note împreună este că ideea PWM pe care o folosim pentru ieșirea noastră poate avea o anumită rezoluție până când PWM funcționează prea lent și difuzorul va începe să preia unda pătrată PWM. De exemplu, dacă ar fi să folosim o rezoluție de 8192 (13 biți), fiecare dintre cele 8192 de puncte trebuie să corespundă cu o margine ascendentă a ceasului de la bord. Deci, 100MHz / 8192 = 12,2kHz, care se încadrează în domeniul auditiv uman.

Adăugarea efectivă a amplitudinilor este foarte simplă, trebuie doar să vă asigurați că poate rula foarte repede.

Ieșire PWM

Ciclul de funcționare al PWM va reprezenta amplitudinea undei noastre de ieșire în acel moment. De exemplu, dacă avem un interval de amplitudine de la 0 la 128, 0 ar fi un ciclu de funcționare de 0%, 64 ar fi 50%, 128 ar fi 100%, etc. Acest PWM va rula extrem de rapid (al nostru este de 97,6 kHz), atât de rapid încât difuzorul nu va recunoaște undele pătrate individuale și, în schimb, se va uita la tensiunea medie, creând semnalul nostru „analogic”.

Fișier de constrângeri

Este posibil să fi conectat hardware-ul dvs. diferit, deci asigurați-vă că fișierul de constrângeri se potrivește.

Pasul 5: Descărcări de coduri

Mai jos este codul, atât în format.txt, cât și.vhd pentru Vivado. Wave_Generator este sub-modulul generator de unde, iar Two_Octave_Synth este modulul de top cu toate celelalte.

Recomandat: