Audio-DSP mit Spartan 3-FPGA

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

von Benutzer:TheMason

Ziel

Ziel dieses Projekts ist es der Aufbau einer FPGA-basierten Plattform, mit der es möglich ist Synthesizer, Effektgeräte, Mischpulte oder gar ein Harddiskrecording-System zu realisieren.

Feature-Liste

Eigenschaften des Audioprozessors:

  • Oszillatoren
  • Biquads (Filter)
  • Addierer, Schalter, Verstärker (Multiplizierer)
  • Delays
  • Steuerung des Audioprozessors via SPI oder RS232
  • 4 Mono Ein- und Ausgänge
  • GPO (General-Purpose-Outputs) zur Konfiguration der Codecs

Übersicht

Overview wo uc.jpg

Basis des Audiosystems ist das Spartan-3-Development-Board von Xilinx. An diesem Board werden zwei Audio-Codecs angeschlossen, von denen einer als Master und der andere als Slave agiert. Optional kann noch ein Mikrocontroller angeschlossen werden, welcher den FPGA per SPI steuert. Da dieses Projekt mittlerweile recht umfangreich geworden ist, kann ich hier nur einen kurzen Umriss des Systems geben. Dabei beschränke ich mich auf die grobe Funktionsweise des Audioprozessors, erläutere die Schnittstelle (welche ich als Basis für weitere Projekte bereits nutze) und gebe einen kleinen Überblick über die Hardware.

Das System kann (sofern man zwei Audio-Codecs, von denen einer als Master, der andere als Slave arbeitet, angeschlossen und konfiguriert hat) direkt genutzt werden, da der DAP per RS232 gesteuert werden kann. Der Audioprozessor startet mit einem Stereo-Tiefpassfilter, das sich auf den ersten Codec bezieht, sodass man eine erste Demo hat (selbst wenn diese etwas unspektakulär ist)


Nachbau

Wer sich dieses System nachbauen möchte, benötigt zunächst ein FPGA-Board. Mit dem Spartan-3-Board von Digilent gestaltet sich der Nachbau einfach, weil die Programmier-Dateien für den FPGA direkt für dieses Board verwendet werden können. Nutzer anderer Boards (Xilinx) müssten zuerst die UCF-Datei für die Pins ihres jeweiligen Boards anpassen, und dieses Projekt neu synthetisieren (compilieren). Nutzer von Altera-Boards hingegen müssen die BlockRAM-Instanzen auf die Altera-Architektur anpassen (den Inhalt der RAMs dabei nicht vergessen :-). Vielleicht findet sich ja der eine oder andere der den VHDL Code für Altera-FPGAs portiert. Der eigentliche wichtige Teil eines Nachbaus ist der Codec-Teil. Dieses System verwendet zwar zwei Codecs, aber es kann auch mit einem gearbeitet werden. Als Codec kommt der TLV320AIC23B von Texas Instruments zum Einsatz. Diesen kann man als kostenloses Muster bei TI direkt bekommen. Des weiteren benötigt man noch eine handvoll Bauteile wie Kondensatoren, Widerstände und einen Quarz. (Ein Codec MUSS als Master laufen, sonst hat das System keine Audio-Clocks, da diese nicht vom FPGA generiert werden) Die Initialisierung des Codecs wird vom PC aus gemacht. Dazu dienen die 4 GPO-Leitungen auf dem B1-Verbinder. Da der Codec nur "halbes" SPI unterstüzt (man kann nur schreiben, nicht lesen) gestaltet sich die Initialisierung recht einfach. Die 4 GPO-Leitungen teilen sich folgendermaßen auf :

  • Chip-Select Codec 2
  • Chip-Select Codec 1
  • SPI Data Out
  • SPI Clock

Audio-Prozessor (DAP)

Overview dap core.JPG

Der FPGA beinhaltet in dem gesamten System einen Quasi-DSP. Quasi-DSP deshalb, da die Struktur im Gegensatz zu einem DSP bzw. Mikrocontroller keine Verzweigungen, Interrupts oder ähnliches zulässt. Der Audio-Prozessor besteht im wesentlichen aus 3 Teilen : einem Rahmen, einem SDSP (Small DSP)-Kern sowie einem Utility-Kern. Beide Kerne können theoretisch parallel arbeiten, da jeder Kern einen eigenen Zustandsautomaten und einen eigenen Microcode-Speicher besitzen. Diese Möglichkeit ist allerdings noch nicht implementiert.

Der SDSP-Kern besteht im wesentlichen aus einer MAC-Einheit, einem Speicher für Audiodaten, einem Koeffizienten-Speicher, einem Adressgenerator und mehreren Muxern, sowie dem schon angesprochenen Zustandsautomaten und dem Microcode. Weiterhin ist ein Hidden-Write- (bzw. Shadow Register) Mechanismus integriert, welcher ein "knackserfreies" Aktualisieren von Koeffizienten ermöglicht. Alle diese Komponenten werden vom Microcode aus gesteuert (genau wie bei einem Mikrocontroller). Mit diesem Kern ist es möglich, Audiosignale zu bearbeiten. Zu Den Bearbeitungsmöglichkeiten zählen in erster Linie das Verändern der Lautstärke, Mischen, Filtern (Biquad) sowie Laden und Speichern von Audiowerten.

Der Utility-Kern besteht aus einem Akkumulator (für DDS), einem Shaper, einem Adressgenerator, einem Wavetable-Speicher, einem Zufallszahlengenerator, einigen Muxern, (einem Adressgenerator für SRAM, einem SRAM-Controller; diese sind allerdings nur nutzbar, wenn man das ganze mit dem ISE 6.2 synthetisiert) und dem schon angesprochenen Zustandsautomaten und dem Microcode. Der Microcode steuert (genau wie beim SDSP-Kern) dabei die einzelnen Komponenten des Utility-Kerns. Dieser Kern ist für das Erzeugen von Audiosignalen zuständig, und erlaubt ein Audiosignal zu verzögern, sofern man die ISE-Version 6.2 verwendet (später dazu mehr). Als Wellenformen stehen Sägezahn, Rechteck (mit veränderbarer Pulsbreite), Rauschen sowie benutzderdefinierbare Wellenformen (Wavetable) zur Verfügung.

Der Rahmen besteht aus einem Zustandsautomaten, einem Programmspeicher, einigen Muxern, sowie einem doppelten I2S-Sender/Empfänger (für 2 Stereo Ein- und Ausgänge). In den Rahmen werden die beiden Kerne "eingehängt". Die Kerne werden vom Programmspeicher aus mit Daten versorgt, und vom Zustandsautomaten angesteuert. Der Programmspeicher (PMEM) ist als 512x32 Bit organisiert. Das heißt, dass ein Befehl im Programmspeicher 32 Bit an Informationen enthält und der Audioprozessor max. 512 Befehle umfassen kann.

SDSP-Core

Struktur des SDSP-Kerns

Der eigentliche Kern des DAPs ist die MAC-Einheit. Mit ihr werden die grundlegenden Operationen Multiplikation und Addition durchgeführt. Es ist eine 32x32-Bit-Einheit. Die Funktionsweise des Kerns ist eigentlich recht einfach. Die MAC-Einheit hat 2 Eingänge. Einer dieser Eingänge kann ein Audiosignal, ein Wert aus dem Audiospeicher (AMEM-BlockRAM) oder ein zuvor berechnetes Ergebnis sein. Der andere Eingang kann ein Koeffizient aus dem CMEM-BlockRAM oder eine Konstante (1.000, 0.000 oder -1.000) sein. Der Ausgang (32-Bit, hart geclippt) geht auf das AMEM-BlockRAM und zum Ausgangs-Clipping. Das Ausgangsclipping schneidet das Audiosignal auf 24-Bit zurecht. Die Adressen für die Speicher (AMEM und CMEM) werden im Addressgenerator erzeugt. Dieser wird von außen mit einer 8-Bit-Basis-Adresse gespeist und erzeugt einen Offset zu den Eingangsadressen. Er besitzt 2 setzbare Zähler und einige Multiplexer. Alle Steuersignale der Komponenten von einem weiteren aus BlockRAM (MMEM) versorgt. Weiterhin wird von außen eine Startadresse vorgegeben. Dadurch lassen sich quasi Opcodes mit von außen vorgegeben Parametern (Adressen) aufrufen. Das MMEM-BlockRAM wird nun einfach nur linear ausgelesen bis ein Stopbit gesetzt ist.



Util-Core

Struktur des Utility-Kerns

Beschreibung folgt


Opcodes des DAP

Diese 32 Bit eines Befehls teilen sich folgendermaßen auf :

  • 4 Bit = Opcode (für SDSP und Utility Kern gleich)
  • 2 Bit = noch leer
  • 1 Bit = Core Select (SDSP oder Utility)
  • 1 Bit = Ende des Programms
  • 4 Bit = Eingangsrouting (Kanal 1 - 4, Ergebnis SDSP-Kern, Ergebnis Utility-Kern)
  • 4 Bit = Ausgangsrouting (SDSP-Ausgang auf Kanal 1-4, Utility-Ausgang auf Kanal 1-4)
  • 8 Bit = Adresse 1 (bei SDSP für Audio-Memory, bei Utility-Kern für Datenspeicher)
  • 8 Bit = Adresse 2 (bei SDSP für Koeffizientenspeicher, bei Utility-Kern unbenutzt)

Das Eingangsrouting bestimmt, mit welchem Signal der gewählte Kern arbeiten soll. Dies können die Eingänge 1-4 aber auch ein vorher berechnetes Ergebnis des SDSP- bzw. Utility-Kerns sein. Das Ausgangsrouting bestimmt, von welchem Kern das Signal auf welchen Ausgang geroutet wird.

Die Opcodes des DAPs sind:

SDSP-Kern:

  • Biquad rechnen
  • Audiowert speichern
  • Audiowert laden
  • Move eines Wertes im Audiospeicher
  • Summe rücksetzen
  • Eingang zu Summe addieren
  • Wert aus dem Audiospeicher zu Summe addieren
  • Eingang zu Summe mischen (mit Lautstärkekoeffizient)
  • Wert aus dem Audiospeicher zu Summe mischen (mit Lautstärkekoeffizient)
  • Lautstärke

Utility-Kern:

  • Oszillator (DDS-Teil)
  • Waveshaper
  • Verzögerung

Der Ablauf eines Audio-Programms ist folgender:

Sobald ein neues Sample anliegt, wird die Abarbeitung des Programms von Adresse 0x0000 an im PMEM angestoßen. Es wird dabei jeweils ein Befehl geladen und Daten wie Opcode und Adressen liegen dabei an beide Kernen gleichermaßen an. Ist das Programm-Ende-Bit nicht gesetzt, so wird der jeweilige Kern (mit dem im Opcode angegeben Routing) angesteuert. Legt der betreffende Kern sein Ready-Signal auf 1, so wird der nächste Befehl abgearbeitet. Dieses Verhalten (Laden und Verteilen von Opcode-Daten sowie die Ablaufsteuerung, also das Ansteuern des Programms, Ansteuern der einzelnen Kerne, warten auf dessen Abarbeitung und das Programmende) wird vom Rahmen übernommen.

Speicherorganisation

Alle Speicher die vom DAP angesprochen werden, haben eine Wortbreite von 32 Bit, der Zugriff erfolgt aber ausschließlich über eine Breite von 8 Bit (Interface).

DAP

  • Programmspeicher (PMEM) 0x0000 - 0x07ff

SDSP

  • Audiospeicher (AMEM) von außen nicht zugänglich
  • Koeffizientenspeicher (CMEM) 0x2000 - 0x2023 (man "sieht" nur den Hidden Write -> später mehr dazu)
  • Microcodespeicher (MMEM) 0x4000 - 0x47ff

Utility-Core

  • Datenspeicher (DMEM) 0x6000 - 0x67ff
  • Wavetable-Speicher (WMEM) 0x8000 - 0x87ff
  • Microcodespeicher (UMEM) 0xa000 - 0xa7ff

Hidden-Write

Um bei Änderung der Koeffizienten Knackser zu vermeiden (die dadurch entstehen, dass der Koeffizient nur teilweise [durch 8-Bit-Zugriffe] geändert wird, währenddessen aber Audio trotzdem noch "weiterläuft" und mit "falschen" Zwischenwerten gerechnet wird), ist ein Mechanismus implementiert, der die zu ändernden Koeffizienten im Hintergund in den Speicher schreibt. Um diesen Mechanismus zu nutzen, müssen zuerst die Koeffizienten in interne Register geschrieben werden. Die Register (es sind 8 32-Bit-Register) liegen im Speicherbereich 0x2000 bis 0x201f. Die Speicherstelle 0x2020 gibt die Startadresse innerhalb des Koeffizientenspeichers an. Diese Adresse ist nur 8 Bit breit. Die Speicherstelle 0x2021 gibt an, wieviele der 8 Register übertragen werden sollen. Die Speicherstelle 0x2022 löst den Kopiervorgang aus. Hier reicht es, ein Dummy-Byte zu schreiben. Um den Kopiervorgang zu beenden (MUSS GEMACHT WERDEN, sonst können keine weiteren Koeffizientenupdates gemacht werden), schreibt man an Speicherstelle 0x2023 ebenfalls ein Dummy-Byte.

I/O Register

Es gibt noch einen 8-Bit breiten Adressbereich innerhalb des DAPs, mit dem der I2S-Teil stummgeschaltet werden kann. Weiterhin hat man die Möglichkeit, die Anzahl der Systemtakte pro Sample und die Anzahl der aktiven Systemtakte (also die Zeit die der Audioprozessor beschäftigt ist) zu ermitteln. Dadurch lässt sich eine Auslastungsanzeige des DAPs realisieren.

Interface

Um von außen nun ein Programm (bzw. Koeffizienten und Daten) zu laden, ist eine einfach zu handhabende und erweiterbare Schnittstelle implementiert. Die Schnittstelle kann per RS232 (fest eingestellt auf 115,2kBaud) oder per SPI (wird hardwaremäßig eingestellt) angesteuert werden. Die Schnittstelle in ihrer Gesamtheit ist schichtweise aufgebaut und beginnt mit einem Daten-Dispatcher. Dieser Daten-Dispatcher entscheidet (nachdem dieser selektiert wurde) mit dem ersten Byte, an welches angeschlossene Gerät der weitere Datenstrom geleitet wird.

Als angeschlossene Geräte sind im aktuellen Entwurf ein Gerät namens "StdIO" und der Audioprozessor verfügbar.

Das "StdIO"-Gerät steuert die 7-Segment-Anzeige (16-Bit-Hexadezimalanzeige oder 32-Bit-Einzelsegmentanzeige) sowie die 8 Leuchtdioden, und erlaubt es, die 3 Drucktaster sowie die 8 Schiebeschalter auszulesen.

Der Audioprozessor besteht (schnittstellenseitig) nur aus einer Speicherzugriffsschnittstelle. Diese Schnittstelle entscheidet mit dem ersten Byte (sobald es selektiert wurde), ob in den Speicher geschrieben, von diesem gelesen, ein I/O-Schreib- oder -Lesezugriff erfolgen soll. Die folgenden 2 Bytes (im Falle eines I/O-Zugriffs nur 1 Byte) bestimmen die Adresse und damit den Speicherbereich des Audioprozessors, auf den zugegriffen werden soll. Die Speicherschnittstelle besitzt einen Autoinkrementierer, mit dem fortlaufende Bytes einfach hintereinander geschrieben werden können, ohne dass jedes mal wieder der FPGA, das Gerät und die neue Adresse neu geschrieben werden müssen, was den Zugriff erheblich beschleunigt.

Ursprünglich basierte das System auf einem SPI-Interface. Dabei wurde die Chip-Select-Leitung als "globaler" Interface-Reset betrachtet, d.h. war die Leitung auf High, war der FPGA deselektiert und und alle Interface-Zustandsautomaten wurden im Reset gehalten. Erst mit dem Setzen dieser Leitung wurde der FPGA angesprochen. (erstes Byte -> Daten-Dispatcher, folgende Bytes gehen an das ausgewählte Gerät). Weiterhin hat SPI die Eigenschaft, dass mit jedem gesendeten Byte auch eines empfangen wurde. Der Umstand, dass RS232 weder eine Chip-Select Leitung benötigt noch eine synchrone Übertragung erzwingt, führt zu dem Umstand, dass man bei Nutzung von RS232 einige Befehle zusätzlich benötigt. Diese Befehle werden durch das Zeichen 0x1b (ESC) eingeleitet. Soll statt der "Spezialfunktion" das Byte 0x1b übertragen werden, so wird dieses einfach erneut gesendet. Soll die Chip-Select-Leitung gesetzt bzw. gelöscht werden, so wird die Sequenz 0x1b 0x00 (Selektieren) bzw. 0x1b 0x01 (Deselektieren) gesendet. Soll ein zuvor im Ausgangsregister gesetztes Byte gesendet werden, so muss die Sequenz 0x1b 0x02 gesendet werden.

Beispiele:

0x121b auf dem 7-Segment-Display per RS232 anzeigen:

  • - ESC 0x00 (FPGA selektieren)
  • - 0xf0 (StdIO selektieren)
  • - 0x00 (Hi-Byte der 7-Segment-Hex-Anzeige wählen)
  • - 0x12 (Wert 12)
  • - ESC 0x01 (FPGA deselektieren)
  • - ESC 0x00 (FPGA selektieren)
  • - 0xf0 (StdIO selektieren)
  • - 0x01 (Lo-Byte der 7-Segment-Hex-Anzeige wählen)
  • - 0x1b 0x1b (Wert 1b -> zu beachten: wenn der Wert 0x1b übertragen werden soll, muss dieser doppelt gesendet werden !!)
  • - ESC 0x01 (FPGA deselektieren)

Beispiel, um in den Programmspeicher des Audioprozessors an Adresse 0x0010 das Langwort 0x12233445 zu schreiben:

  • - ESC 0x00 (FPGA selektieren)
  • - 0xf1 (DAP selektieren)
  • - 0x00 (Speicher schreiben)
  • - 0x00
  • - 0x10 (Adresse 0x0010 -> PMEM-Adresse 0x010)
  • - 0x12 (Adresse 0x0010 -> 0x12)
  • - 0x23 (Adresse 0x0011 -> 0x23, autoincrement)
  • - 0x34 (Adresse 0x0012 -> 0x34, autoincrement)
  • - 0x45 (Adresse 0x0013 -> 0x45, autoincrement)
  • - ESC 0x01 (FPGA deselektieren)

Auslesen der 8 Schalter:

  • - ESC 0x00 (FPGA selektieren)
  • - 0xf0 (StdIO selektieren)
  • - 0x04 (Schalter auslesen)
  • - 0x00 (dummy byte -> überträgt Schalterstellung in Ausgaberegister)
  • - ESC 0x02 (Ausgaberegister übertragen, danach empfängt man die 8 Schalterstellungen binärcodiert)
  • - ESC 0x01 (FPGA deselektieren)

Der Datendispatcher (welcher mit dem ersten Byte nach dem Selektieren des FPGAs [0x1b 0x00] angesprochen wird) hat weiterhin einige nützliche Funktionen, die in ihrer Gesamtheit allerdings noch nicht ausführlich getestet wurden. Darunter sind Funktionen, mit denen Informationen über die an den Ports des Daten-Dispatchers angeschlossenen Geräte zu ermitteln. Diese Funktion kann dazu genutzt werden, um zu ermitten, welche Geräte im FPGA implementiert sind und an welchen Ports welche Geräte angeschlossen sind.

Anzahl der Ports des Daten-Dispatchers liefern:

  • - ESC 0x00 (FPGA selektieren)
  • - 0xed (Anzahl Ports lesen)
  • - 0x00 (dummy byte -> überträgt Inhalt des Ausgaberegisters)
  • - ESC 0x02 (Ausgaberegister übertragen, danach empfängt man 0x22)
  • - ESC 0x01 (FPGA deselektieren)

DAP-Modul-Schnipsel

Um mal "eben" mit dem DAP zu spielen, ein paar Schnipsel die sich recht leicht zu kompletten Funktionsblöcken zusammenschließen lassen. Es werden hier nur die RS232-Sequenzen mit einer kurzen Erklärung aufgelistet.

  • Dual Mono Biquad
  • ESC 0x00 - FPGA selektieren
  • 0xF1 - DAP auswählen
  • 0x00 0x00 0x00 - Memory Write (Adresse 0x0000 -> Program Memory)
  • 0x10 0x00 0x00 0x08 - Biquad mit Kanal 1 (0) rechnen (AMEM = 0x00;CMEM = 0x08) und auf Kanal 1 (0) ausgeben
  • 0x10 0xf0 0x08 0x10 - Biquad mit vorherigem Ergebnis (0xf) rechnen (AMEM = 0x08; CMEM = 0x10) und auf Kanal 1 (0) ausgeben
  • 0x01 0x00 0x00 0x00 - Audioprogramm Ende (wichtig !!!)
  • ESC 0x01 - DAP & FPGA deselektieren

Erklärung :

Der Aufbau des Opcodes 0x100008 deutet an, dass ein Biquad durchgerechnet werden soll. Das Eingangsregister 0 bedeutet, dass Kanal 1 des 1. Codecs verwendet wird. Das Ausgangsregister, welches nach Fertigstellung des Ergebnisses benutzt werden soll, ist 0 (-> Kanal 1 des 1. Codecs). Der Teil 0x00 0x08 bedeutet hierbei, dass die Biquad-Koeffizienten im CMEM ab Adresse 0x08 stehen. Die Audio-Zwischenwerte werden in den Audiospeicher AMEM ab Adresse 0x00 gelegt. Der zweite Opcode (0x10f00810) rechnet ebenfalls ein Biquad durch. Nur dass hier statt Kanal 1 des Codecs das voher vom SDSP berechnete Ergebnis verwendet werden soll (Kanal 0xf, wenn man so will). Ausgangsregister ist auch hier wieder Kanal 1. Da dieser Biquad unabhängig vom ersten (d.h. mit anderen Parametern) gerechnet werden soll, sind hier logischerweise auch andere Adressen für AMEM (0x08) und CMEM (0x10) angegeben. Die CMEM-Adresse ist dabei etwas unkritischer, da es ja durchaus sein kann, dass ein Audiosignal zweimal mit den selben Biquad-Werten gerechnet werden soll, bzw. unterschiedliche Kanäle mit den selben Biquad-Werten, z.b. bei einem Stereo-Equalizer. Kritischer ist allerdings die Verwendung der AMEM-Adresse. Diese sollte für jede Operation (sofern AMEM denn verwendet wird) unterschiedlich sein, vor allem bei der Berechnung von Biquads. Dies hat den Grund, dass bei Operationen, die dieselben AMEM Adressen haben, die vorher berechneten Werte überschrieben werden. Dies ist bei Biquads gaanz böse (kann u.U. SEHR laut werden), und vom Ergebnis her nicht vorhersagbar.

Hardware

Fpga ext board schematic no uc.JPG

Wie eingangs erwähnt, benötigt das System eine (bzw. zwei) Audio-Codecs. Im aktuellen Schaltplan wird auf einen Mikroprozessor verzichtet. Dieser diente im System primär zu Initialisierung der Codecs. Dieser Vorgang kann nun vom PC aus gesteuert werden, da in der neuen ISE-6.2-Version 4 Leitungen herausgeführt wurden, welche per RS232 gesetzt und gelöscht werden. Wer das System nachbauen möchte, kann entweder die TLV320AIC23B-Codecs oder auch beliebige andere Codecs verwenden, solange einer als Master und der andere als Slave arbeitet und beide auf den I2S-Modus mit 64FS und 20-Bit-Wortlänge eingestellt sind. Die Initialisierung dieser Codecs muss dann aber separat vorgenommen werden (wobei man dann wahrscheinlich nicht um einen uC drumrum kommt). Um das System zu testen (Programme und Koeffizienten in den DAP einzuspielen), wird lediglich eine serielle Schnittstelle verwendet. Wer will, kann aber genausogut den SPI-Modus verwenden und den DAP direkt von einem Mikrocontroller aus steuern. Zur Auswahl der verwendeten Schnittstelle (RS232 oder SPI) wird Pin 13 des B1-Connectors benutzt. Liegt dieser Pin auf GND, so wird der FPGA per RS232 gesteuert. Liegt dieser Pin auf 3.3V, so wird der FPGA per SPI gesteuert.

Hier der Schaltplan meines verwendeten Audio-Boards.

Hier noch die Pinbelegung des B1-Erweiterungssteckers:

  • 01 GND
  • 02 VCC 5V
  • 03 VCC 3.3V
  • 04 N.C.
  • 05 SPI_CS - Chip Select (von uC nach FPGA)
  • 06 N.C.
  • 07 SPI_DI - SPI Data In (von uC nach FPGA)
  • 08 BCLK - Bit Clock (von Master Codec)
  • 09 SPI_CLK - SPI Clock (von uC nach FPGA)
  • 10 LRCLK - LR-Clock (von Master Codec)
  • 11 SPI_DO - SPI Data Out (von FPGA nach uC)
  • 12 SDOUT1 - zum D/A Wandler (Codec) 1
  • 13 IF_SEL - Interface Select (GND = RS232; VCC3.3 = SPI)
  • 14 SDIN1 - vom A/D Wandler (Codec) 1
  • 15 RXD_OUT - RS232 Signal vom MAX232 zum uC
  • 16 SDIN2 - vom A/D Wandler (Codec) 2
  • 17 TXD_IN - RS232 Signal vom uC zum MAX232
  • 18 SDOUT2 - zum D/A Wandler (Codec) 2
  • 19 GPO 3 - Chip-Select Codec 2
  • 20 N.C.
  • 19 GPO 2 - Chip-Select Codec 1
  • 20 N.C.
  • 19 GPO 1 - SPI-Data out
  • 20 N.C.
  • 19 GPO 0 - SPI-Clock Out
  • 20 N.C.

Nexys Board

Im SVN-Repository (s.u.) gibt es eine Version des DAPs für das Nexys-Board. Diese ist voll SW-kompatibel zum alten Spartan-3-Board (allerdings z.Zt. nur über RS232 steuerbar). Neu bei der Version ist, dass das Speicherinterface generisch ausgelegt wurde und ein einfacher SRAM-Controller für das PSDRAM des Nexys-Boards geschrieben wurde. Durch das generische Interface ist es möglich, andere Speicherarten anzubinden. Der verwendete Codec ist wie schon im bisherigen Projekt der TLV320AIC23B. Dieser wird via RS232 (6-pin Port A des Nexys-Boards) über die GPO Leitungen (6-pin Port D des Nexys-Boards) initialisiert. Die eigentlichen Datenleitungen des Codecs liegen an Port B (BCLK, LRCLK, DIN, DOUT).


Diese Version ist voll lauffähig (wurde mit den Demos getestet). Die Pinbelegung für die RS232 und den Audio-Codec ist wie folgt:

Header A : RS232-Schnittstelle

Pin 1 : RxD von MAX232
Pin 2 : TxD von MAX232
Pin 3 : -
Pin 4 : -
Pin 5 : GND
Pin 6 : VCC (3.3V/5V für MAX232/MAX3232)


Header B : I2S-Schnittstelle für einen Codec

Pin 1 : BitClk
Pin 2 : L/R Clk
Pin 3 : SDIN
Pin 4 : SDOUT
Pin 5 : GND
Pin 6 : VCC (3.3V für den Codec)


Header D : Codec-Konfiguration via SPI

Pin 1 : Codec 2 CS
Pin 2 : Codec 1 CS
Pin 3 : Codec SPI Data
Pin 4 : Codec SPI Clk
Pin 5 : GND
Pin 6 : VCC

DAP mit selbstgelötetem FPGA-Board

Auf einen Beitrag von Thomas Pototschnig hin bin ich auf sein selbstentworfenes Spartan-3-FPGA-Board (Grafikkarte) aufmerksam geworden. Thomas hat mir die Erlaubnis gegeben, dieses Board für den DAP zu verwenden und die Schaltpläne hier zu veröffentlichen. Nachdem ich von ihm noch einige Vorversionen (nur die Platinen) ergattern konnte und diese erfolgreich aufgebaut (mit Spartan 3-200 und -400) habe, bin ich von diesem Board echt begeistert. Danke nochmals.

FPGA-Board.jpg

Hier Schaltplan und Layout.

Media:miniFPGA-Board.zip

Das Board ist zweiseitig und die "schlimmsten" zu lötenden Bauteile sind lediglich der FPGA (QFP-144) und die beiden RAMs (SOJ36, ekelig). Der Rest ist recht einfach. Auch die Inbetriebnahme des Boards gestaltete sich problemlos.

Den Quellcode für den DAP musste ich etwas ändern und abspecken. Durch den ineffizienten VHDL-Code der MAC-Einheit gestaltete es sich schwierig, den Entwurf synthetisierbar zu machen. Das Synthetisieren auf einem FT256 gestaltete sich einfacher. Hier ist noch dergestalt Handlungsbedarf, dass die MAC-Einheit überarbeitet werden muss. Der abgespeckte Entwurf läuft auf dem FPGA-Board mit einem Spartan 3-400 sowie auf einem Spartan 3-200. Den Audio-Codec, das FPGA Board, einen AVR und noch etwas IO-Kram habe ich auf eine Lochrasterplatine aufgebaut. Was noch fehlt, sind MIDI- und SD/MMC-Karten-Schnittstellen. Dann hat man eine schöne Plattform für Synthesizer und Effektgeräte.



Anmerkung

Da, wie schon gesagt, das Projekt komplett auf meinem "Mist" gewachsen ist, wird es wohl noch eine Weile dauern, bis alles, was den DAP betrifft, hier in diesem Artikel (und auch in einem Dokumentations-PDF) eingearbeitet ist. Ich werde (sofern ich Zeit dazu habe) noch ein Delphi-Programm mit Sourcecode einstellen, welches den DAP richtig nutzbar macht, so dass man dann direkt damit "spielen" kann. Eine umfangreiche und vollständige Dokumentation würde momentan einfach zu viel Zeit in Anspruch nehmen, und ich möchte langsam das Projekt vorstellen, um Anregung, Kritik und Verbesserungsvorschläge ernten zu können. Ich hoffe, weitere Leute zu finden, um diesem Projekt noch mehr Leben und Möglichkeiten einhauchen zu können.

Fotos

Ursprüngliche Version:

Spartan.3-Board und Expansion-Board
Expansion Board


Nexys-Board:

Nexys-Board mit 1 Audio-Codec
Nexys-Board mit Lochraster-Board und 2 Audio-Codec-Boards (siehe Artikel Audio Codec Board)
2 Audio-Codec-Boards (siehe Artikel Audio Codec Board)


Aufbau von Benutzer:Andreas:

Nexys + Breadboard + 1 Audio Codec Board


Aufbau des DAPs mit FPGA-Board (entworfen von Thomas Pototschnig) auf Lochraster an AVR, Codec und weiterer IO


Synth Board. DAP mit AVR,Codec, MIDI-Interface, RS232 (schaltbar) und LCD


Synth Board. Komplettansicht


Synth Board. Synth-Board


Selbstgeroutetes DAP-Board


Selbstgeroutetes DAP-Board


Selbstgeroutetes DAP-Board auf Trägerplatine


DAP-Board mit Touch-Display Seitenansicht


DAP-Board mit Touch-Display

Diese Version des DAP hat ein Grafikdisplay incl. Touchpanel. Die Ansteuerung übernimmt der FPGA. Dort ist einer kleiner "Grafik-Prozessor" integriert, der das Update des Displays und das Kopieren der Bitmaps übernimmt.


DAP Synthesizer Ansicht 1.jpg

Synth-Board. Komplettansicht in einem Cherry-Tastaturgehäuse (wie dafür gemacht :-)) im Synthesizer-Stil


Fertige Version des DAP als Synthesizer

Der komplette Synthesizer mit schicker Frontplatte und passendem (oben schon erwähnten :-)) Cherry-Tastatur-Gehäuse.


Heue Hardwareversion der DAP-Hauptplatine

Diese Version beinhaltet folgendes : :-)

- Xilinx XC3S400
- ATmega2561
- 16 MByte (8Mx16) SDRAM
- µSD Card Slot
- AT45DB321 DataFlash
- 24C512 EEProm
- TLC320AI23B Audio Codec mit Kopfhörer Ausgang
- CS5343 A/D Wandler
- CS4344 D/A Wandler
- MIDI
- RS232
- etlichen IO-Pins vom AVR und FPGA
- 2 separaten Clock-Oszillatoren (nicht bestückt)

... und weiterem Kleinkram (Level-Shifter, LDO, Platform-Flash, usw ... und vielen 100nF-Kondensatoren)

Ideal zum Aufbau einer Audioplattform.



Audio-Demos

Ein EQ-Demo mit rosa Rauschen. Klingt wie eine Meeresbrandung.

Media:eq_demo1.zip

Der DAP als Synth. Der DAP wird komplett vom PC aus gesteuert (Hüllkurve, Sequencer und Filterberechnung werden im PC gemacht).

Media:synthdemo1.wav.zip


MC505-Demos

Die folgenden Demos stammen von meiner Roland MC505 Groovebox. Es wird einfach nur ein Werkspreset abgespielt und durch den DAP gejagt.


Synth-Board Audio-Demos

Die folgenden Demos stammen vom DAP in Verbindung mit einem AVR, der die Filterkoeffizientenberechnung sowie eine komplette Synthesizersteuerung beinhaltet, also quasi einen Synthesizer aus dem DAP macht (inkl. MIDI-Steuerung).

MIDI-Sequenz und Tiefpassfilter (Filter und Modulation über MIDI gesteuert) :

Media:Dap-syn-demo-01.mp3

Dieselbe MIDI-Sequenz mit Hochpassfilter (Filter und Modulation ebenfalls über MIDI gesteuert) :

Media:Dap-syn-demo-02.mp3

Eine eher Techno-ähnliche Demo, welche die Auflösung des Systems (DAP+AVR+MIDI) ein wenig zeigt.

Media:Dap_syn_demo_03.mp3

Delphi Tools

Um den DAP nutzbar zu machen benötigt man entweder ein uC Programm oder ein PC Programm. Da das verwenden von PC-Programmen einfacher fürs Spielen und Experimentieren ist, werde ich hier im Laufe der Zeit kleine Demo-Programme aber auch komplette Front-Ends für den DAP reinstellen. Die Delphi-Programme sind allesamt in Turbo-Delphi geschrieben und die dazugehörigen Quellcodes werden ebenfalls im Laufe der Zeit geuploaded. Ich werde allerdings zuerst noch das Feature des Konfigurierens der Codecs vom PC aus einbauen. Nachtrag zum Konfigurieren des Codecs : Prinzipiell funktioniert es, allerdings ist das mit häßlichen Nebengeräuschen verbunden, da ich bei jeder Änderung der Lautstärke im Codec, diesen auch Resetten muß, da sonst immer beide Codecs beschrieben werden, was unschön ist. Warum dies so ist kann ich leider nicht sagen, da ich keine Möglichkeit habe die SPI-Leitungen mitzusniffen (bräuchte dafür einen kleinen LA, den ich nicht habe).


Es folgen noch der Quellcode für den Mischer (hab ich gerade nicht zur Hand) und weitere Demos (ein Synthesizer und eine 4x4 Patchbay mit EQ und was mir sonst noch einfällt. Dann natürlich mit Source-Codes). Anhand dieser Beispiele wird auch eine grobe Doku erstellt.

SVN-Repository

svn co svn://mikrocontroller.net/audiodsp

Ein automatisch aktualisiertes Paket mit den Daten aus dem Repository gibt es unter http://www.mikrocontroller.net/download/audiodsp-snapshot.tar.gz.


Änderungen

  • 12.07.2007: Es wurde ein generisches Speicherinterfaces implementiert, welches Wartezyklen im DAP erlaubt. Dadurch kann man auf die jeweilgen Speicher des Boards eingehen. Z.Zt. ist nur eine einfaches Speicherschnittstelle für den asynchronen Betrieb des PSDRAM des Nexys-Boards implementiert. Die Schnittstelle ermöglicht den Anschluss eines RAM-Controller, welcher z. B. ein Quasi-Multiport-RAM darstellt. Getestet wurde der Stand mit dem Nexys-1000-Board.

To do

  • nähere Zukunft
    • Einen Konfigurationsdialog in die Demo-Programme einarbeiten mit denen man mit den Codecs etwas spielen kann (Line-In Level, Mikrofon-Level, Bypass, Head-Phone Volume) tlw. erledigt. Funktioniert aber nicht richtig, und daher noch nicht eingebaut. Quellcodes dazu sind vorhanden.
    • Doku anhand der Demo-Programme erstellen
    • C-Code schnipsel erstellen
  • fernere Zukunft
    • Front-End des DAPs machen, mit dem sich DAP-Programme erstellen lassen, der Koeffizienten-, Daten- und Wellenform-Speicher beschrieben und gelesen werden kann, der Mikro-Code editierbar gemacht wird und noch ein paar Sachen mehr machbar sind
    • weitere Module für den Rahmen (HDD-Core, weitere Routing-Möglichkeiten innerhalb der bisherigen Cores SDSP und Util)

Diskussion

Falls Interesse an einer Sammelbestellung für die Platinen und Bauteile besteht