Inhoudsopgave:

Basys3 FPGA Digitale Audio Synthesizer - Ajarnpa
Basys3 FPGA Digitale Audio Synthesizer - Ajarnpa

Video: Basys3 FPGA Digitale Audio Synthesizer - Ajarnpa

Video: Basys3 FPGA Digitale Audio Synthesizer - Ajarnpa
Video: FPGA Nexys A7 100T - Basic Audio Synthesizer 2024, Juli-
Anonim
Image
Image
Basys3 FPGA Digitale Audio Synthesizer
Basys3 FPGA Digitale Audio Synthesizer
Basys3 FPGA Digitale Audio Synthesizer
Basys3 FPGA Digitale Audio Synthesizer

Deze digitale sinusgolf-toetsenbordsynthesizer neemt gebruikersinvoer via een reeks tijdelijke schakelaars die zijn opgesteld als een toetsenbord en voert een audiogolf uit via een luidspreker. Op basis van gebruikersinvoer genereert het apparaat sinusgolven van verschillende frequenties van C4 tot C6. De gebruiker kan noten invoeren van C4 tot C6 (25 noten in totaal), en tot vier toetsen tegelijk -- als er meer dan vier toetsen worden ingedrukt, worden de vier laagste tonen gespeeld.

Dit project is gedaan door Ryan Morris en Mavis Tsoi voor onze Cal Poly CPE 133 Digital Design-klasse:)

Stap 1: Theorie

Een FPGA-bord kan alleen digitale signalen uitvoeren. Met andere woorden, het kan alleen een hoge (3,3V) spanning of een lage (0V) spanning produceren. Audiosignalen zijn echter analoog en kunnen oneindig veel spanningsstappen hebben. Om dit te omzeilen, gebruiken we een PWM-signaal (pulsbreedtemodulatie) om een analoge golf te emuleren. Als je niet weet wat PWM is, kijk dan eens op:

Stap 2: Ingrediënten & Gereedschap

  • Computer waarop Vivado is geïnstalleerd
  • We gebruiken Vivado-versie 2017.2
  • Basys3 FPGA-bord
  • 25 SPDT-eindschakelaars (we hebben deze gebruikt)
  • 30 jumperdraden (het ene uiteinde mannelijk, het andere uiteinde maakt niet uit), 12 inch
  • Draadsnijders
  • Draadstrippers
  • Reservedraad om te solderen
  • Soldeer met harskern
  • Soldeerbout
  • ¼” vrouwelijke audio-aansluiting
  • Versterker/luidspreker
  • Iets om de schakelaars op te monteren (we gebruikten protoboard + houten kist)

Stap 3: bedrading en hardware instellen

Bedrading en hardware instellen
Bedrading en hardware instellen
Bedrading en hardware instellen
Bedrading en hardware instellen
Bedrading en hardware instellen
Bedrading en hardware instellen

Systeem Architectuur

Zie Afbeelding 1: 25 beschikbare ingangen → Basys3-kaart → versterker & luidspreker.

Uitgang:

Zie afbeelding 2: Basys3-kaart → 1/2 vrouwelijke audio-aansluiting → luidspreker (met versterker)

Invoer

De pmod-aansluitingen op het Basys3-bord moeten worden verbonden met aarde om een lage ingang te zien en zullen niet goed werken als ze als een open circuit worden gelaten. Daarom moeten we SPDT-schakelaars gebruiken voor al onze noottoetsen. Met een SPDT-schakelaar kan de gebruiker in principe schakelen tussen circuits wanneer hij wordt ingedrukt, dus we zullen ze gebruiken als onze "knoppen" om lage (0V) of hoge (3,3V) signalen naar het Basys3-bord in te voeren.

Elke schakelaar heeft de NO (normaal geopende) aansluiting aangesloten op 3,3 V, NC (normaal gesloten) aansluiting aangesloten op GND en COM (gemeenschappelijke) aansluiting aangesloten op de FPGA-ingang. Zie figuur 3.

Omdat we 25 eindschakelaars hebben, zullen ze allemaal een gemeenschappelijke 3.3V-lijn en een gemeenschappelijke GND-lijn delen. Vervolgens wordt de signaallijn van elke eindschakelaar gebundeld in groepen van 8 en aangesloten op de pmod-verbindingen op het Basys3-bord met behulp van inritsbare jumperdraden om de monumentale puinhoop die we zullen maken te minimaliseren. Zie afbeelding 4 of een voorbeeld van de eerste acht toetsen.

Stap 4: VHDL-configuratie (Vivado)

VHDL-configuratie (Vivado)
VHDL-configuratie (Vivado)
VHDL-configuratie (Vivado)
VHDL-configuratie (Vivado)

De sinusgolfgenerator en PWM-generator werden eerst getest om er zeker van te zijn dat ons concept werkte, daarna werden de ingangsbegrenzer en amplitude-opteller/shifter geïntegreerd. Details van de functie en I/O van elk procesblok zijn zoals weergegeven in de afbeelding. De code wordt hieronder weergegeven, maar is ook bijgevoegd als VHD- en txt-bestanden. Als er verschillen zijn, ga dan met de VHD-bestanden.

Tussen haakjes: we hadden onze regels waarschijnlijk korter moeten maken, maar het insluiten van code op Instructables bleek ook behoorlijk vervelend om mee om te gaan, dus de spatiëring is niet de grootste en er is geen syntaxisaccentuering. Als je Vivado hebt en de code wilt volgen, raden we je ten zeerste aan om het bestand gewoon te downloaden.

Laten we eerst eens kijken naar de Sine Wave Generator-module.

bibliotheek IEEE;gebruik IEEE. STD_LOGIC_1164. ALL; gebruik IEEE. NUMERIC_STD. ALL; entiteit Wave_Generator is Port (Trigger: in STD_LOGIC; -- Toetsdruk Freq_Cnt: in STD_LOGIC_VECTOR (15 omlaag tot 0); -- Tellerwaarde = 100 MHz / (Note Frequency*64 Divisies van sinusgolf) (afronden naar het dichtstbijzijnde getal) -- hernoemd van Freq wavegenCLK: in STD_LOGIC;-Basys3 100MHz CLK WaveOut: uit STD_LOGIC_VECTOR (9 tot 0)); -- Ondertekende amplitude van golfeinde Wave_Generator; architectuur Gedrag van Wave_Generator is signaal i: integer bereik 0 tot 64:= 0; -- index van amplitudegeheugenbanktype memory_type is array (0 tot 63) van geheeltallig bereik -64 tot 63; -- maak een geheugenbank (ROM) om amplitudewaarden vast te houden -- is dit RAM of ROM gewoon benieuwd … signaalamplitude: geheugentype: = (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); -- amplitudegeheugenbank voor sinusgolfbeginproces (wavegenCLK, Trigger) variabele teller: unsigned (15 tot 0):= to_unsigned (0, 16); -- klok deler teller, hernoemd van count1 begin if (rising_edge(wavegenCLK)) then if (Trigger = '1') then -- toets wordt ingedrukt counter:= counter + 1; if (counter = unsigned(Freq_Cnt)) then -- Freq_Cnt = 100Mhz / (note freq * 64 delen van de sinusgolf) -- reset de teller en wijs amplitudegegevens toe aan de outputteller:= to_unsigned(0, 16); WaveOut <= STD_LOGIC_VECTOR (to_signed(amplitude(i), 10)); -- verhoog i voor de volgende meting i <= i + 1; -- reset i als één sinusgolf is voltooid if(i = 63) then i <= 0; stop als; stop als; -- (teller = unsigned (Freq_Cnt)) anders -- toets is niet ingedrukt -- reset uitgang, amplitude-index en teller WaveOut <= "0000000000"; ik <= 0; teller:= to_unsigned(0, 16); --output Amplitude = -64 als er geen noot wordt gespeeld, end if; -- (Trigger = '1') einde als; -- (rising_edge(CLK)) eindproces; einde Gedrags;

We zullen een digitale sinusgolf in de Basys3 genereren met behulp van de interne klok en een ROM. Dit ROM zal 64 waarden opslaan die 64 amplitudes op een sinusgolf vertegenwoordigen. Zie figuur 1. De 64 waarden die we gebruiken, emuleren een sinusgolf met een redelijk goede resolutie.

Met behulp van de interne klok tellen we tot een waarde die de kloksnelheid vertegenwoordigt, gedeeld door de frequentie van de golf die we willen en 64: Clk div = 100MHz / (Freq * 64) Elke keer dat onze teller die waarde bereikt, bellen we een getal van de ROM en stuur die uit onze golfgeneratormodule. De frequentie van onze golf hangt af van hoe snel we deze amplituden noemen.

We zullen 25 submodules hebben, elk geassocieerd met een frequentie/noot.

Hier is de resterende code die de Sine Wave Generator-modules aanroept:

bibliotheek IEEE;gebruik IEEE. STD_LOGIC_1164. ALL; gebruik IEEE. NUMERIC_STD. ALL; entiteit Two_Octave_Synth is Port (CLK: in STD_LOGIC; O4: in STD_LOGIC_VECTOR (11 omlaag naar 0); O5: in STD_LOGIC_VECTOR (12 omlaag naar 0); uitvoer: uit STD_LOGIC); einde Two_Octave_Synth; architectuur Gedrag van Two_Octave_Synth is onderdeel Wave_Generator is Port (Trigger: in STD_LOGIC; Freq_Cnt: in STD_LOGIC_VECTOR (15 tot 0); wavegenCLK: in STD_LOGIC; WaveOut: uit STD_LOGIC_VECTOR (9 tot 0)); eindcomponent; --------------------------- uitgangssignalen van golfgenerator ------------------ ----- signaal WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveG5A5Gs5, WaveAs5, WaveB5, WaveC6: ondertekend (9 tot 0); -------------------------------- voor nootselectielogica -------------- ------ signaal 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: niet ondertekend (4 tot 0); signaal cntC4, cntCs4, cntD4, cntDs4, cntE4, cntF4, cntFs4, cntG4, cntGs4, cntA4, cntAs4, cntB4, cntC5, cntCs5, cntD5, cntDs5, cntDs5, cntE5, CntF5, cntF5, cntF5, cnt: niet ondertekend (4 tot 0); signaalfout: STD_LOGIC; ----------------------------------- voor het toevoegen van sinusgolven ----------- --------------- signaal Wave0, Wave1, Wave2, Wave3: ondertekend (9 tot 0); --signalen van het uitgangssignaal van de Wave Generator-module WaveSum: STD_LOGIC_VECTOR (9 tot 0); --signaal voor gesommeerde sinusgolven (2's compliment -512 tot 511) signaal positiveWaveSum: STD_LOGIC_VECTOR (9 tot 0); --unsigned 0 tot 1023, voor gebruik in PWM-generator ----------------------------------- voor het genereren van PWM ------------------------------- signaal ping_length: unsigned (9 downto 0):= unsigned (positiveWaveSum); --signal off_length: unsigned (6 downto 0):= to_unsigned(127, 7) - unsigned(WAVE); signaal PWM: unsigned (9 downto 0):= to_unsigned (0, 10); begin Note_C4: Wave_Generator poortkaart (Trigger => O4(0), Freq_Cnt => X"1755", wavegenCLK => CLK, ondertekend (WaveOut) => WaveC4); --5973, 261.63 Hz Note_Cs4: Wave_Generator poortkaart (Trigger => O4(1), Freq_Cnt => X"1606", wavegenCLK => CLK, ondertekend (WaveOut) => WaveCs4);--5638, 277.18 Hz Note_D4: Wave_Generator poortkaart (Trigger => O4(2), Freq_Cnt => X"14C9", wavegenCLK => CLK, ondertekend (WaveOut) => WaveD4); --5321, 293.66 Hz Note_Ds4: Wave_Generator poortkaart (Trigger => O4(3), Freq_Cnt => X"139F", wavegenCLK => CLK, ondertekend (WaveOut) => WaveDs4);--5023, 311.13 Hz Note_E4: Wave_Generator poortkaart (Trigger => O4(4), Freq_Cnt => X"1285", wavegenCLK => CLK, ondertekend (WaveOut) => WaveE4); --4741, 329,63 Hz Note_F4: Wave_Generator poortkaart (Trigger => O4(5), Freq_Cnt => X"117B", wavegenCLK => CLK, ondertekend (WaveOut) => WaveF4); --4475, 349,23 Hz Note_Fs4: Wave_Generator poortkaart (Trigger => O4(6), Freq_Cnt => X"1080", wavegenCLK => CLK, ondertekend (WaveOut) => WaveFs4);--4224, 369,99 Hz Note_G4: Wave_Generator poortkaart (Trigger => O4(7), Freq_Cnt => X"0F92", wavegenCLK => CLK, ondertekend (WaveOut) => WaveG4); --3986, 392,00 Hz Note_Gs4: Wave_Generator poortkaart (Trigger => O4(8), Freq_Cnt => X"0EB3", wavegenCLK => CLK, ondertekend (WaveOut) => WaveGs4);--3763, 415,30 Hz Note_A4: Wave_Generator poortkaart (Trigger => O4(9), Freq_Cnt => X"0DE0", wavegenCLK => CLK, ondertekend (WaveOut) => WaveA4); --3552, 440.00 Hz Note_As4: Wave_Generator poortkaart (Trigger => O4(10), Freq_Cnt => X"0D18", wavegenCLK => CLK, ondertekend (WaveOut) => WaveAs4);--3352, 466.16 Hz Note_B4: Wave_Generator poortkaart (Trigger => O4(11), Freq_Cnt => X"0C5C", wavegenCLK => CLK, ondertekend (WaveOut) => WaveB4); ----3164, 493,88 Hz -------------------------------------------- -------------------------------------------------- --------------------------- Note_C5: Wave_Generator poortkaart (Trigger => O5(0), Freq_Cnt => X"0BAB", wavegenCLK => CLK, ondertekend (WaveOut) => WaveC5); --2987, 523,25 Hz Note_Cs5: Wave_Generator poortkaart (Trigger => O5(1), Freq_Cnt => X"0B03", wavegenCLK => CLK, ondertekend (WaveOut) => WaveCs5);--2819, 554,37 Hz Note_D5: Wave_Generator poortkaart (Trigger => O5(2), Freq_Cnt => X"0A65", wavegenCLK => CLK, ondertekend (WaveOut) => WaveD5); --2661, 587.33 Hz Note_Ds5: Wave_Generator poortkaart (Trigger => O5(3), Freq_Cnt => X"09D0", wavegenCLK => CLK, ondertekend (WaveOut) => WaveDs5);--2512, 622.25 Hz Note_E5: Wave_Generator poortkaart (Trigger => O5(4), Freq_Cnt => X"0943", wavegenCLK => CLK, ondertekend (WaveOut) => WaveE5); --2371, 659.25 Hz Note_F5: Wave_Generator poortkaart (Trigger => O5(5), Freq_Cnt => X"08Be", wavegenCLK => CLK, ondertekend (WaveOut) => WaveF5); --2238, 698,46 Hz Note_Fs5: Wave_Generator poortkaart (Trigger => O5(6), Freq_Cnt => X"0840", wavegenCLK => CLK, ondertekend (WaveOut) => WaveFs5);--2112, 739,99 Hz Note_G5: Wave_Generator poortkaart (Trigger => O5(7), Freq_Cnt => X"07CA", wavegenCLK => CLK, ondertekend (WaveOut) => WaveG5); --1994, 783,99 Hz Note_Gs5: Wave_Generator poortkaart (Trigger => O5(8), Freq_Cnt => X"075A", wavegenCLK => CLK, ondertekend (WaveOut) => WaveGs5);--1882, 830,61 Hz Note_A5: Wave_Generator poortkaart (Trigger => O5(9), Freq_Cnt => X"06F0", wavegenCLK => CLK, ondertekend (WaveOut) => WaveA5); --1776, 880.00 Hz Note_As5: Wave_Generator poortkaart (Trigger => O5(10), Freq_Cnt => X"068C", wavegenCLK => CLK, ondertekend (WaveOut) => WaveAs5);--1676, 932.33 Hz Note_B5: Wave_Generator poortkaart (Trigger => O5(11), Freq_Cnt => X"062E", wavegenCLK => CLK, ondertekend (WaveOut) => WaveB5); --1582, 987.77 Hz Note_C6: Wave_Generator poortkaart (Trigger => O5(12), Freq_Cnt => X"05D6", wavegenCLK => CLK, ondertekend (WaveOut) => WaveC6); ----1494, 1046.5 Hz ------------ nootselectielogica------------ 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; Selectie: proces (WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveG5A5Gs5, WaveG5A5Gs5, WaveB5, WaveC6) beginnen als (cntC6 = "00000") dan --------------- als er geen signalen worden gegenereerd Wave0 <= "0000000000"; Golf1 <= "0000000000"; Golf2 <= "0000000000"; Golf3 <= "0000000000"; else if (O4(0) = '1') then ------------------- noot C4 gespeeld Wave0 Wave0 Wave1 fout Wave0 Wave1 Wave2 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 Wave1 Wave2 Wave3 fout Wave0 < = GolfC6; Golf1 <= "0000000000"; Golf2 <= "0000000000"; Golf3 Golf1 <= GolfC6; Golf2 <= "0000000000"; Golf3 Golf2 <= GolfC6; Wave3 Wave3-fout Wave1 <= "000000000000"; Golf2 <= "0000000000"; Golf3 Golf2 <= "000000000000"; Wave3 Wave3-fout <= '1'; eindgeval; stop als; stop als; eindproces; ------------- sinusgolf-opteller -------------------- WaveSum <= STD_LOGIC_VECTOR (Wave0 + Wave1 + Wave2 + Wave3); --------- maak sinus positief voor pwm --------------------- positiveWaveSum <= niet WaveSum (9) & WaveSum (8 tot 0); ------------- PWM-generator --------------------- proces (CLK) --variabele telling: niet-ondertekend (1 tot 0):= to_unsigned(0, 2); begin if (rising_edge(CLK)) then --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 als; einde als; einde proces; einde Gedragsmatige;

4 Note SelectorHet lastigste onderdeel van dit project is het selecteren van slechts vier frequenties. We deden het met een heleboel IF-statements en we gebruikten signalen in plaats van variabelen, zodat het proces kan worden gesimuleerd en debuggen. We hebben andere methoden geprobeerd met behulp van variabelen en FOR-lussen, maar liepen tegen runtime-fouten aan. Dus uiteindelijk hebben we besloten dat als het werkt, we het met rust laten. Repareer niet wat niet kapot is amirite?

De vier uitvoergolven zijn gelabeld Wave0, Wave1, Wave2, Wave3 - deze worden bij elkaar opgeteld om de uiteindelijke uitvoer te vormen.

Als je naar de code kijkt, zie je een aantal signalen met het label C4, Cs4, D4, Ds4, enz. Dit zijn 5-bits signalen die de overeenkomstige trigger van O4 (octaaf 4) of O5 (octaaf 5) nemen en ze maken 5-bit om toe te voegen.

Vervolgens geven de variabelen cntC4, cntCs4, enz. aan hoeveel noten lager dan de doelnoot zijn gespeeld, inclusief de doelnoot. Als bijvoorbeeld C4, E4, G4, A#4 en D5 worden gespeeld (C9-akkoord), is cntC4 1, cntE4 is 2, cntG4 is 3, enz.

Telkens wanneer een noot wordt gespeeld, wordt de telling voor de doelnoot onderzocht om te zien waar het nootsignaal moet worden aangesloten. Als bijvoorbeeld de D5-noot wordt gespeeld (wat betekent dat O5(2) hoog is) en cntD5 is 3, dan worden er momenteel 3 noten gespeeld, met 2 noten lager dan D5, dus we zullen waveD5 aan Wave2 vasthaken (de derde golf signaal geteld vanaf Wave0). Als alternatief, als cntD5 5 is, worden er momenteel 5 noten gespeeld, met 4 noten lager dan D5, dus we laten waveD5 gewoon hangen en doen er niets mee.

De IF-verklaringen worden vervolgens herhaald om de gevallen voor alle 25 biljetten te dekken.

Amplitude-opteller

Nadat de laagste 4 golven zijn geselecteerd, moeten we ze bij elkaar optellen. De reden dat we slechts vier noten bij elkaar zullen voegen, is omdat het PWM-idee dat we gebruiken voor onze uitvoer slechts een bepaalde resolutie kan hebben totdat de PWM te langzaam loopt en de luidspreker de PWM-blokgolf begint op te pikken. Als we bijvoorbeeld een resolutie van 8192 (13 bit) zouden gebruiken, moet elk van die 8192 punten overeenkomen met een stijgende flank van de ingebouwde klok. Dus 100 MHz / 8192 = 12,2 kHz, wat ruim binnen het bereik van het menselijk gehoor ligt.

Het daadwerkelijk toevoegen van de amplitudes is supereenvoudig, je moet er alleen voor zorgen dat het heel snel kan werken.

PWM-uitgang

De duty cycle van de PWM vertegenwoordigt de amplitude van onze uitgangsgolf op dat moment. Als we bijvoorbeeld een amplitudebereik van 0 tot 128 hebben, zou 0 een duty cycle van 0% zijn, 64 zou 50% zijn, 128 zou 100% zijn, enz. Deze PWM zal extreem snel werken (de onze is 97,6 kHz), zo snel dat de spreker de individuele blokgolven niet herkent en in plaats daarvan naar de gemiddelde spanning kijkt, waardoor ons "analoge" signaal ontstaat.

Beperkingen Bestand

Mogelijk hebt u uw hardware anders aangesloten, dus zorg ervoor dat het bestand met beperkingen overeenkomt.

Stap 5: Codedownloads

Hieronder staat de code, zowel in.txt-formaat als in.vhd voor Vivado. Wave_Generator is de submodule van de golfgenerator en Two_Octave_Synth is de bovenste module met al het andere.

Aanbevolen: