Taula de continguts:

Sintetitzador d'àudio digital Basys3 FPGA: 5 passos
Sintetitzador d'àudio digital Basys3 FPGA: 5 passos

Vídeo: Sintetitzador d'àudio digital Basys3 FPGA: 5 passos

Vídeo: Sintetitzador d'àudio digital Basys3 FPGA: 5 passos
Vídeo: AMD Xilinx Arty A7, Artix 7 FPGA Evaluation Board - Getting Started 2024, Juliol
Anonim
Image
Image
Sintetitzador d'àudio digital Basys3 FPGA
Sintetitzador d'àudio digital Basys3 FPGA
Sintetitzador d'àudio digital Basys3 FPGA
Sintetitzador d'àudio digital Basys3 FPGA

Aquest sintetitzador digital de teclat d'ona sinusoïdal prendrà les entrades de l'usuari mitjançant una sèrie d'interruptors momentanis disposats com un teclat i emetrà una ona d'àudio a través d'un altaveu. Basat en les entrades de l'usuari, el dispositiu generarà ones sinusoïdals de diverses freqüències de C4 a C6. L'usuari pot introduir notes des de C4 fins a C6 (25 notes en total) i fins a quatre tecles alhora - si es premen més de quatre tecles, es reproduiran els quatre tons més baixos.

Aquest projecte el van fer Ryan Morris i Mavis Tsoi per a la nostra classe de disseny digital Cal Poly CPE 133:)

Pas 1: teoria

Una placa FPGA només pot emetre senyals digitals. En altres paraules, només pot produir una tensió alta (3,3 V) o baixa (0 V). No obstant això, els senyals d'àudio són analògics i poden tenir infinits increments de tensió. Per solucionar-ho, utilitzarem un senyal PWM (modulació d’amplada de pols) per emular una ona analògica. Si no sabeu què és PWM, consulteu això:

Pas 2: ingredients i eines

  • Ordinador amb Vivado instal·lat
  • Utilitzarem la versió 2017 de Vivado
  • Taula FPGA Basys3
  • 25 interruptors de límit SPDT (els hem utilitzat)
  • 30 cables de pont (un extrem masculí, l’altre extrem no importa), de 12 polzades
  • Talladors de filferro
  • Decapants de filferro
  • Filferro de recanvi per soldar
  • Soldadura de nucli de resina
  • Soldador
  • Connector d'àudio femení de ¼”
  • Amplificador / altaveu
  • Alguna cosa per muntar els interruptors (hem utilitzat protoboard + caixa de fusta)

Pas 3: Configuració de cablejat i maquinari

Configuració de cablejat i maquinari
Configuració de cablejat i maquinari
Configuració de cablejat i maquinari
Configuració de cablejat i maquinari
Configuració de cablejat i maquinari
Configuració de cablejat i maquinari

Arquitectura de sistemes

Vegeu la figura 1: 25 entrades disponibles → Basys3 Board → amplificador i altaveu.

Sortida

Vegeu la figura 2: Taula Basys3 → Connector d'àudio femella de 1/2 → Altaveu (amb amplificador)

Entrada

Les connexions pmod de la placa Basys3 s'han de connectar a terra per tal de veure una entrada baixa i no funcionaran correctament si es deixen com un circuit obert. Per això, hem d’utilitzar commutadors SPDT per a totes les nostres tecles de notes. Un commutador SPDT permet bàsicament a l'usuari canviar entre circuits quan es prem, de manera que els utilitzarem com a "botons" per introduir senyals baixos (0V) o alts (3,3V) a la placa Basys3.

Cada commutador tindrà el terminal NO (normalment obert) connectat a 3,3 V, el terminal NC (normalment tancat) connectat a GND i el terminal COM (comú) connectat a l'entrada FPGA. Vegeu la figura 3.

Com que tenim 25 interruptors de límit, tots compartiran una línia comuna de 3,3V i una línia GND comuna. A continuació, la línia de senyal de cada interruptor de límit s’agruparà en grups de vuit i es connectarà a les connexions pmod de la placa Basys3 mitjançant cables jumper que es poden tancar per minimitzar el desordre monumental que farem. Vegeu la figura 4 o un exemple de les primeres vuit tecles.

Pas 4: Configuració de VHDL (Vivado)

Configuració de VHDL (Vivado)
Configuració de VHDL (Vivado)
Configuració de VHDL (Vivado)
Configuració de VHDL (Vivado)

El generador d’ones sinusoïdals i el generador PWM es van provar primer per assegurar-se que el nostre concepte funcionava, després es van integrar el limitador d’entrada i el sumador / canvi d’amplitud. Els detalls de la funció i E / S de cada bloc de procés són els que es mostren a la figura. El codi es mostra a continuació, però també s’adjunta com a fitxers VHD i txt. Si hi ha discrepàncies, aneu amb els fitxers VHD.

BTW: probablement hauríem d’haver reduït les nostres línies, però la inserció de codi a Instructables també va resultar ser molt molesta, de manera que l’espaiat no és el més gran i no hi ha ressaltat de sintaxi. Si teniu Vivado i voleu seguir el codi, us recomanem que descarregueu el fitxer.

En primer lloc, vegem el mòdul Generador d’ones sinusoidals.

biblioteca IEEE; utilitzeu IEEE. STD_LOGIC_1164. ALL; utilitzeu IEEE. NUMERIC_STD. ALL; entitat Wave_Generator és Port (Trigger: a STD_LOGIC; - Premeu la tecla Freq_Cnt: a STD_LOGIC_VECTOR (15 fins a 0); de Freq wavegenCLK: a STD_LOGIC; - Basys3 100MHz CLK WaveOut: fora de STD_LOGIC_VECTOR (9 a 0)); - Amplitud signada del final d'ona Wave_Generator; arquitectura El comportament de Wave_Generator és el senyal i: rang enter de 0 a 64: = 0; - l’índex del tipus de banc de memòria d’amplitud memory_type és una matriu (0 a 63) d’un rang enter de -64 a 63; - Creeu un banc de memòria (ROM) per contenir valors d'amplitud: aquesta memòria RAM o ROM només es pregunta … amplitud del senyal: 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 memòria d'amplitud per al procés d'inici de l'ona sinusoïdal (wavegenCLK, Trigger) comptador variable: sense signar (15 fins a 0): = to_unsigned (0, 16); - comptador divisor de rellotge, canviat el nom de count1 començar if (rising_edge (wavegenCLK)) llavors if (Trigger = '1') llavors - es prem la tecla comptador: = comptador + 1; if (comptador = sense signar (Freq_Cnt)) aleshores - Freq_Cnt = 100Mhz / (nota freq * 64 divisions de l’ona sinusoïdal): restableix el comptador i assigna les dades d’amplitud al comptador de sortida: = to_unsigned (0, 16); WaveOut <= STD_LOGIC_VECTOR (signat (amplitud (i), 10)); - increment i per a la següent lectura i <= i + 1; - restableix i si s'ha completat una ona sinusoïdal si (i = 63) llavors i <= 0; acabar si; acabar si; - (comptador = sense signar (Freq_Cnt)) else - no es prem la tecla - restableix la sortida, l'índex d'amplitud i el comptador WaveOut <= "0000000000"; i <= 0; comptador: = to_unsigned (0, 16); --Amplitud de sortida = -64 quan no es reprodueix cap nota, acaba si; - (Trigger = '1') end if; - (rising_edge (CLK)) procés final; final Conductual;

Generarem una ona sinusoïdal digital a Basys3 mitjançant el rellotge intern i una ROM. Aquesta ROM emmagatzemarà 64 valors que representen 64 amplituds en una ona sinusoïdal. Vegeu la figura 1. Els 64 valors que fem servir emulen una ona sinusoïdal amb una resolució força bona.

Mitjançant el rellotge intern, comptem fins a un valor que representa la velocitat del rellotge dividida per la freqüència de l’ona que volem i 64: Clk div = 100MHz / (Freq * 64) Cada vegada que el nostre comptador arriba a aquest valor, cridem a un número de la ROM i enviar-la del nostre mòdul generador d'ones. La freqüència de la nostra ona dependrà de la rapidesa amb què anomenem aquestes amplituds.

Tindrem 25 submòduls, cadascun associat a una freqüència / nota.

Aquí teniu la resta del codi que crida als mòduls Sine Wave Generator:

biblioteca IEEE; utilitzeu IEEE. STD_LOGIC_1164. ALL; utilitzeu IEEE. NUMERIC_STD. ALL; l’entitat Two_Octave_Synth és Port (CLK: a STD_LOGIC; O4: a STD_LOGIC_VECTOR (11 fins a 0); O5: a STD_LOGIC_VECTOR (12 a 0); sortida: fora STD_LOGIC); final Two_Octave_Synth; arquitectura Comportamental de Two_Octave_Synth és component Wave_Generator és 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); component final; --------------------------- Senyals de sortida del generador d'ones ------------------ ----- senyal 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: signat (de 9 a 0); -------------------------------- per a la lògica de selecció de notes -------------- ------ senyal 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: sense signar (4 a 0); senyal 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: sense signar (4 a 0); error de senyal: STD_LOGIC; ----------------------------------- per afegir ones sinusoïdals ----------- --------------- senyal Wave0, Wave1, Wave2, Wave3: signat (9 a 0); --signals del senyal de sortida del mòdul Wave Generator WaveSum: STD_LOGIC_VECTOR (9 fins a 0); - senyal d'ones sinusoïdals sumades (compliment de 2 -512 a 511) senyal positiu WaveWorm: STD_LOGIC_VECTOR (9 a 0); - sense signar del 0 al 1023, per utilitzar-lo al generador PWM ----------------------------------- per generar PWM ------------------------------- senyal ping_length: unsigned (9 downto 0): = unsigned (positiveWaSSum); --signal off_length: unsigned (6 downto 0): = to_unsigned (127, 7) - unsigned (WAVE); senyal PWM: sense signar (de 9 a 0): = a_no signat (0, 10); començar Nota_C4: mapa de ports Wave_Generator (Trigger => O4 (0), Freq_Cnt => X "1755", wavegenCLK => CLK, signat (WaveOut) => WaveC4); --5973, 261,63 Hz Note_Cs4: mapa de ports Wave_Generator (Trigger => O4 (1), Freq_Cnt => X "1606", wavegenCLK => CLK, signat (WaveOut) => WaveCs4); - 5638, 277,18 Hz Note_D4: Mapa de ports Wave_Generator (Trigger => O4 (2), Freq_Cnt => X "14C9", wavegenCLK => CLK, signat (WaveOut) => WaveD4); --5321, 293,66 Hz Nota_Ds4: mapa de ports Wave_Generator (Trigger => O4 (3), Freq_Cnt => X "139F", wavegenCLK => CLK, signat (WaveOut) => WaveDs4); - 5023, 311,13 Hz Note_E4: Mapa de ports Wave_Generator (Trigger => O4 (4), Freq_Cnt => X "1285", wavegenCLK => CLK, signat (WaveOut) => WaveE4); --4741, 329,63 Hz Nota_F4: mapa de ports Wave_Generator (Trigger => O4 (5), Freq_Cnt => X "117B", wavegenCLK => CLK, signat (WaveOut) => WaveF4); --4475, 349,23 Hz Note_Fs4: mapa de ports Wave_Generator (Trigger => O4 (6), Freq_Cnt => X "1080", wavegenCLK => CLK, signat (WaveOut) => WaveFs4); - 4224, 369,99 Hz Note_G4: Mapa de ports Wave_Generator (Trigger => O4 (7), Freq_Cnt => X "0F92", wavegenCLK => CLK, signat (WaveOut) => WaveG4); --3986, 392,00 Hz Nota_Gs4: mapa de ports Wave_Generator (Trigger => O4 (8), Freq_Cnt => X "0EB3", wavegenCLK => CLK, signat (WaveOut) => WaveGs4); - 3763, 415,30 Hz Nota_A4: Mapa de ports Wave_Generator (Trigger => O4 (9), Freq_Cnt => X "0DE0", wavegenCLK => CLK, signat (WaveOut) => WaveA4); --3552, 440,00 Hz Nota_As4: mapa de ports Wave_Generator (Trigger => O4 (10), Freq_Cnt => X "0D18", wavegenCLK => CLK, signat (WaveOut) => WaveAs4); - 3352, 466,16 Hz Note_B4: Mapa de ports Wave_Generator (Trigger => O4 (11), Freq_Cnt => X "0C5C", wavegenCLK => CLK, signat (WaveOut) => WaveB4); --3164, 493,88 Hz -------------------------------------------- -------------------------------------------------- --------------------------- Nota_C5: mapa de ports Wave_Generator (Trigger => O5 (0), Freq_Cnt => X "0BAB", wavegenCLK => CLK, signat (WaveOut) => WaveC5); --2987, 523,25 Hz Note_Cs5: mapa de ports Wave_Generator (Trigger => O5 (1), Freq_Cnt => X "0B03", wavegenCLK => CLK, signat (WaveOut) => WaveCs5); - 2819, 554,37 Hz Note_D5: Mapa de ports Wave_Generator (Trigger => O5 (2), Freq_Cnt => X "0A65", wavegenCLK => CLK, signat (WaveOut) => WaveD5); --2661, 587,33 Hz Nota_Ds5: mapa de ports Wave_Generator (Trigger => O5 (3), Freq_Cnt => X "09D0", wavegenCLK => CLK, signat (WaveOut) => WaveDs5); - 2512, 622,25 Hz Nota_E5: Mapa de ports Wave_Generator (Trigger => O5 (4), Freq_Cnt => X "0943", wavegenCLK => CLK, signat (WaveOut) => WaveE5); --2371, 659,25 Hz Nota_F5: mapa de ports Wave_Generator (Trigger => O5 (5), Freq_Cnt => X "08Be", wavegenCLK => CLK, signat (WaveOut) => WaveF5); --2238, 698,46 Hz Nota_Fs5: mapa de ports Wave_Generator (Trigger => O5 (6), Freq_Cnt => X "0840", wavegenCLK => CLK, signat (WaveOut) => WaveFs5); - 2112, 739,99 Hz Note_G5: Mapa de ports Wave_Generator (Trigger => O5 (7), Freq_Cnt => X "07CA", wavegenCLK => CLK, signat (WaveOut) => WaveG5); --1994, 783,99 Hz Nota_Gs5: mapa de ports Wave_Generator (Trigger => O5 (8), Freq_Cnt => X "075A", wavegenCLK => CLK, signat (WaveOut) => WaveGs5); - 1882, 830,61 Hz Nota_A5: Mapa de ports Wave_Generator (Trigger => O5 (9), Freq_Cnt => X "06F0", wavegenCLK => CLK, signat (WaveOut) => WaveA5); --1776, 880,00 Hz Nota_As5: mapa de ports Wave_Generator (Trigger => O5 (10), Freq_Cnt => X "068C", wavegenCLK => CLK, signat (WaveOut) => WaveAs5); - 1676, 932,33 Hz Nota_B5: Mapa de ports Wave_Generator (Trigger => O5 (11), Freq_Cnt => X "062E", wavegenCLK => CLK, signat (WaveOut) => WaveB5); --1582, 987,77 Hz Nota_C6: mapa de ports Wave_Generator (Trigger => O5 (12), Freq_Cnt => X "05D6", wavegenCLK => CLK, signat (WaveOut) => WaveC6); --1494, 1046,5 Hz ------------ lògica de selecció de notes ------------ C4 <= "0000" & O4 (0); Cs4 <= "0000" & O4 (1); D4 <= "0000" & O4 (2); DS4 <= "0000" i 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" i O5 (2); DS5 <= "0000" i O5 (3); E5 <= "0000" & O5 (4); F5 <= "0000" i O5 (5); Fs5 <= "0000" i O5 (6); G5 <= "0000" & O5 (7); Gs5 <= "0000" & O5 (8); A5 <= "0000" i O5 (9); As5 <= "0000" i O5 (10); B5 <= "0000" i 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; Selecció: procés (WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveG5, WaveGs5, WaveGs5, WaveB5, WaveC6) comencen si (cntC6 = "00000") llavors --------------- si no es generen senyals Wave0 <= "0000000000"; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 <= "0000000000"; else if (O4 (0) = '1') then ------------------- note C4 played 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 error3 Wave2 Wave1 Wave2 Wave3 error Wave0 Wave1 Wave2 error3 Wave2 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 error3 Error Wave0 Wave1 Wave2 Wave3 error Wave0 Wave1 Wave2 error3 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 Error Wave3 Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave2 <= "0000000000"; Wave3 Error Wave3 <= '1'; cas final; acabar si; acabar si; finalitzar el procés; ------------- Sumador d'ona sinusoïdal -------------------- WaveSum <= STD_LOGIC_VECTOR (Wave0 + Wave1 + Wave2 + Wave3); --------- Feu que l’ona sinusoïdal sigui positiva per pwm --------------------- positiva WaveSum <= no WaveSum (9) i WaveSum (8 fins a 0); ------------- Generador de PWM --------------------- procés (CLK) - recompte de variables: sense signar (1 fins a 0): = to_unsigned (0, 2); comenceu si (rising_edge (CLK)) llavors --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 si; finalitza si; finalitza el procés; finalitza Comportamental;

4 Selector de notes La part més complicada d’aquest projecte és seleccionar només quatre freqüències. Ho hem fet amb moltes sentències IF i hem utilitzat senyals en lloc de variables perquè el procés es pugui simular i depurar. Hem provat altres mètodes amb variables i bucles FOR, però hem tingut errors en temps d'execució. Per tant, al final vam decidir que, si funciona, ho deixarem en pau. No solucioneu el que no es trenca l'amirite?

Les quatre ones de sortida tenen l’etiqueta Wave0, Wave1, Wave2, Wave3: són les que s’afegiran juntes per formar la sortida final.

En mirar el codi, veureu un munt de senyals etiquetats com C4, Cs4, D4, Ds4, etc. Són senyals de 5 bits que prenen el disparador corresponent des de O4 (octava 4) o O5 (octava 5) i els fan 5 bits per afegir.

A continuació, les variables cntC4, cntCs4, etc. representen quantes notes més baixes que la nota objectiu s'han reproduït, inclosa la nota objectiu. Per exemple, si es reprodueixen C4, E4, G4, A # 4 i D5 (acord C9) cntC4 serà 1, cntE4 serà 2, cntG4 serà 3, etc.

A continuació, sempre que es toqui una nota, s'examinarà el recompte de la nota objectiu per veure fins a on connectar el senyal de la nota. Per exemple, si es toca una nota D5 (que vol dir que O5 (2) és alta) i cntD5 és 3, actualment hi ha 3 notes que es toquen, amb 2 notes més baixes que D5, de manera que connectarem l’ona D5 a l’ona Wave2 (la tercera ona de senyal de Wave0). Com a alternativa, si cntD5 és 5, actualment hi ha 5 notes que s’estan reproduint, amb 4 notes inferiors a D5, de manera que deixarem l’ona D5 penjada i no hi farem res.

A continuació, les declaracions IF es repeteixen per cobrir els casos de les 25 notes.

Sumador d'amplitud

Després de seleccionar les 4 ones més baixes, les hem de sumar. La raó per la qual només afegirem quatre notes juntes és que la idea de PWM que fem servir per a la nostra sortida només pot tenir una determinada resolució fins que el PWM funcioni massa lent i l’altaveu comenci a agafar l’ona quadrada de PWM. Per exemple, si utilitzéssim una resolució de 8192 (13 bits), cadascun d'aquests 8192 punts hauria de correspondre a una vora ascendent del rellotge incorporat. Per tant, 100 MHz / 8192 = 12,2 kHz, que està dins del rang de l’audició humana.

L’addició real d’amplituds és molt senzilla, només heu d’assegurar-vos que pugui funcionar molt ràpidament.

Sortida PWM

El cicle de treball del PWM representarà l’amplitud de la nostra ona de sortida en aquell instant. Per exemple, si tenim un rang d'amplitud de 0 a 128, 0 seria un cicle de treball del 0%, 64 seria del 50%, 128 seria del 100%, etc. Aquest PWM funcionarà extremadament ràpid (el nostre és de 97,6 kHz), tan ràpid que l'altaveu no reconeixerà les ones quadrades individuals i, en canvi, mirarà la tensió mitjana, creant el nostre senyal "analògic".

Fitxer de restriccions

És possible que hàgiu connectat el maquinari de manera diferent, així que només cal que assegureu-vos que el fitxer de restriccions coincideixi.

Pas 5: baixades de codi

A continuació es mostra el codi, tant en format.txt com en.vhd per a Vivado. Wave_Generator és el submòdul del generador d’ones i Two_Octave_Synth és el mòdul superior amb tota la resta.

Recomanat: