Πίνακας περιεχομένων:

Basys3 FPGA Digital Audio Synthesizer: 5 Βήματα
Basys3 FPGA Digital Audio Synthesizer: 5 Βήματα

Βίντεο: Basys3 FPGA Digital Audio Synthesizer: 5 Βήματα

Βίντεο: Basys3 FPGA Digital Audio Synthesizer: 5 Βήματα
Βίντεο: Digital Audio Delay on an FPGA. 2024, Ιούλιος
Anonim
Image
Image
Basys3 FPGA Digital Audio Synthesizer
Basys3 FPGA Digital Audio Synthesizer
Basys3 FPGA Digital Audio Synthesizer
Basys3 FPGA Digital Audio Synthesizer

Αυτός ο ψηφιακός συνθέτης πληκτρολογίου ημιτονοειδούς κύματος θα λάβει τις εισόδους των χρηστών μέσω μιας σειράς στιγμιαίων διακοπτών που έχουν σχεδιαστεί σαν πληκτρολόγιο και θα εξάγει ένα ηχητικό κύμα μέσω ενός ηχείου. Με βάση τις εισόδους του χρήστη, η συσκευή θα παράγει ημιτονοειδή κύματα διαφόρων συχνοτήτων από C4 έως C6. Ο χρήστης μπορεί να εισάγει σημειώσεις από C4 έως C6 (συνολικά 25 σημειώσεις) και έως τέσσερα πλήκτρα ταυτόχρονα - αν πατηθούν περισσότερα από τέσσερα πλήκτρα, θα αναπαράγονται οι τέσσερις χαμηλότεροι τόνοι.

Αυτό το έργο έγινε από τους Ryan Morris και Mavis Tsoi για την τάξη ψηφιακού σχεδιασμού Cal Poly CPE 133:)

Βήμα 1: Θεωρία

Ένας πίνακας FPGA μπορεί να εξάγει μόνο ψηφιακά σήματα. Με άλλα λόγια, μπορεί να παράγει μόνο υψηλή (3,3V) ή χαμηλή (0V) τάση. Ωστόσο, τα ηχητικά σήματα είναι αναλογικά και μπορούν να έχουν απείρως πολλές αυξήσεις τάσης. Για να το ξεπεράσουμε, θα χρησιμοποιήσουμε ένα σήμα PWM (διαμόρφωση πλάτους παλμού) για να μιμηθούμε ένα αναλογικό κύμα. Εάν δεν γνωρίζετε τι είναι το PWM, ελέγξτε το:

Βήμα 2: Συστατικά & Εργαλεία

  • Υπολογιστής με εγκατεστημένο το Vivado
  • Θα χρησιμοποιήσουμε την έκδοση Vivado 2017.2
  • Basys3 FPGA Board
  • 25 SPDT Limit Switches (τα χρησιμοποιήσαμε)
  • 30 καλώδια άλματος (το ένα άκρο αρσενικό, το άλλο άκρο δεν έχει σημασία), 12 ιντσών
  • Συρματοκόπτης
  • Απογυμνωτές καλωδίων
  • Ανταλλακτικό σύρμα για συγκόλληση
  • Συγκολλητικό με ρητίνη-πυρήνα
  • Συγκολλητικό σίδερο
  • Female”θηλυκή υποδοχή ήχου
  • Ενισχυτής/ηχείο
  • Κάτι για να τοποθετήσετε τους διακόπτες (χρησιμοποιήσαμε protoboard + ξύλινο κουτί)

Βήμα 3: Ρύθμιση καλωδίωσης και υλικού

Καλωδίωση & Ρύθμιση υλικού
Καλωδίωση & Ρύθμιση υλικού
Καλωδίωση & Ρύθμιση υλικού
Καλωδίωση & Ρύθμιση υλικού
Καλωδίωση & Ρύθμιση υλικού
Καλωδίωση & Ρύθμιση υλικού

Αρχιτεκτονική του συστήματος

Δείτε Σχήμα 1: 25 διαθέσιμες είσοδοι → Basys3 Board → ενισχυτής & ηχείο.

Παραγωγή

Δείτε Σχήμα 2: Basys3 Board → 1/2 Θήλυ Audio Jack → Ηχείο (με ενισχυτή)

Εισαγωγή

Οι συνδέσεις pmod στην πλακέτα Basys3 πρέπει να είναι συνδεδεμένες στη γείωση για να βλέπουν χαμηλή είσοδο και δεν θα λειτουργούν σωστά εάν παραμείνουν ως ανοιχτό κύκλωμα. Εξαιτίας αυτού, πρέπει να χρησιμοποιήσουμε διακόπτες SPDT για όλα τα κλειδιά σημείωσής μας. Ένας διακόπτης SPDT επιτρέπει βασικά στο χρήστη να αλλάζει μεταξύ κυκλωμάτων όταν πιέζεται, οπότε θα τα χρησιμοποιήσουμε ως «κουμπιά» για την εισαγωγή σημάτων χαμηλού (0V) ή υψηλού (3.3V) στον πίνακα Basys3.

Κάθε διακόπτης θα έχει το τερματικό ΝΟ (κανονικά ανοιχτό) συνδεδεμένο σε 3,3V, τερματικό NC (κανονικά κλειστό) συνδεδεμένο στο GND και τερματικό COM (κοινό) συνδεδεμένο στην είσοδο FPGA. Δείτε το σχήμα 3.

Επειδή έχουμε 25 οριακούς διακόπτες, όλοι θα μοιράζονται μια κοινή γραμμή 3,3V και μια κοινή γραμμή GND. Στη συνέχεια, η γραμμή σήματος από κάθε οριακό διακόπτη θα ομαδοποιηθεί σε ομάδες των 8 ατόμων και θα συνδεθεί με τις συνδέσεις pmod στον πίνακα Basys3 χρησιμοποιώντας καλώδια με φερμουάρ για να ελαχιστοποιήσει το μνημειώδες χάος που θα κάνουμε. Δείτε το σχήμα 4 ή ένα παράδειγμα των πρώτων οκτώ πλήκτρων.

Βήμα 4: Ρύθμιση VHDL (Vivado)

Ρύθμιση VHDL (Vivado)
Ρύθμιση VHDL (Vivado)
Ρύθμιση VHDL (Vivado)
Ρύθμιση VHDL (Vivado)

Η γεννήτρια ημιτόνου και η γεννήτρια PWM δοκιμάστηκαν πρώτα για να βεβαιωθούν ότι η ιδέα μας λειτούργησε, στη συνέχεια ενσωματώθηκαν ο περιοριστής εισόδου και ο αθροιστής/μετατροπέας πλάτους. Λεπτομέρειες της συνάρτησης και της εισόδου/εξόδου κάθε μπλοκ διεργασίας είναι όπως φαίνεται στο σχήμα. Ο κώδικας εμφανίζεται παρακάτω, αλλά και συνημμένος ως αρχεία VHD και txt. Εάν υπάρχουν αποκλίσεις, πηγαίνετε με τα αρχεία VHD.

BTW: Μάλλον θα έπρεπε να είχαμε κάνει τις γραμμές μας πιο σύντομες, αλλά η ενσωμάτωση κώδικα στο Instructables αποδείχθηκε επίσης πολύ ενοχλητική, οπότε η απόσταση δεν είναι η μεγαλύτερη και δεν υπάρχει επισημάνσεις σύνταξης. Εάν έχετε Vivado και θέλετε να ακολουθήσετε τον κώδικα, σας συνιστούμε ανεπιφύλακτα να κατεβάσετε το αρχείο.

Αρχικά, ας δούμε την ενότητα Sine Wave Generator.

βιβλιοθήκη IEEE; χρήση IEEE. STD_LOGIC_1164. ALL; χρησιμοποιήστε το IEEE. NUMERIC_STD. ALL; οντότητα Wave_Generator is Port (Ενεργοποίηση: σε STD_LOGIC; - Πατήστε το πλήκτρο Freq_Cnt: στο STD_LOGIC_VECTOR (15 προς τα 0); - Αριθμός μετρητή = 100MHz / (Σημείωση Συχνότητα*64 Διαιρέσεις του ημιτονοειδούς κύματος) (στρογγυλή στον πλησιέστερο αριθμό) - μετονομάστηκε από Freq wavegenCLK: σε STD_LOGIC; - Basys3 100MHz CLK WaveOut: out STD_LOGIC_VECTOR (9 κάτω στο 0)). - Υπογεγραμμένο πλάτος άκρου κύματος Wave_Generator. αρχιτεκτονική Behavioral of Wave_Generator είναι σήμα i: ακέραιο εύρος 0 έως 64: = 0; -δείκτης τράπεζας μνήμης εύρους τύπου memory_type είναι πίνακας (0 έως 63) ακέραιου εύρους -64 έως 63, - δημιουργήστε τράπεζα μνήμης (ROM) για να κρατάτε τιμές πλάτους- αυτή η RAM ή η ROM απλά αναρωτιέται … πλάτος σήματος: 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); - τράπεζα μνήμης πλάτους για διαδικασία έναρξης ημιτονοειδούς κύματος (wavegenCLK, Trigger) μεταβλητός μετρητής: ανυπόγραφος (15 προς 0 προς): = προς_ανυπόγραφο (0, 16). - μετρητής διαιρέτη ρολογιού, που μετονομάστηκε από count1 ξεκινά εάν (αυξανόμενη_ακμή (wavegenCLK)) στη συνέχεια εάν (Ενεργοποίηση = '1') τότε- το πλήκτρο πιέζεται μετρητής: = μετρητής + 1; εάν (μετρητής = ανυπόγραφος (Freq_Cnt)) τότε - Freq_Cnt = 100Mhz / (σημ. συχνότητα * 64 διαιρέσεις του ημιτονοειδούς κύματος) - επαναφέρετε τον μετρητή και αντιστοιχίστε δεδομένα πλάτους στον μετρητή εξόδου: = σε_ανυπόγραφο (0, 16)? WaveOut <= STD_LOGIC_VECTOR (προς_υπογραφή (πλάτος (i), 10)); - προσαύξηση i για την επόμενη ανάγνωση i <= i + 1, - επαναφορά i εάν ένα ημιτονοειδές κύμα έχει ολοκληρωθεί εάν (i = 63) τότε i <= 0 · τέλος εαν; τέλος εαν; - (counter = unsigned (Freq_Cnt)) else- το πλήκτρο δεν πατιέται- επαναφορά εξόδου, δείκτη πλάτους και μετρητή WaveOut <= "0000000000"; i <= 0; μετρητής: = to_sunsigned (0, 16); --Έξοδος εξόδου = -64 όταν δεν παίζεται καμία νότα όταν τελειώσει εάν? - (Ενεργοποίηση = '1') τέλος αν? - (άνοδος_ακράς (CLK)) τερματική διαδικασία. τέλος Συμπεριφορική?

Θα δημιουργήσουμε ένα ψηφιακό ημιτονοειδές κύμα στο Basys3 χρησιμοποιώντας το εσωτερικό ρολόι και μια ROM. Αυτή η ROM θα αποθηκεύσει 64 τιμές που αντιπροσωπεύουν 64 πλάτη σε ημιτονοειδές κύμα. Δείτε το Σχήμα 1. Οι 64 τιμές που χρησιμοποιούμε μιμούνται ένα ημιτονοειδές κύμα με αρκετά καλή ανάλυση.

Χρησιμοποιώντας το εσωτερικό ρολόι, μετράμε σε μια τιμή που αντιπροσωπεύει την ταχύτητα του ρολογιού διαιρούμενη με τη συχνότητα του κύματος που θέλουμε και 64: Clk div = 100MHz / (Freq * 64) Κάθε φορά που ο μετρητής μας φτάνει σε αυτήν την τιμή, καλούμε έναν αριθμό από τη ROM και στείλτε το από τη μονάδα γεννήτριας κυμάτων. Η συχνότητα του κύματός μας θα εξαρτηθεί από το πόσο γρήγορα ονομάζουμε αυτά τα πλάτη.

Θα έχουμε 25 υποενότητες, το καθένα συσχετισμένο με μία συχνότητα/νότα.

Ακολουθεί ο υπόλοιπος κώδικας που καλεί τις μονάδες Sine Wave Generator:

βιβλιοθήκη IEEE; χρήση IEEE. STD_LOGIC_1164. ALL; χρησιμοποιήστε το IEEE. NUMERIC_STD. ALL; οντότητα Two_Octave_Synth is Port (CLK: σε STD_LOGIC; O4: σε STD_LOGIC_VECTOR (11 προς 0); O5: σε STD_LOGIC_VECTOR (12 προς 0); έξοδος: εκτός STD_LOGIC); τέλος Two_Octave_Synth; αρχιτεκτονική Behavioral of Two_Octave_Synth is component τελικό στοιχείο? --------------------------- σήματα εξόδου από γεννήτρια κύματος ------------------ ----- σηματοδοτούν WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveG5, WaveGs5, WaveA5, WaveAs5, WaveB5, WaveC6: υπογεγραμμένο (9 προς 0) -------------------------------- για λογική επιλογής σημειώσεων -------------- ------ σήμα 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: ανυπόγραφο (4 στο 0). σήμα cntC4, cntCs4, cntD4, cntDs4, cntE4, cntF4, cntFs4, cntG4, cntGs4, cntA4, cntAs4, cntB4, cntC5, cntCs5, cntD5, cntDs5, cntE5, cntF5, cntFs5, cntG5, cntGs5, cntA5, cntAs5, cntB5, cntC6: χωρίς υπογραφή (4 κάτω από το 0); σφάλμα σήματος: STD_LOGIC; ----------------------------------- για προσθήκη ημιτονοειδών κυμάτων ----------- --------------- σήμα Wave0, Wave1, Wave2, Wave3: υπογεγραμμένο (9 προς 0) -σήματα από σήμα εξόδου μονάδας Wave Generator WaveSum: STD_LOGIC_VECTOR (9 προς 0) -σήμα για συνοπτικά ημιτονοειδή κύματα (η φιλοφρόνηση 2 -512 έως 511) σήμα θετικόWaveSum: STD_LOGIC_VECTOR (9 κάτω στο 0). --ανυπόγραφο 0 έως 1023, για χρήση σε γεννήτρια PWM --------------------------------------- για παραγωγή PWM ----------------------------------- σήμα ping_length: χωρίς υπογραφή (9 προς 0): = χωρίς υπογραφή (positiveWaveSum); --signal off_length: ανυπόγραφο (6 προς 0): = προς_ανυπόγραφο (127, 7) -ανυπόγραφο (WAVE) σήμα PWM: χωρίς υπογραφή (9 προς 0): = προς_ανυπόγραφο (0, 10); έναρξη Σημείωση_C4: Χάρτης θύρας Wave_Generator (Trigger => O4 (0), Freq_Cnt => X "1755", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveC4); --5973, 261.63 Hz Σημείωση_Cs4: Χάρτης θύρας Wave_Generator (Trigger => O4 (1), Freq_Cnt => X "1606", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveCs4);-5638, 277,18 Hz Σημείωση_D4: Χάρτης θύρας Wave_Generator (Trigger => O4 (2), Freq_Cnt => X "14C9", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveD4); --5321, 293,66 Hz Σημείωση_Ds4: Χάρτης θύρας Wave_Generator (Trigger => O4 (3), Freq_Cnt => X "139F", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveDs4);-5023, 311,13 Hz Σημείωση_E4: Χάρτης θύρας Wave_Generator (Trigger => O4 (4), Freq_Cnt => X "1285", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveE4); --4741, 329,63 Hz Σημείωση_F4: Χάρτης θύρας Wave_Generator (Trigger => O4 (5), Freq_Cnt => X "117B", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveF4); --4475, 349,23 Hz Σημείωση_Fs4: Χάρτης θύρας Wave_Generator (Trigger => O4 (6), Freq_Cnt => X "1080", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveFs4);-4224, 369,99 Hz Σημείωση4: Χάρτης θύρας Wave_Generator (Trigger => O4 (7), Freq_Cnt => X "0F92", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveG4); --3986, 392.00 Hz Σημείωση_Gs4: Χάρτης θύρας Wave_Generator (Trigger => O4 (8), Freq_Cnt => X "0EB3", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveGs4);-3763, 415,30 Hz Σημείωση_A4: Χάρτης θύρας Wave_Generator (Trigger => O4 (9), Freq_Cnt => X "0DE0", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveA4); --3552, 440.00 Hz Σημείωση_As4: Χάρτης θύρας Wave_Generator (Trigger => O4 (10), Freq_Cnt => X "0D18", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveAs4);-3352, 466,16 Hz Σημείωση_B4: Χάρτης θύρας Wave_Generator (Trigger => O4 (11), Freq_Cnt => X "0C5C", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveB4); --3164, 493,88 Hz ------------------------------------------------ ------------------------------------------------------ --------------------------- Σημείωση_C5: Χάρτης θύρας Wave_Generator (Trigger => O5 (0), Freq_Cnt => X "0BAB", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveC5); --2987, 523,25 Hz Σημείωση_Cs5: Χάρτης θύρας Wave_Generator (Trigger => O5 (1), Freq_Cnt => X "0B03", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveCs5);-2819, 554,37 Hz Σημείωση_D5: Χάρτης θύρας Wave_Generator (Trigger => O5 (2), Freq_Cnt => X "0A65", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveD5); --2661, 587.33 Hz Σημείωση_Ds5: Χάρτης θύρας Wave_Generator (Trigger => O5 (3), Freq_Cnt => X "09D0", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveDs5);-2512, 622,25 Hz Σημείωση_E5: Χάρτης θύρας Wave_Generator (Trigger => O5 (4), Freq_Cnt => X "0943", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveE5); --2371, 659,25 Hz Σημείωση_F5: Χάρτης θύρας Wave_Generator (Trigger => O5 (5), Freq_Cnt => X "08Be", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveF5); --2238, 698,46 Hz Σημείωση_Fs5: Χάρτης θύρας Wave_Generator (Trigger => O5 (6), Freq_Cnt => X "0840", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveFs5);-2112, 739,99 Hz Σημείωση5: Χάρτης θύρας Wave_Generator (Trigger => O5 (7), Freq_Cnt => X "07CA", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveG5); --1994, 783,99 Hz Σημείωση_Gs5: Χάρτης θύρας Wave_Generator (Trigger => O5 (8), Freq_Cnt => X "075A", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveGs5);-1882, 830,61 Hz Σημείωση_A5: Χάρτης θύρας Wave_Generator (Trigger => O5 (9), Freq_Cnt => X "06F0", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveA5); --1776, 880,00 Hz Σημείωση_As5: Χάρτης θύρας Wave_Generator (Trigger => O5 (10), Freq_Cnt => X "068C", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveAs5);-1676, 932,33 Hz Σημείωση_B5: Χάρτης θύρας Wave_Generator (Trigger => O5 (11), Freq_Cnt => X "062E", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveB5); --1582, 987,77 Hz Σημείωση_C6: Χάρτης θύρας Wave_Generator (Trigger => O5 (12), Freq_Cnt => X "05D6", wavegenCLK => CLK, υπογεγραμμένο (WaveOut) => WaveC6); --1494, 1046,5 Hz ------------ λογική επιλογής σημειώσεων ------------ C4 <= "0000" & O4 (0); Cs4 <= "0000" & O4 (1); D4 <= "0000" & O4 (2); Ds4 <= "0000" & O4 (3); Ε4 <= "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; Επιλογή: διαδικασία (WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, WaveF5, WaveFs5, WaveG5, WaveGs5, WaveA5, WaveAs5, WaveB5, WaveC6) ξεκινούν εάν (cntC6 = "00000") στη συνέχεια --------------- εάν δεν δημιουργούνται σήματα Wave0 <= "0000000000"; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 <= "0000000000"; αλλιώς αν (O4 (0) = '1') τότε ------------------- σημείωση C4 έπαιξε Wave0 Wave0 Wave1 error Wave0 Wave1 Wave2 error Wave0 Wave1 Wave2 Wave3 error Wave0 Wave1 error Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 Wave0 Wave1 error Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 σφάλμα Wave0 Wave1 Wave2 Wave3 Wave0 < = WaveC6; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave1 <= WaveC6; Wave2 <= "0000000000"; Wave3 Wave2 <= WaveC6; Wave3 Wave3 error Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave2 <= "0000000000"; Wave3 Wave3 error <= '1'; τελική περίπτωση? τέλος εαν; τέλος εαν; τελική διαδικασία? ------------- αθροιστής ημιτονοειδούς κύματος -------------------- WaveSum <= STD_LOGIC_VECTOR (Wave0 + Wave1 + Wave2 + Wave3); --------- κάνει το ημιτονοειδές κύμα θετικό για pwm --------------------- θετικόWaveSum <= όχι WaveSum (9) & WaveSum (8 κάτω έως 0); ------------- γεννήτρια PWM --------------------- διαδικασία (CLK)-αριθμός μεταβλητών: χωρίς υπογραφή (1 προς 0): = to_sunsigned (0, 2); έναρξη εάν (αυξανόμενη άκρη (CLK)) τότε --μετρήστε: = μετρήστε + 1; --if (count = to_unsigned (4, 2)) then --count: = to_sunsigned (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 εάν; τερματισμός εάν; τερματισμός διαδικασίας. τέλος Συμπεριφοράς

4 Επιλογέας ΣημείωσηςΤο πιο δύσκολο κομμάτι αυτού του έργου είναι η επιλογή μόλις τεσσάρων συχνοτήτων. Το κάναμε με μια ολόκληρη δήλωση lotta IF και χρησιμοποιήσαμε σήματα αντί για μεταβλητές, έτσι ώστε η διαδικασία να μπορεί να προσομοιωθεί και να διορθωθεί. Δοκιμάσαμε άλλες μεθόδους χρησιμοποιώντας μεταβλητές και βρόχους FOR, αλλά αντιμετωπίσαμε σφάλματα χρόνου εκτέλεσης. Έτσι, στο τέλος, αποφασίσαμε ότι αν λειτουργεί, θα το αφήσουμε ήσυχο. Μην διορθώσετε αυτό που δεν είναι σπασμένος αμιρίτης;

Τα τέσσερα κύματα εξόδου φέρουν την ένδειξη Wave0, Wave1, Wave2, Wave3 - αυτά είναι που θα προστεθούν μαζί για να σχηματίσουν την τελική έξοδο.

Κοιτάζοντας τον κώδικα, θα δείτε μια δέσμη σημάτων με την ένδειξη C4, Cs4, D4, Ds4, κ.λπ. Αυτά είναι σήματα 5-bit που παίρνουν την αντίστοιχη σκανδάλη από O4 (οκτάβα 4) ή O5 (οκτάβα 5) και τα κάνουν 5-bit για προσθήκη.

Στη συνέχεια, οι μεταβλητές cntC4, cntCs4 κ.λπ. αντιπροσωπεύουν πόσες νότες χαμηλότερες από τη νότα στόχου έχουν παιχτεί, συμπεριλαμβανομένης της νότας στόχου. Για παράδειγμα, εάν παίζονται C4, E4, G4, A#4 και D5 (χορδή C9) το cntC4 θα είναι 1, το cntE4 θα είναι 2, το cntG4 θα είναι 3 κ.λπ.

Στη συνέχεια, κάθε φορά που παίζεται μια νότα, η καταμέτρηση για τη νότα -στόχο θα εξεταστεί για να δει πού να συνδέσει το σήμα της νότας. Για παράδειγμα, εάν παίζεται η νότα D5 (που σημαίνει ότι το O5 (2) είναι υψηλό) και το cntD5 είναι 3, τότε παίζονται 3 νότες, με 2 νότες χαμηλότερες από το D5, οπότε θα συνδέσουμε το waveD5 με το Wave2 (το τρίτο κύμα καταμέτρηση σήματος από το Wave0). Εναλλακτικά, εάν το cntD5 είναι 5, τότε αυτή τη στιγμή παίζονται 5 νότες, με 4 νότες χαμηλότερες από το D5, οπότε θα αφήσουμε το waveD5 να κρέμεται και δεν θα κάνουμε τίποτα με αυτό.

Στη συνέχεια, οι δηλώσεις IF επαναλαμβάνονται για να καλύψουν τις περιπτώσεις και για τις 25 σημειώσεις.

Amplitude Adder

Αφού επιλεγούν τα χαμηλότερα 4 κύματα πρέπει να τα προσθέσουμε μαζί. Ο λόγος που θα προσθέσουμε μόνο τέσσερις σημειώσεις είναι επειδή η ιδέα PWM που χρησιμοποιούμε για την έξοδό μας μπορεί να έχει μόνο μια ορισμένη ανάλυση έως ότου το PWM λειτουργεί πολύ αργά και το ηχείο θα αρχίσει να σηκώνει το τετράγωνο κύμα PWM. Για παράδειγμα, αν χρησιμοποιήσουμε ανάλυση 8192 (13 bit), καθένα από αυτά τα 8192 σημεία πρέπει να αντιστοιχεί σε μια ανερχόμενη άκρη του ρολογιού επί του σκάφους. Έτσι, 100MHz / 8192 = 12,2kHz, το οποίο είναι αρκετά εντός του εύρους της ανθρώπινης ακοής.

Η πραγματική προσθήκη των πλάτων είναι εξαιρετικά απλή, απλά πρέπει να βεβαιωθείτε ότι μπορεί να τρέξει πολύ γρήγορα.

Έξοδος PWM

Ο κύκλος λειτουργίας του PWM θα αντιπροσωπεύει το πλάτος του κύματος εξόδου μας εκείνη τη στιγμή. Για παράδειγμα, εάν έχουμε εύρος πλάτους από 0 έως 128, το 0 θα ήταν κύκλος εργασίας 0%, το 64 θα ήταν 50%, το 128 θα ήταν 100%κ.λπ. Αυτό το PWM θα λειτουργεί εξαιρετικά γρήγορα (το δικό μας είναι 97,6 kHz), τόσο γρήγορα ώστε το ηχείο να μην αναγνωρίζει τα μεμονωμένα τετραγωνικά κύματα και αντίθετα να κοιτάξει τη μέση τάση, δημιουργώντας το «αναλογικό» μας σήμα.

Αρχείο περιορισμών

Μπορεί να έχετε συνδέσει το υλικό σας διαφορετικά, οπότε βεβαιωθείτε ότι το αρχείο περιορισμών ταιριάζει.

Βήμα 5: Λήψεις κώδικα

Παρακάτω είναι ο κώδικας, τόσο σε μορφή.txt όσο και.vhd για το Vivado. Το Wave_Generator είναι η υποενότητα γεννήτριας κυμάτων και η Two_Octave_Synth είναι η κορυφαία μονάδα με όλα τα άλλα.

Συνιστάται: