Съдържание:

Basys3 FPGA цифров аудио синтезатор: 5 стъпки
Basys3 FPGA цифров аудио синтезатор: 5 стъпки

Видео: Basys3 FPGA цифров аудио синтезатор: 5 стъпки

Видео: Basys3 FPGA цифров аудио синтезатор: 5 стъпки
Видео: КИХ-фильтр на XILINX FPGA: проектирование с использованием MATLAB и реализация FPGA 2024, Юли
Anonim
Image
Image
Basys3 FPGA цифров аудио синтезатор
Basys3 FPGA цифров аудио синтезатор
Basys3 FPGA цифров аудио синтезатор
Basys3 FPGA цифров аудио синтезатор

Този цифров синтезатор на синусоидална клавиатура ще приема потребителски входове чрез поредица от моментни превключватели, разположени като клавиатура, и ще извежда аудио вълна през високоговорител. Въз основа на потребителски входове, устройството ще генерира синусоиди с различни честоти от C4 до C6. Потребителят може да въвежда бележки от C4 до C6 (общо 25 ноти) и до четири клавиша едновременно - ако са натиснати повече от четири клавиша, ще се изпълнят четирите най -ниски тона.

Този проект е направен от Райън Морис и Мавис Цой за нашия клас по цифров дизайн Cal Poly CPE 133:)

Стъпка 1: Теория

FPGA платката може да извежда само цифрови сигнали. С други думи, той може да произвежда само високо (3.3V) напрежение или ниско (0V) напрежение. Аудио сигналите обаче са аналогови и могат да имат безкрайно много увеличения на напрежението. За да заобиколим това, ще използваме PWM (широчинно -импулсна модулация) сигнал, за да емулираме аналогова вълна. Ако не знаете какво е PWM, вижте това:

Стъпка 2: Съставки и инструменти

  • Компютър с инсталиран Vivado
  • Ще използваме Vivado версия 2017.2
  • Basys3 FPGA съвет
  • 25 ограничителни превключвателя SPDT (използвахме ги)
  • 30 джъмперни проводника (единият край мъжки, другият край няма значение), 12 инча
  • Резачки за тел
  • Машини за сваляне на тел
  • Резервна тел за запояване
  • Смола-сърцевина спойка
  • Поялник
  • ¼”женски аудио жак
  • Усилвател/високоговорител
  • Нещо за монтиране на превключвателите (използвахме протоборд + дървена кутия)

Стъпка 3: Настройка на окабеляване и хардуер

Настройка на окабеляване и хардуер
Настройка на окабеляване и хардуер
Настройка на окабеляване и хардуер
Настройка на окабеляване и хардуер
Настройка на окабеляване и хардуер
Настройка на окабеляване и хардуер

Системна Архитектура

Вижте Фигура 1: 25 налични входа → Basys3 Board → усилвател и високоговорител.

Изход

Вижте Фигура 2: База Basys3 → 1/2 женски аудио жак → високоговорител (с усилвател)

Вход

Връзките pmod на платката Basys3 трябва да бъдат свързани към земята, за да се види нисък вход и няма да функционират правилно, ако останат като отворена верига. Поради това трябва да използваме SPDT ключове за всички наши клавиши за бележки. Превключвателят SPDT основно позволява на потребителя да превключва между вериги при натискане, така че ще ги използваме като нашите „бутони“за въвеждане на ниски (0V) или високи (3.3V) сигнали към платката Basys3.

Всеки превключвател ще има NO (нормално отворен) терминал, свързан към 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 е Port (Тригер: в STD_LOGIC; - Натискане на клавиша Freq_Cnt: в STD_LOGIC_VECTOR (15 надолу 0); - Стойност на брояча = 100MHz / (Забележка Честота*64 деления на синусоида) (закръглено до най -близкото число) - преименувано от Freq wavegenCLK: в STD_LOGIC; - Basys3 100MHz CLK WaveOut: изход STD_LOGIC_VECTOR (9 надолу 0)); - Подписана амплитуда на края на вълната Wave_Generator; архитектура Поведението на 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 downto 0): = to_unsigned (0, 16); - брояч на разделител на часовник, преименуван от count1 begin if (rise_edge (wavegenCLK)) then if (Trigger = '1') then- клавишът е натиснат counter: = counter + 1; if (брояч = без знаци (Freq_Cnt)) след това - Freq_Cnt = 100Mhz / (забележете честота * 64 деления на синусоидалната вълна) - нулирайте брояча и задайте амплитудни данни към изходния брояч: = to_unsigned (0, 16); WaveOut <= STD_LOGIC_VECTOR (to_signed (amplitude (i), 10)); - увеличение i за следващо четене i <= i + 1; - нулиране i, ако една синусоида е завършена, ако (i = 63), тогава i <= 0; край ако; край ако; - (брояч = без знак (Freq_Cnt)) else- клавишът не е натиснат- изход за нулиране, индекс на амплитуда и брояч WaveOut <= "0000000000"; i <= 0; брояч: = to_unsigned (0, 16); -изходна амплитуда = -64, когато не се свири нота, край, ако; - (Trigger = '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 е Port (CLK: в STD_LOGIC; O4: в STD_LOGIC_VECTOR (11 downto 0); O5: в STD_LOGIC_VECTOR (12 downto 0); изход: out STD_LOGIC); край Two_Octave_Synth; архитектура Поведението на Two_Octave_Synth е компонент Wave_Generator е 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)) краен компонент; --------------------------- изходни сигнали от генератора на вълни ------------------ ----- сигнал WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, WaveE5, Wave5, Wave5, Wave5 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, cntAs, cntAs4, cntB4, cntC5, cntCs5, cntD5, cntDs5, cntE5, cnt5, cnt5, cnt5, cnt5, cnt5: без знак (4 надолу 0); грешка в сигнала: STD_LOGIC; ----------------------------------- за добавяне на синусоидални вълни ----------- --------------- сигнал Wave0, Wave1, Wave2, Wave3: подписан (9 downto 0); -сигнали от изходния сигнал на Wave Generator модул WaveSum: STD_LOGIC_VECTOR (9 надолу 0); -сигнал за сумирани синусоиди (комплиментът на 2 -512 до 511) положителен сигнал WaveSum: STD_LOGIC_VECTOR (9 надолу 0); -без знаци от 0 до 1023, за използване в PWM генератор ----------------------------------- за генериране на PWM ------------------------------- сигнал ping_length: unsigned (9 downto 0): = unsigned (positiveWaveSum); --signal off_length: unsigned (6 downto 0): = to_unsigned (127, 7) -unsigned (WAVE); сигнал ШИМ: без знак (9 надолу 0): = до_знак (0, 10); започнете Note_C4: Карта на порта Wave_Generator (Trigger => O4 (0), Freq_Cnt => X "1755", wavegenCLK => CLK, подписано (WaveOut) => WaveC4); --5973, 261.63 Hz Note_Cs4: Карта на порта на Wave_Generator (Trigger => O4 (1), Freq_Cnt => X "1606", wavegenCLK => CLK, подписано (WaveOut) => WaveCs4);-5638, 277.18 Hz Note_D4: Карта на порта Wave_Generator (Trigger => O4 (2), Freq_Cnt => X "14C9", wavegenCLK => CLK, подписано (WaveOut) => WaveD4); --5321, 293.66 Hz Note_Ds4: Карта на порта на Wave_Generator (Trigger => O4 (3), Freq_Cnt => X "139F", wavegenCLK => CLK, подписано (WaveOut) => WaveDs4);-5023, 311.13 Hz Note_E4: Карта на порта Wave_Generator (Trigger => O4 (4), Freq_Cnt => X "1285", wavegenCLK => CLK, подписано (WaveOut) => WaveE4); --4741, 329.63 Hz Note_F4: Карта на порта Wave_Generator (Trigger => O4 (5), Freq_Cnt => X "117B", wavegenCLK => CLK, подписано (WaveOut) => WaveF4); --4475, 349.23 Hz Note_Fs4: Карта на порта на Wave_Generator (Trigger => O4 (6), Freq_Cnt => X "1080", wavegenCLK => CLK, подписано (WaveOut) => WaveFs4);-4224, 369.99 Hz Note_G4: Карта на порта на Wave_Generator (Trigger => O4 (7), Freq_Cnt => X "0F92", wavegenCLK => CLK, подписано (WaveOut) => WaveG4); --3986, 392.00 Hz Note_Gs4: Карта на порта на Wave_Generator (Trigger => O4 (8), Freq_Cnt => X "0EB3", wavegenCLK => CLK, подписано (WaveOut) => WaveGs4);-3763, 415.30 Hz Note_A4: Карта на порта Wave_Generator (Trigger => O4 (9), Freq_Cnt => X "0DE0", wavegenCLK => CLK, подписано (WaveOut) => WaveA4); --3552, 440.00 Hz Note_As4: Карта на порта Wave_Generator (Trigger => O4 (10), Freq_Cnt => X "0D18", wavegenCLK => CLK, подписано (WaveOut) => WaveAs4);-3352, 466.16 Hz Note_B4: Карта на порта Wave_Generator (Trigger => O4 (11), Freq_Cnt => X "0C5C", wavegenCLK => CLK, подписано (WaveOut) => WaveB4); --3164, 493.88 Hz -------------------------------------------- -------------------------------------------------- --------------------------- Note_C5: Карта на порта Wave_Generator (Trigger => O5 (0), Freq_Cnt => X "0BAB", wavegenCLK => CLK, подписан (WaveOut) => WaveC5); --2987, 523.25 Hz Note_Cs5: Карта на порта на Wave_Generator (Trigger => O5 (1), Freq_Cnt => X "0B03", wavegenCLK => CLK, подписано (WaveOut) => WaveCs5);-2819, 554.37 Hz Note_D5: Карта на порта Wave_Generator (Trigger => O5 (2), Freq_Cnt => X "0A65", wavegenCLK => CLK, подписано (WaveOut) => WaveD5); --2661, 587.33 Hz Note_Ds5: Карта на порта на Wave_Generator (Trigger => O5 (3), Freq_Cnt => X "09D0", wavegenCLK => CLK, подписано (WaveOut) => WaveDs5);-2512, 622.25 Hz Note_E5: Карта на порта Wave_Generator (Trigger => O5 (4), Freq_Cnt => X "0943", wavegenCLK => CLK, подписано (WaveOut) => WaveE5); --2371, 659.25 Hz Note_F5: Карта на порта на Wave_Generator (Trigger => O5 (5), Freq_Cnt => X "08Be", wavegenCLK => CLK, подписано (WaveOut) => WaveF5); --2238, 698.46 Hz Note_Fs5: Карта на порта на Wave_Generator (Trigger => O5 (6), Freq_Cnt => X "0840", wavegenCLK => CLK, подписано (WaveOut) => WaveFs5);-2112, 739.99 Hz Note_G5: Карта на порта Wave_Generator (Trigger => O5 (7), Freq_Cnt => X "07CA", wavegenCLK => CLK, подписано (WaveOut) => WaveG5); --1994, 783.99 Hz Note_Gs5: Карта на порта на Wave_Generator (Trigger => O5 (8), Freq_Cnt => X "075A", wavegenCLK => CLK, подписано (WaveOut) => WaveGs5);-1882, 830.61 Hz Note_A5: Карта на порта Wave_Generator (Trigger => O5 (9), Freq_Cnt => X "06F0", wavegenCLK => CLK, подписано (WaveOut) => WaveA5); --1776, 880.00 Hz Note_As5: Карта на порта на Wave_Generator (Trigger => O5 (10), Freq_Cnt => X "068C", wavegenCLK => CLK, подписано (WaveOut) => WaveAs5);-1676, 932.33 Hz Note_B5: Карта на порта Wave_Generator (Trigger => O5 (11), Freq_Cnt => X "062E", wavegenCLK => CLK, подписано (WaveOut) => WaveB5); --1582, 987.77 Hz Note_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); 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 + С6; Избор: процес (WaveC4, WaveCs4, WaveD4, WaveDs4, WaveE4, WaveF4, WaveFs4, WaveG4, WaveGs4, WaveA4, WaveAs4, WaveB4, WaveC5, WaveCs5, WaveD5, WaveDs5, Wave5 Wave5, Wave5 Wave5, Wave5 Wave5 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 Грешка Wave2 Wave3 Wave0 Wave1 Wave2 Wave3 грешка Wave0 Wave1 Wave2 Wave3 грешка Wave0 Wave1 Wave2 Wave3 грешка Wave0 Wave1 Wave2 Wave3 грешка Wave0 Wave1 Wave2 Wave3 грешка Wave2 Wave Грешка Wave2 Wave3 Wave0 Wave1 Wave2 Wave3 грешка Wave0 Wave1 Wave2 Wave3 грешка Wave0 Wave1 Wave2 Wave3 грешка Wave0 Wave1 Wave2 Wave3 грешка Wave0 Wave1 Wave2 Wave3 грешка Wave2 Wave2 Wave2 Wave3 Wave = WaveC6; Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave1 <= WaveC6; Wave2 <= "0000000000"; Wave3 Wave2 <= WaveC6; Wave3 Грешка на Wave3 Wave1 <= "0000000000"; Wave2 <= "0000000000"; Wave3 Wave2 <= "0000000000"; Wave3 Wave3 error <= '1'; краен случай; край ако; край ако; краен процес; ------------- суматор на синусоидални вълни -------------------- WaveSum <= STD_LOGIC_VECTOR (Wave0 + Wave1 + Wave2 + Wave3); --------- направете синусоидата положителна за pwm --------------------- positiveWaveSum <= не WaveSum (9) & WaveSum (8 downto 0); ------------- PWM генератор --------------------- процес (CLK)-променлив брой: без знаци (1 надолу 0): = to_unsigned (0, 2); start if (нарастващ ръб (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 ако; край ако; край процес; край поведенчески;

4 Селектор за бележки Най -сложната част от този проект е избирането само на четири честоти. Направихме го с много лота IF изявления и използвахме сигнали вместо променливи, за да може процесът да бъде симулиран и отстранен. Опитахме други методи, използвайки променливи и цикли FOR, но срещнахме грешки по време на изпълнение. Така че в крайна сметка решихме, че ако работи, ще го оставим на мира. Не поправяйте това, което не е счупен амирит?

Четирите изходни вълни са обозначени като Wave0, Wave1, Wave2, Wave3 - това е, което ще бъде добавено заедно, за да образува крайния изход.

Разглеждайки кода, ще видите куп сигнали с етикет C4, Cs4, D4, Ds4 и т.н. Това са 5-битови сигнали, които вземат съответния тригер от O4 (октава 4) или O5 (октава 5) и ги правят 5-битов за добавяне.

След това променливите cntC4, cntCs4 и т.н. представляват колко ноти, по -ниски от целевата, са изиграни, включително целевата. Например, ако се играят C4, E4, G4, A#4 и D5 (акорд C9) cntC4 ще бъде 1, cntE4 ще бъде 2, cntG4 ще бъде 3 и т.н.

След това, всеки път, когато се пусне нота, броят на целевата нота ще бъде проверен, за да се види къде да се свърже нотният сигнал. Например, ако се играе нота D5 (което означава, че O5 (2) е висока) и cntD5 е 3, тогава в момента се играят 3 ноти, с 2 ноти по -ниски от D5, така че ще закачим вълна D5 към вълна 2 (третата вълна отчитане на сигнала от Wave0). Като алтернатива, ако cntD5 е 5, тогава в момента се играят 5 ноти, с 4 ноти по -ниски от D5, така че просто ще оставим waveD5 да виси и няма да правим нищо с него.

След това изявленията IF се повтарят, за да покрият случаите за всичките 25 бележки.

Амплитуден суматор

След като са избрани най -ниските 4 вълни, трябва да ги съберем. Причината, поради която ще добавим само четири бележки заедно, е, че идеята за ШИМ, която използваме за нашия изход, може да има само определена разделителна способност, докато ШИМ не работи твърде бавно и високоговорителят ще започне да улавя квадратната вълна на ШИМ. Например, ако трябва да използваме разделителна способност 8192 (13 бита), всяка от тези 8192 точки трябва да съответства на нарастващ ръб на бордовия часовник. И така, 100MHz / 8192 = 12.2kHz, което е в рамките на човешкия слух.

Действителното добавяне на амплитудите е супер просто, просто трябва да сте сигурни, че може да работи много бързо.

ШИМ изход

Работният цикъл на ШИМ ще представлява амплитудата на нашата изходна вълна в този момент. Например, ако имаме диапазон на амплитуда от 0 до 128, 0 ще бъде 0%работен цикъл, 64 ще бъде 50%, 128 ще бъде 100%и т.н. Тази ШИМ ще работи изключително бързо (нашата е 97,6 kHz), толкова бързо, че говорителят няма да разпознае отделните квадратни вълни и вместо това ще погледне средното напрежение, създавайки нашия „аналогов“сигнал.

Файл с ограничения

Може да сте свързали хардуера по различен начин, така че просто се уверете, че файлът с ограничения съвпада.

Стъпка 5: Изтегляне на код

По -долу е кодът, както във.txt формат, така и.vhd за Vivado. Wave_Generator е подмодулът на генератора на вълни, а Two_Octave_Synth е най-горният модул с всичко останало.

Препоръчано: