Tutorial: UltraNet-Receiver mit Arduino MKR Vidor 4000

Stand 02.09.2024: Dies ist noch ein Platzhalter für das Tutorial. In den nächsten Wochen werde ich das Tutorial hier schreiben und mit Bildern entsprechend ausfüllen...

Auf meinem Youtube-Kanal habe ich 2023 ein Video zum Auslesen und Verarbeiten des Behringer UltraNet-Protokolls veröffentlicht (siehe Youtube: Hacking Behringers Ultranet for a FPGA-based DIY-Audiomixer). Dieses Tutorial soll euch dabei helfen, die doch recht komplexe Signalverarbeitung zwischen UltraNet-Gerät, FPGA und Mikrocontroller nachvollziehen und selbst verwenden zu können.

Bitte schaut euch zunächst entweder den einleitenden Artikel zum UltraNet Receiver und/oder das Youtube-Video an. Ganz kurz zusammengefasst: UltraNet überträgt auf zwei Signalpfaden jeweils 8 Mono-Audiokanäle mit 48kHz in einem AES/EBU-Format (auch AES3, auch von SP/DIF im Heimkino verwendet). Diese Signale werden in meinem Ansatz zunächst in I2S-Signale und dann in individuelle 24-Bit-Datenvektoren im FPGA konvertiert. Da die AES/EBU-Signale mit 12,288 MHz übertragen werden, muss der FPGA mit einer ausreichend hohen Taktrate (200 MHz) die Signale dekodieren.

 

1 Hardware und Software

vidor4000

Da ich eher zufällig auf das ganze Thema gestoßen bin, habe ich zunächst mit dem Arduino MKR Vidor 4000 Board experimentiert. So bin ich zum Intel Cyclone 10LP FPGA gekommen, aber man kann theoretisch das Ganze auch mit einem Xilinx/AMD FPGA durchführen. Als Hardware habe ich für das Tutorial weiterhin das Arduino MKR Vidor 4000 Board vorgesehen, wohlwissend, dass es momentan (Stand 09/2024) leider nicht lieferbar ist. Alternativ kann man aber auch andere FPGA-Boards mit Cyclone-FPGA verwenden, z.B. das Trenz CYC1000 oder vergleichbare Boards. Der Vorteil des Vidor 4000 ist einfach, dass auf dem Board neben dem FPGA auch ein ESP32 und ein weiterer Mikrocontroller sitzen, mit denen man sehr viele zusätzliche Dinge berechnen kann (z.B. die Lautstärkeparameter oder die EQ-Einstellungen). Dies ist aber auch von einem PC aus möglich, sodass man auch mit dem CYC1000 theoretisch zum gleichen Ergebnis kommen kann.

 

Als Software benötigen wir insgesamt drei kostenfreie Tools:

  • Arduino IDE in Version 2.x, Downloadlink
    • Board-Support für Arduino SAMD Boards (32-bits ARM Cortex-M0+)
    • Ticker-Bibliothek von Stefan Staub
  • Intel Quartus Prime Lite (z.B. Version 23.1.1), Downloadlink
  • HTerm, Downloadlink

Theoretisch können wir auf HTerm verzichten, da wir die Steuerkommandos auch direkt von der Windows-Kommandozeile senden können. Aber es macht das Ganze deutlich einfacher.

 

2 GitHub Projekt auschecken

Um das GitHub-Projekt auszuchecken, installieren wir zunächst Git von www.git-scm.com. Nach der Installation mit Standardeinstellungen starten wir die Git-Bash entweder aus dem Startmenü von Windows, oder durch Drücken von Windows+R und dann der Eingabe von "C:\Program Files\Git\git-bash.exe". Mit dem Kommando "cd ~" wechseln wir in das Home-Verzeichnis des Benutzerkontos und checken das Repository mit dem folgenden Kommando in ein neues Unterverzeichnis aus "git clone https://github.com/xn--nding-jua/UltranetReceiver.git". Wir können das Verzeichnis mit dem Befehl Windows+R und dann der Eingabe von "%USERPROFILE%\UltranetReceiver" im Explorer öffnen.

 

3 FPGA-Bitstream vorbereiten

Nachdem die Grundvoraussetzungen passen, starten wir das installierte Quartus Prime Lite. Es sollten alle neueren Versionen grundsätzlich funktionieren, aber lassen wir uns mal auf Version 23.1.1 schauen. Wir öffnen als erstes das Quartus-Projekt aus dem Git-Repository:

ultranetTutorial 01

ultranetTutorial 02

Mit einem Doppelklick auf den Projektnamen auf der linken Seite kann man das übergeordnete Schematic öffnen:

ultranetTutorial 03

Zunächst machen wir noch keine Anpassungen an der Logik, sodass das Projekt lediglich kompiliert werden muss. Entweder drückst Du jetzt STRG+L oder klickst über das Hauptmenü auf "Processing" und dann auf "Start Compilation":

ultranetTutorial 04

Je nach Computer dauert das Kompilieren nun zwischen 2 und 10 Minuten:

ultranetTutorial 05

Anschließend werden im Unterverzeichnis "FPGA\output_files" zahlreiche neue Dateien angezeigt, unter anderem auch die für uns nun wichtige Datei UltranetReceiver.ttf:

ultranetTutorial 06

 

Leider können wir diese Datei jetzt noch nicht direkt in unseren Arduino-Code einbetten, aber wir können diese Datei mit Hilfe des beigelegten Konverter-Tools in eine übliche C-Header-Datei konvertieren. Hierzu kannst Du entweder die Batch-Datei "update_fpga_bitstream.bat" aus dem Unterverzeichnis "Controller" ausführen, oder den folgenden Befehl direkt in den Windows-Ausführen-Dialog eingeben: "%USERPROFILE%\UltranetReceiver\Controller\update_fpga_bitstream.bat". Nach der kurzen Konversion sollte eine neue Header-Datei "bitstream.h" im Verzeichnis "Controller" angelegt worden sein:

ultranetTutorial 07

 

Damit ist schon mal der FPGA-Teil soweit fürs erste abgeschlossen und wir können uns dem Hochladen über die Arduino-IDE zuwenden.

 

4 Bitstream hochladen und Verbindung testen

Von nun an können wir alles über die Arduino IDE in Version 2.x durchführen. Starte zunächst die Arduino IDE. Hier müssen wir nun erst einmal die Unterstützung für den SAMD21 und den ESP32 installieren. Hierfür klicke auf "File", dann auf "Preferences..." und dann auf den blauen Button auf der rechten Seite. Dort müssen die folgenden URLs eingetragen werden:

http://downloads.arduino.cc/Hourly/samd/package_samd-hourly-build_index.json
https://espressif.github.io/arduino-esp32/package_esp32_index.json (<- die ESP32-Unterstützung brauchen wir hier nicht, aber es ist eine gute Vorbereitung für den FPGA-Audiomixer)

ultranetTutorial 08

Nach Klicks auf die OK-Buttons kannst Du nun nach "samd" im Boards manager suchen und die Unterstützung für "Arduino SAMD Boards (32-bits ARM Cortex-M0+)" installieren. Bei dieser Gelegenheit kann man auch gleich den Support für den ESP32 installieren, sofern man möchte (der steckt im NINA W102 des Vidor 4000 drin). Das dauert aber etwas länger und wird für dieses Tutorial auch nicht benötigt.

 

Der Code benötigt zum Kompilieren nun noch eine Hilfs-Bibliothek, nämlich den Ticker von Stefan Staub. Diese Bibliothek kannst Du über den Library Manager von der Arduino IDE installieren:

ultranetTutorial 11

 

Jetzt ist endlich ein guter Zeitpunkt, das Arduino MKR Vidor 4000 an den USB-Anschluss anzuschließen. Die Arduino IDE sollte nun auch den virtuellen COM-Port finden und als "Board" "Arduino MKR Vidor 4000" anzeigen. Mit STRG+R oder über das Hauptmenü kannst Du den Code erst mal kompilieren. Das sollte recht schnell gehen und innerhalb von wenigen Sekunden abgeschlossen sein. Bitte nicht wundern, es kommen einige Warnungen, die aber oftmals in rot dargestellt werden. Das ist kein Fehler und sollte so in der Art aussehen:

ultranetTutorial 10

Jetzt sind wir schon mal auf einem Stand, dass wir den SAMD programmieren können. Mit STRG+U oder über das "Sketch"-Menü aus dem Hauptmenü und "Upload" sollte der Code auf den SAMD21 übertragen werden. Auch wird gleich der SPI-Flash des FPGAs mit unserem Bitstream beschrieben, weswegen das Hochladen ab ca. 50% etwas länger dauert. Das Board resettet nun automatisch und der FPGA und SAMD sind einsatzbereit.

Achtung 1: Eine Fehlerquelle ist hier, dass der Arduino MKR Vidor 4000 recht viel Strom benötigt. Ich hatte schon große Probleme mit einem passiven USB-Hub und selbst Notebook-USB-Anschlüsse haben teilweise nicht funktioniert. Ein aktiver USB-Hub mit einem guten Kabel hilft hier sehr, bzw. der direkte Anschluss an einen Desktop-PC.

Achtung 2: Den Vidor 4000 nicht direkt in der mitgelieferten Box mit dem Schaumstoff anschließen. Das schwarze Schaumstoff ist leider leitend und führt zu Kommunikationsproblemen. Es geht zwar nichts kaputt, aber der Vidor bootet nicht und der PC zeigt lediglich "USB Gerät fehlerhaft"

 

Wenn Du jetzt die heruntergeladene Software HTerm startest, können wir einen ersten Verbindungstest machen:

ultranetTutorial 12

Zunächst muss oben der korrekte COM-Port gewählt und sowohl führs senden als auch fürs Empfangen "LF" als Endzeichen gewählt werden. Nun kann mit einem Klick auf "Connect" die Verbindung hergestellt werden. Der Befehl "info?" gefolgt von einem Druck auf die Enter-Taste oder einem Klick auf den "ASend" Button rechts sollte im Feld "Received Data" zu folgendem ähnlichen Text führen:

Ultranet Receiver 0.4.0
FPGA-Version v0.1
Compiled on 02.09.2024
Infos: https://github.com/xn--nding-jua/UltranetReceiver

 

Falls nichts kommt, bitte den COM-Port testen und prüfen, ob der Vidor 4000 korrekt verbunden ist - und vor allem der schwarze Schaumstoff von den Pins entfernt wurde!

 

5 UltraNet-Gerät verbinden

Sofern der SAMD Daten über den COM-Port zurücksendet, versuch auch der FPGA bereits, UltraNet-Signale zu dekodieren. Jetzt brauchen wir also UltraNet. Ich hab für meine Tests ein defektes P16-I verwendet und bin direkt an die Buffer-ICs mit Jump-Wires gegangen:

ConnectionP16I 

Wenn ihr das nicht machen wollt/könnt, dann müsst ihr das UltraNet-Signal mit einem Signalempfänger (z.B. dem SI-52008-F) empfangen und dann mit einem weiteren Bauteil aus dem differentiellen Signal ein single-ended-Signal erzeugen:

ultranetTutorial 13

Folgende Pins sind momentan belegt:

  • Pin D0: der FPGA erwartet hier die Kanäle 1 bis 8
  • Pin D1: der FPGA erwartet hier die Kanäle 9 bis 16
  • Pin D3: Ausgabe eines Summensignals als SP/DIF, was von jedem handelsüblichen SP/DIF-Konverter verstanden wird
  • Pin D21: Ausgabe eines Summensignals als PDM, was mit einem einfachen RC-Filter wieder in ein richtiges Analogsignal gewandelt werden kann
  • Zusätzlich wird ein reguläres I2S-Signal ausgegeben:
    • Pin D4: I2S MCLK (Masterclock mit 12,288 MHz)
    • Pin D5: I2S Wordclock (48 kHz)
    • Pin D6: I2S Bitclock (2,304 MHz)
    • Pin D7: I2S Data (24-Bit, 48kHz, Stereo)

 

Für einen ganz einfachen Test bietet es sich also an, einen UltraNet-Stream an Pin D0 anzuschließen und entweder einen SPDIF-Konverter an D3 oder ein RC-Tiefpass an D21. Als RC reicht folgendes aus:

LPF

 

6 Signaltests

Damit wir etwas hören, müssen wir die Lautstärken noch entsprechend zum FPGA senden. Beim Initialisieren wird zwar die Hauptlautstärke auf 100% gesetzt, die einzelnen Kanälen liegen aber noch auf 0%. Also wieder HTerm öffnen, "LF" als Zeilenabschluss wählen und mit dem korrekten COM-Port verbinden. Ggfs. noch mal mit dem Befehl "info?" die Verbindung checken.

Nun kannst Du z.B. für Kanal 1 die Lautstärke auf 25% setzen. Dafür sende den Befehl "vol_ch1@25", bzw. einen anderen Kanal zwischen 1 und 16. Es sollte vom Controller ein "OK" zurückkommen. Zusätzlich kann die Hauptlautstärke mit den Befehlen "vol_main_l@25" und "vol_main_r@25" zwischen 0 und 100 eingestellt werden. Hier ist bislang noch eine lineare Lautstärkeskalierung implementiert. Im zweiten Repository "Audiomixer" ist eine logarithmische Skalierung vorhanden.

Solltest Du kein Audiosignal hören können, prüfe bitte die Signalleitung auf D0 und ggfs. mit einem Oszi die Signalform. Bei mir hat sich gezeigt, dass die Flankensteilheit durchaus ein Problem sein kann. Die Signale takten mit 12,288 MHz und dürfen daher nicht zu frei und willkürlich verlegt sein. Mit der direkten Verbindung zum IC (siehe Bild weiter oben) hatte es bei mir gut funktioniert. Bei der Verbindung über den SI-52008 und den AM26LV32CD hatte ich schon etwas größere Probleme.

 

7 Weitere Möglichkeiten

Sollte das UltraNet-Signal nun bei Dir korrekt dekodiert werden, kannst Du Dich vielleicht an das nächst größere Projekt wagen: den f/bape Audioplayer. Hier habe ich neben der reinen Audiomixer-Möglichkeit auf EQs, Frequenzweichen, Audio-Kompressoren und Noisegates implementiert. Hier ist die Funktionsvielfalt und die Kombinationsmöglichkeit einzig durch die Anzahl der Logikelemente im FPGA limiertiert und man kann damit durchaus ein gut funktionierendes 22 Kanal Digitalmischpult bauen. Es lohnt sich also mal reinzusehen: f/bape - Ein FPGA-basierter Audioplayer mit Equalizer