Innehållsförteckning:

Laser Harp Synthesizer på Zybo Board: 10 steg (med bilder)
Laser Harp Synthesizer på Zybo Board: 10 steg (med bilder)

Video: Laser Harp Synthesizer på Zybo Board: 10 steg (med bilder)

Video: Laser Harp Synthesizer på Zybo Board: 10 steg (med bilder)
Video: Crokett's Theme / Harp Laser Performance by Arkonis 2024, Juli
Anonim
Laser Harp Synthesizer på Zybo Board
Laser Harp Synthesizer på Zybo Board

I denna handledning kommer vi att skapa en fullt fungerande laserharpa med IR -sensorer med ett seriellt gränssnitt som gör att användaren kan ändra inställning och ton för instrumentet. Denna harpa kommer att vara en nyinspelning av det gamla instrumentet från 2000 -talet. Systemet skapades med hjälp av ett Xilinx Zybo -utvecklingsbord tillsammans med Vivado Design Suites. Vad du behöver för att slutföra projektet:

  • 12 IR -sensorer och sändare (mer eller mindre kan användas beroende på antalet strängar)
  • Zybo Zynq-7000 utvecklingskort
  • Gratis RTOS
  • Vivado Design Suite
  • Tråd (för anslutning av sensorerna till kortet)
  • 3 stycken PVC -rör ((2) 18 tum och (1) 8 tum)
  • 2 PVC -armbågar

Steg 1: Skaffa Digilents Zybo DMA Audio Demo

FPGA -sidan av detta projekt är till stor del baserad på demoprojektet som finns här. Den använder direkt minnesåtkomst för att skicka data direkt från minne som processorn kan skriva till över AXI Stream till ett I2S -ljudblock. Följande steg hjälper dig att få igång DMA -ljuddemoprojektet:

  1. En ny version av kortfilen för Zybo -kortet kan vara nödvändig. Följ dessa instruktioner för att skaffa nya kortfiler för Vivado.
  2. Följ steg 1 och 2 i instruktionerna på den här sidan för att öppna demoprojektet i Vivado. Använd Vivado -metoden, inte SDK -maskinvaruöverlämningen.
  3. Du kan få ett meddelande som säger att några av dina ip -block bör uppdateras. Om så är fallet, välj "Visa IP -status" och välj sedan all föråldrad IP -adress på fliken IP -status och klicka på "Uppgradera markerat". När den är klar och ett fönster dyker upp som frågar om du vill generera utdataprodukter, fortsätt och klicka på "Generera". Om du får ett kritiskt varningsmeddelande, ignorera det.
  4. Byt från designen till fliken källor i Vivado för att se källfilerna. Högerklicka på blockdesignen "design_1" och välj "Create HDL Wrapper". När du blir ombedd väljer du "kopiera genererad omslag för att tillåta användarredigeringar". En omslagsfil för projektet kommer att genereras.
  5. Nu när de kritiska stegen som på något sätt utelämnades i den andra handledningen är slutförda kan du återgå till självstudien som tidigare länkats och fortsätta från steg 4 till slutet och se till att demoprojektet fungerar korrekt. Om du inte har något sätt att mata in ljud för att det ska spela in är det bara att spela in med dina hörlurar och lyssna på ett 5-10 sekunders fuzzy ljud när du trycker på uppspelningsknappen. Så länge något kommer ut ur hörlursuttaget när du trycker på uppspelningsknappen fungerar det förmodligen korrekt.

Steg 2: Gör några ändringar i Vivado

Gör några ändringar i Vivado
Gör några ändringar i Vivado

Så nu har du Digilents DMA -ljuddemo som fungerar, men det är inte alls slutmålet här. Så vi måste gå tillbaka till Vivado och göra några ändringar så att våra sensorer kan anslutas till PMOD -rubrikerna och vi kan använda deras värde på programvarusidan.

  1. Öppna blockdiagrammet i Vivado
  2. Skapa ett GPIO-block genom att högerklicka i det tomma utrymmet i blockschemat och välja "Lägg till IP" från menyn. Hitta och välj "AXI GPIO".
  3. Dubbelklicka på det nya IP-blocket och i fönstret för anpassning av IP går du till fliken IP-konfiguration. Välj alla ingångar och ställ in bredden till tolv, eftersom vi kommer att ha 12 "strängar" på vår harpa och därför behöver 12 sensorer. Om du vill använda färre eller fler sensorer justerar du detta nummer på lämpligt sätt. Ställ också in aktiveringsavbrott.
  4. Högerklicka på det nya GPIO IP -blocket och välj "Kör anslutningsautomatisering". Markera AXI -rutan och tryck OK. Detta bör ansluta AXI -gränssnittet automatiskt, men lämna blockets utgångar oanslutna.
  5. För att få plats med det extra avbrottet, dubbelklicka på xlconcat_0 IP -blocket och ändra antalet portar från 4 till 5. Sedan kan du ansluta ip2intc_irpt -stiftet från det nya GPIO -blocket till den nya oanvända porten på xlconcat -blocket.
  6. Högerklicka på "GPIO" -utgången i det nya GPIO -IP -blocket och välj "gör extern". Hitta vart linjen går och klicka på den lilla sidledes femkant och till vänster ska ett fönster öppnas där du kan ändra namnet. Ändra namnet till "SENSORER". Det är viktigt att använda samma namn om du vill att begränsningsfilen vi tillhandahåller ska fungera, annars måste du ändra namnet i begränsningsfilen.
  7. Tillbaka på fliken källor, hitta begränsningsfilen och ersätt den med den vi tillhandahåller. Du kan välja att antingen ersätta filen eller bara kopiera innehållet i vår begränsningsfil och klistra in den över innehållet i den gamla. En av de viktiga sakerna som vår begränsningsfil gör är att aktivera pullup -motstånden på PMOD -rubrikerna. Detta är nödvändigt för de specifika sensorer vi använde, men inte alla sensorer är desamma. Om dina sensorer kräver nedrullningsmotstånd kan du ändra varje instans av "set_property PULLUP true" med "set_property PULLDOWN true". Om de kräver ett annat motståndsvärde än det på kortet, kan du ta bort dessa rader och använda externa motstånd. Stiftnamnen finns i kommentarerna i begränsningsfilen och de motsvarar etiketterna i första diagrammet i Zybo -schematiken sida som finns här. Om du vill använda olika pmod -stift matchar du bara namnen i begränsningsfilen med etiketterna i schematisk. Vi använder PMOD -rubriken JE och JD och använder sex datastiften på varje, utelämnar stift 1 och 7. Denna information är viktig när du ansluter dina sensorer. Som visas i schemat är stift 6 och 12 på PMODS VCC och stift 5 och 11 är slipade.
  8. Återskapa HDL -omslaget som tidigare och kopiera och skriv över det gamla. När det är klart, generera bitström och exportera hårdvara som tidigare och starta om SDK: n. Om du får frågan om du vill ersätta den gamla maskinvarufilen är svaret ja. Det är förmodligen bäst att ha SDK stängt när du exporterar hårdvara så att den ersätts ordentligt.
  9. Starta SDK.

Steg 3: Få FreeRTOS -körning

Nästa steg är att få FreeRTOS att köra på Zybo -kortet.

  1. Om du inte redan har en kopia, ladda ner FreeRTOS här och extrahera filerna.
  2. Importera FreeRTOS Zynq -demon som finns på FreeRTOSv9.0.0 / FreeRTOS / Demo / CORTEX_A9_Zynq_ZC702 / RTOSDemo. Importprocessen är i stort sett densamma som för det andra demoprojektet, men eftersom FreeRTOS Zynq -demoen bygger på andra filer i FreeRTOS -mappen bör du inte kopiera filerna till din arbetsyta. Istället bör du placera hela FreeRTOS -mappen i din projektmapp.
  3. Skapa ett nytt styrelsepaket genom att gå till "fil" -> "nytt" -> "styrelsepaket". Se till att fristående är valt och klicka på Slutför. Efter ett ögonblick kommer ett fönster att dyka upp, markera rutan bredvid lwip141 (detta hindrar en av FreeRTOS -demos från att misslyckas med att kompilera) och tryck OK. När det är klart högerklickar du på RTOSdemo -projektet och går till "egenskaper", går till "projektreferenser" -fliken och markerar rutan bredvid den nya bsp du skapade. Förhoppningsvis kommer det att erkännas men ibland kan Xilinx SDK vara konstigt med den här typen av saker. Om du fortfarande får ett fel efter det här steget som xparameters.h saknas eller något liknande, försök upprepa detta steg och kanske avsluta och starta om SDK: n.

Steg 4: Lägg till laserharpkod

Nu när FreeRTOS har importerats kan du ta med filerna från laserharpprojektet till FreeRTOS -demon

  1. Skapa en ny mapp under mappen src i FreeRTOS -demon och kopiera och klistra in alla medföljande c -filer förutom main.c i den här mappen.
  2. Byt ut RTOSDemo main.c mot det medföljande main.c.
  3. Om allt görs korrekt bör du kunna köra laserharpkoden vid denna tidpunkt. För teständamål används knappinmatningen som användes i DMA -demoprojektet nu för att spela ljud utan sensorer anslutna (någon av de fyra huvudknapparna fungerar). Den kommer att spela en sträng varje gång du trycker på den och går igenom alla strängar i systemet över flera tryckningar. Anslut några hörlurar eller högtalare till hörlursuttaget på Zybo -kortet och se till att du kan höra ljudet från strängarna som kommer igenom när du trycker på en knapp.

Steg 5: Om koden

Många av er som läser denna handledning lär troligtvis lära sig att ställa in ljud eller använda DMA för att göra något annorlunda eller skapa ett annat musikinstrument. Av den anledningen ägnar de närmaste avsnitten åt att beskriva hur den tillhandahållna koden fungerar tillsammans med hårdvaran som tidigare beskrivits för att få en fungerande ljudutgång med DMA. Om du förstår varför kodbitarna finns så bör du kunna justera dem för vad du än vill skapa.

Avbryter

Först ska jag nämna hur avbrott skapas i detta projekt. Sättet vi gjorde det var genom att först skapa en avbrottsvektortabellstruktur som håller reda på ID, avbrottshanterare och en referens till enheten för varje avbrott. Avbrotts -ID: n kommer från xparameters.h. Avbrottshanteraren är en funktion som vi skrev för DMA och GPIO, och I2C -avbrottet kommer från Xlic I2C -drivrutinen. Enhetsreferensen pekar på instanser av varje enhet som vi initierar någon annanstans. Nära slutet av _init_audio -funktionen går en slinga genom varje objekt i avbrottsvektortabellen och anropar två funktioner, XScuGic_Connect () och XScuGic_Enable () för att ansluta och aktivera avbrotten. De refererar till xInterruptController, som är en avbrottsstyrenhet som skapats i FreeRTOS main.c som standard. Så i princip kopplar vi alla våra avbrott till denna avbrottskontroller som redan skapades för oss av FreeRTOS.

DMA

DMA -initialiseringskoden börjar på lh_main.c. Först deklareras en statisk instans av en XAxiDma -struktur. Sedan i funktionen _init_audio () konfigureras den. Först kallas konfigurationsfunktionen från demoprojektet, som är i dma.c. Det är ganska väl dokumenterat och kommer direkt från demoen. Sedan blir avbrottet anslutet och aktiverat. För detta projekt krävs endast master-to-slave-avbrott, eftersom all data skickas av DMA till I2S-styrenheten. Om du vill spela in ljud behöver du också slav-till-master-avbrottet. Master-to-slave-avbrottet blir uppringt när DMA har skickat ut all data du sa till den att skicka. Detta avbrott är otroligt viktigt för vårt projekt eftersom varje gång DMA -enheten skickar ut en buffert med ljudprover måste den genast börja skicka ut nästa buffert, annars skulle en hörbar fördröjning inträffa mellan sändningarna. Inuti funktionen dma_mm2s_ISR () kan du se hur vi hanterar avbrottet. Den viktiga delen är nära slutet där vi använder xSemaphoreGiveFromISR () och portYIELD_FROM_ISR () för att meddela _audio_task () att den kan initiera nästa DMA -överföring. Vi skickar konstant ljuddata genom att växla mellan två buffertar. När en buffert överförs till I2C -blocket har den andra bufferten sina värden beräknade och lagrade. När avbrottet kommer från DMA växlar den aktiva bufferten och den nyligen skrivna bufferten börjar överföras medan den tidigare överförda bufferten börjar skrivas över med nya data. Den viktigaste delen av funktionen _audio_task är där fnAudioPlay () blir anropad. fnAudioPlay () tar in DMA -instansen, buffertens längd och en pekare till bufferten från vilken data kommer att överföras. Några värden skickas till I2S -register för att meddela att fler prover kommer. Då blir XAxiDma_SimpleTransfer () uppmanad att initiera överföringen.

I2S ljud

audio.c och audio.h är där I2S -initialiseringen sker. I2S -initialiseringskod är en ganska vanlig bit kod som flyter runt på ett antal ställen, du kan hitta små variationer från andra källor men den här borde fungera. Det är ganska väl dokumenterat och behöver inte ändras mycket för harpeprojektet. Den DMA -ljuddemo som den kom från har funktioner för att växla till mikrofonen eller linjeingångarna så att du kan använda dem om du behöver den funktionen.

Ljudsyntes

För att beskriva hur ljudsyntesen fungerar, kommer jag att lista alla ljudmodeller som används i utvecklingen som ledde till den slutliga metoden, eftersom det kommer att ge dig en känsla av varför det görs på det sätt som det görs.

Metod 1: En period av sinusvärden beräknas för varje sträng med motsvarande frekvens för den strängens musiknot och lagras i en array. Till exempel kommer matrisens längd att vara perioden för sinusvåg i prover, vilket är lika med antal prover / cykel. Om samplingshastigheten är 48 kHz och notfrekvensen är 100 Hz, så finns det 48 000 samplingar/sekund och 100 cykler/sekund som leder till 4800 samplingar per cykel, och matrislängden kommer att vara 4800 sampel och innehåller värdena för en komplett sinusvågsperiod. När strängen spelas fylls ljudprovbufferten genom att ta ett värde från sinusvågsuppsättningen och sätta in det i ljudbufferten som ett sampel, sedan öka indexet i sinusvågsuppsättningen så att vi använder vårt tidigare exempel under kursen av 4800 sampel sätts en sinusvågscykel in i ljudbufferten. En modulooperation används på arrayindexet så att det alltid faller mellan 0 och längden, och när arrayindexet går över ett visst tröskelvärde (som exempelvis värden på 2 sekunder) stängs strängen av. För att spela flera strängar samtidigt, håll koll på varje strängars arrayindex separat och lägg till värdet från varje stränges sinusvåg tillsammans för att få varje sampel.

Metod 2: För att skapa en mer musikalisk ton börjar vi med den tidigare modellen och lägger till övertoner till varje grundfrekvens. Harmoniska frekvenser är frekvenser som är heltalsmultiplar av grundfrekvensen. Till skillnad från när två orelaterade frekvenser summeras tillsammans, vilket resulterar i att två distinkta ljud spelas samtidigt, när övertoner läggs ihop fortsätter det att låta som bara ett ljud, men med en annan ton. För att uppnå detta lägger vi till (2 * array index % array längd) och (3 * array index % array längd) för att uppnå detta), och så vidare för hur många övertoner som önskas. Dessa multiplicerade index kommer att korsa sinusvågen vid frekvenser som är heltalsmultiplar av den ursprungliga frekvensen. För att möjliggöra mer kontroll av tonen multipliceras varje övertons värden med en variabel som representerar mängden av den övertonen i det övergripande ljudet. Till exempel kan den grundläggande sinusvågan ha sina värden alla multiplicerade med 6 för att göra den mer av en faktor i det övergripande ljudet, medan den femte övertonen kan ha en multiplikator på 1, vilket betyder att dess värden bidrar mycket mindre till det övergripande ljudet.

Metod 3: Okej, så nu har vi en mycket fin ton på noterna, men det finns fortfarande ett ganska avgörande problem: de spelar med en fast volym under en bestämd längd. För att överhuvudtaget låta som ett riktigt instrument bör volymen på en sträng som spelas sönderfalla smidigt med tiden. För att åstadkomma detta fylls en array med värdena för en exponentiellt förfallande funktion. När ljudproverna skapas beräknas ljudet från varje sträng som i föregående metod, men innan det läggs till ljudprovet multipliceras det med värdet vid strängarnas arrayindex i den exponentiella sönderfallsfunktionsmatrisen. Detta gör att ljudet smidigt försvinner över tiden. När matrisindex når slutet av förfallna array stoppas strängen.

Metod 4: Det sista steget är det som verkligen ger strängljuden deras realistiska strängljud. Innan de lät trevliga men klart syntetiserade. För att försöka bättre efterlikna en harpsträng från den verkliga världen tilldelas varje överton en annan sönderfallshastighet. I riktiga strängar, när strängen först slås, finns det ett högt innehåll av högfrekventa övertoner som skapar den typ av plockljud som vi förväntar oss av en sträng. Dessa högfrekventa övertoner är mycket kortfattat huvuddelen av ljudet, ljudet av strängen som träffas, men de förfaller mycket snabbt när de långsammare övertonerna tar över. En sönderfallsmatris skapas för varje harmoniskt tal som används vid ljudsyntes, var och en med sin egen sönderfallshastighet. Nu kan varje överton oberoende multipliceras med värdet dess motsvarande förfallna matris vid strängens matrisindex och läggas till ljudet.

Sammantaget är ljudsyntesen intuitiv men beräkningstung. Att lagra hela strängljudet i minnet på en gång skulle ta för mycket minne, men att beräkna sinusvågan och den exponentiella funktionen mellan varje bildruta skulle ta alldeles för lång tid för att hålla jämna steg med ljuduppspelningen. Ett antal knep används i koden för att påskynda beräkningen. All matematik utom vid den första skapandet av sinus- och exponentiella sönderfallstabeller görs i heltalsformat, vilket kräver att det tillgängliga numeriska utrymmet sprids ut i 24 -bitars ljudutmatning. Till exempel är sinustabellen med amplitud 150 så att den är jämn men inte så stor att många strängar som spelas ihop kan lägga till att vara över 24 bitar. På samma sätt multipliceras de exponentiella tabellvärdena med 80 innan de avrundas till heltal och lagras. De harmoniska vikterna kan anta diskreta värden mellan 0 och 10. Alla prover fördubblas faktiskt och sinusvågorna indexeras med 2: or, vilket effektivt halverar samplingshastigheten. Detta begränsar den maximala frekvensen som kan spelas, men var nödvändig för att det nuvarande antalet strängar och övertoner skulle beräknas tillräckligt snabbt.

Att skapa den här ljudmodellen och få den att fungera krävde stora ansträngningar på processorsidan, och det hade varit otroligt svårt att få den att fungera på fpga -sidan från grunden i tidsramen för detta projekt (tänk att du måste återskapa bitströmmen varje gång gång en bit verilog ändrades för att testa ljudet). Men att göra det på fpga kan troligen vara ett bättre sätt att göra det, eventuellt eliminera problemet med att inte kunna beräkna samplingar tillräckligt snabbt och möjliggöra att fler strängar, övertoner och till och med ljudeffekter eller andra uppgifter körs på processorsidan.

Steg 6: Anslut sensorerna

Anslutning av sensorerna
Anslutning av sensorerna

För att skapa strängarna använde vi IR -brytstrålesensorer som detekterar när strängen spelas. Vi beställde våra sensorer från följande länk. Sensorerna har en ström-, jord- och datakabel medan sändarna bara har en ström- och jordledning. Vi använde 3,3 V och jordstift från PMOD -huvuden för att driva både sändare och sensorer. För att driva alla sensorer och sändare är det nödvändigt att ansluta alla sensorer och sändare parallellt. Datatrådarna från sensorerna kommer var och en att behöva gå till sin egen PMOD -stift.

Steg 7: Konstruera skelettet

Konstruera skelettet
Konstruera skelettet

För att skapa harpans form används de tre bitarna som ett skelett för att placera sensorerna och sändarna på. På en av de två 18 -tums bitarna av PVC -rör riktar du in sensorerna och sändarna i alternerande ordning 1,5 tum från varandra och tejpar dem sedan ner till röret. På det andra 18 -tums PVC -röret rikta in sensorerna och sändarna i alternerande ordning, men se till att kompensera ordern (dvs. om det första röret hade en sensor först skulle det andra ha en sändare först och vice versa). Det kommer att vara nödvändigt att lödda längre trådar på data-, kraft- och jordledningar för att säkerställa att de kommer att kunna nå kortet.

Steg 8: Bygga trä exteriör

Bygga trä exteriör
Bygga trä exteriör

Detta steg är valfritt men det rekommenderas starkt. Trä exteriören får inte bara harpan att se snygg ut, den skyddar också sensorerna och ledningarna från skador. Träramen kan skapas av en rektangulär ring av trä. Rektangelns insida måste ha en öppning på minst 1-1/2 tum för att passa röret och sensorns skelett. När ramen är konstruerad borra två hål som gör att ledningarna från sensorn och sändarna kan släppas ut för att ansluta dem till kortet.

*Obs! Det rekommenderas att du lägger till åtkomstpunkter för att kunna ta bort och sätta in rörskelettet om reparationer behöver göras eller små justeringar måste göras.

Steg 9: Att sätta ihop alla bitar

Att sätta ihop alla bitar
Att sätta ihop alla bitar

När alla föregående steg är klara är det dags att konstruera harpan. Placera först rörskelettet inuti träets yttre. Anslut sedan kablarna för sensorerna och sändarna till rätt plats på kortet. Öppna sedan SDK: n och klicka på felsökningsknappen för att programmera kortet. När kortet är programmerat ansluter du ett par hörlurar eller en högtalare. Beroende på vilken sensor som hamnar i vilken pmod -port kommer din harpas strängar förmodligen att vara ur funktion till att börja med. Eftersom det kan vara svårt att avgöra vilken kabel som går till vilken sensor när så många ledningar är inblandade, inkluderade vi ett sätt att kartlägga strängnummer för att avbryta bitpositioner i programvara. Hitta "static int sensor_map [NUM_STRINGS]" och justera värdena i arrayen tills strängarna spelar från lägsta till högsta i ordning.

Menyn kan användas genom att öppna en seriell terminal (t.ex. RealTerm) och ställa in överföringshastigheten till 115200 och displayen till ANSI. Menyn kan navigeras med hjälp av knapparna w och s för att flytta upp och ner och a och d för att ändra värdena.

Steg 10: ROCK OUT

När harpan är fullt fungerande. Behärska harpan och lyssna på det söta ljudet av din egen musik!

Rekommenderad: