ESP32-Controller sind beliebte Lösungen, die in Tausenden von IoT-, Smart-Home- und anderen Fernsteuerungsprojekten eingesetzt werden. Der ESP32 verfügt außerdem über eine gute I2S-Schnittstelle, die zum Ausgeben und Empfangen digitaler Audiosignale verwendet werden kann. In Kombination mit einem I2S-DAC, einem I2S-ADC und einer SD-Karte sind viele Arten von Audioprojekten möglich. In diesem Projekt integrieren wir all dies zusammen mit einem nRF24-Transceiver zum Senden und Empfangen von (Audio-)Daten auf einer lötfreundlichen Leiterplatte. Im ersten Teil dieser Artikelserie präsentieren wir das Blockdiagramm, die Schaltung und die Demo-Software.

Die Wahl des ESP32

Die beliebten ESP32-Controller sind preiswert, schnell und einfach zu programmieren – zum Beispiel mit der Arduino-IDE. Ausgestattet mit WLAN werden sie in Tausenden von IoT-, Smart-Home- und anderen Fernsteuerungsprojekten eingesetzt, und wir können die Elektor-Projekte dieser Art kaum zählen. Allerdings verfügen ESP32-Controller auch über eine integrierte, gute I2S-Schnittstelle, mit der Audio-Streams digital ausgegeben und empfangen werden können. (Siehe Abschnitt „I2S-Schnittstelle“ unten.) Zum Abspielen von Audio benötigen Sie zusätzlich einen I2S-DAC, der die I2S-Daten vom ESP32 aufnimmt und in ein analoges Signal umwandelt. Umgekehrt benötigen Sie zum Aufnehmen von Audio einen Audio-ADC mit einer I2S-Schnittstelle. Für dieses Projekt kombinieren wir ein auf ESP32-S3 basierendes Entwicklungsmodul mit einem I2S-ADC/DAC-Breakout-Board auf einer Trägerplatine. Außerdem integrieren wir eine Option zum Anstecken eines Nordic nRF24-Funkmoduls, um digitale (Audio-)Daten zu senden und zu empfangen. Eine SD-Karte, mehrere Erweiterungsstecker und verschiedene Stromversorgungsoptionen vervollständigen das Audio-Transceiver-Projekt.

Audio transceiver board project
Das Audio-Transceiver-Board-Projekt

I2S-Schnittstelle

Die I2S-Schnittstelle und das Protokoll zur Übertragung digitaler Audiodaten (hat nichts mit I2C zu tun) sind im Internet [9] gut dokumentiert, sodass wir hier nicht viele Sätze zu den Grundlagen verlieren müssen. Audiodaten werden bitweise über eine Leitung übertragen, wobei eine weitere Leitung als Bit-Clock dient. Eine andere Leitung trennt die Daten für den linken und den rechten Audiokanal. Sie benötigen also mindestens drei Leitungen zwischen Mikrocontroller und I2S-DAC oder -ADC (zusätzlich zu VCC und GND zur Versorgung der Chips).

Um sicherzustellen, dass der Mikrocontroller und der DAC bzw. ADC synchron getaktet werden, gibt es eine weitere Verbindung, den sogenannten „Master Clock“. Viele Quellen im Internet und auch meine eigene Erfahrung zeigen, dass beim Einsatz eines ESP32 der ESP32 als Clock-Master und der DAC oder ADC als Slave agieren sollte, nicht umgekehrt. Deshalb muss das in diesem Projekt eingesetzte I2S2-Pmod-Modul (mit DAC und ADC) als Slave konfiguriert werden, mit einer Jumperverbindung an der richtigen Stelle.  

Abonnieren
Tag-Benachrichtigung zu ESP32 jetzt abonnieren!

Anwendungsfälle

Dieses Audio-Transceiver-Board ist hauptsächlich für Audioanwendungen gedacht, kann aber auch zum Abtasten/Ausgeben/Speichern/Übertragen/Empfangen anderer Signale und Daten verwendet werden. Hier sind einige Anwendungsfälle, von denen wir einige in kommenden Artikeln umsetzen werden.
 

  • Audio-Player, der Dateien von der SD-Karte abspielt (siehe Demo-Software unten)
  • Audio-Recorder
  • Audio-Prozessor (Audio abtasten, Daten verarbeiten und wieder ausgeben)
  • Drahtloser Audio-Sender/Empfänger über WLAN oder ESP-NOW
  • Drahtloser Audio-Sender/Empfänger über Nordic nRF24
  • Datenlogger: Sensoren über SPI/I2C angebunden, Daten werden auf SD-Karte gespeichert
  • Drahtloser Sensorknoten: Übertragung von Sensordaten über WLAN oder nRF24
  • Niederfrequenz-Signale erzeugen oder messen

 

PCB1-V3 - ESP32 Audio Transceiver
Abbildung 1: Die Blöcke und Anschlüsse des ESP32-Audio-Transceivers.

Hauptblöcke

Die Blöcke und Anschlüsse des ESP32 Audio Transceivers sind in Abbildung 1 zu sehen.

ESP32-S3-DevKit-C
Das Herzstück des Audio-Transceiver-Projekts ist das ESP32-S3-DevKit-C-Board mit 44 Pins; es wird in der Mitte unserer Platine eingesteckt. Im Wesentlichen integriert das DevKit-C-Board ein ESP32-S3-WROOM-Modul (mit einem 2-Kern-ESP32-S3-Prozessor), benutzerfreundliche DIL-Erweiterungsstecker und zwei USB-Anschlüsse für Programmierung und Stromversorgung (siehe Abbildung 2). Bitte beachten Sie, dass es mehrere pin-kompatible S3 DevKit-C-Varianten auf dem Markt gibt. Manche verfügen über ein WROOM-Modul mit gedruckter PCB-Antenne, andere über ein WROOM-Modul mit Anschluss für eine externe Antenne. Letzteres ermöglicht es, unsere Trägerplatine zusammen mit dem DevKit in ein Metallgehäuse einzubauen und dennoch die WLAN-Funktionen des ESP32 zu nutzen.

The DevKit-C board integrates a ESP32-S3-WROOM SoC
Abbildung 2: Das DevKit-C-Board integriert ein ESP32-S3-WROOM-SoC
und zwei USB-Anschlüsse für Programmierung und Stromversorgung. Links eine Version
mit PCB-Antenne und 1" Breite. Rechts die Version aus dem Elektor-Shop,
mit 0,9" Breite und Anschluss für eine externe WLAN-Antenne.


Da es S3-DevKit-C-Varianten mit einer Breite von 0,9" und 1" gibt, haben wir unsere Trägerplatine für beide passend gemacht, mit einem zusätzlichen Pin-Header. Bei Verwendung eines 0,9" breiten ESP32-S3-DevKits kann der äußere Pin-Header (J3) ebenfalls als Erweiterungsstecker genutzt werden.

Ein S3-DevKit-C mit PCB-Antenne ist für etwa 8 € erhältlich; es lässt sich einfach einstecken und austauschen. Das Einzige, was gelötet werden muss, sind zwei Reihen von Steckleisten. Allerdings denken wir bereits über eine zweite Version unserer Platine nach, bei der das S3-WROOM-Modul direkt verlötet wird, was Platz und weitere Kosten spart.

I2S DAC/ADC
Es gibt viele I2S-Breakout-Boards zum Abtasten und Abspielen von Audio. Letztendlich haben wir uns für ein Digilent I2S2 Pmod Modul entschieden, das einen Cirrus CS4344 DAC (bis zu 192 kHz/24 Bit) und einen Cirrus CS5343 ADC (bis zu 96 kHz/24 Bit) enthält, beide an Stereo-Klinkenbuchsen angeschlossen (Abbildung 3). Im Grunde sind es zwei Breakout-Boards in einem. Am 2x6-Stecker sind zwei unabhängige I2S-Schnittstellen zugänglich, eine zum Ausgeben und eine zum Aufnehmen von Audio (siehe Textbox I2S-Schnittstelle). Die VCC- und GND-Pins für die Stromversorgung sind ebenfalls doppelt vorhanden. Ungewöhnlich ist, dass dieser 2x6-Stecker horizontal steht, aber das entspricht der Pmod-Spezifikation von Digilent. Um dieses Modul auf unsere Platine zu stecken, muss eine abgewinkelte 2x6-Buchse eingelötet werden.

Digilent I2S2 Pmod module: Audio transceiver board project
Abbildung 3: Das Digilent I2S2 Pmod-Modul enthält einen Cirrus CS4344 DAC
und einen Cirrus CS5343 ADC, beide an Stereo-Klinkenbuchsen angeschlossen.
Das I2S2 Pmod-Modul ist bei weitem nicht das günstigste I2S-Breakout-Board, das man kaufen kann, aber die Audioqualität ist ziemlich gut und es funktioniert hervorragend mit dem ESP32 als I2S-Master. Es ist auch keine Konfiguration nötig, bevor man Audio abspielen oder abtasten kann.

Auf unserer Platine ist der 2x6-Pmod-Anschluss auf GPIO35 bis GPIO40 sowie GPIO47 und GPIO48 geführt. Natürlich steht es Ihnen frei, hier auch andere Pmod-Module (Stromsensoren, Audioverstärker, ...) anzuschließen oder ein eigenes kleines Erweiterungsboard mit 2x6-Stecker im üblichen 2,54-mm-Raster zu bauen.

nRF24-Transceiver
Neben den WLAN- und ESP-NOW-Fähigkeiten des ESP32 wollten wir eine dritte Option anbieten, insbesondere für sehr geringe Latenz beim Senden/Empfangen eines kontinuierlichen Audio-Streams. Nordics proprietäres Funkprotokoll für ihre nRF24-Transceiver-Module ist sehr schnell. Sie können Pakete in weniger als 1 ms vom Sender zum Empfänger übertragen. Die nRF24 Chips werden ebenfalls in vielen IoT-Projekten eingesetzt, da es recht günstige Breakout-Boards gibt und gute (Arduino-)Bibliotheken vorhanden sind. Module mit nRF24, Antennenverstärker und Antennenanschluss lohnen sich besonders. Unsere Erfahrung zeigt, dass die Reichweite in Gebäuden besser als bei WLAN ist. Ein Vorteil ist, dass die Chips in eigenen 1-MHz-Kanälen senden, und nicht direkt in den stark frequentierten WLAN-Kanälen. Ein kleiner Nachteil ist die maximale Payload-Größe von 32 Bytes und die tatsächliche Datenrate in realen Anwendungen, die weit unter der nominalen Rate von 2 Mbit/s liegt. Darauf gehen wir im nächsten Artikel noch ein.

Der nRF24 wird über eine SPI-Schnittstelle plus zwei Digitalleitungen (Chip Enable und Interrupt) angesprochen. Für den 2x4-Stecker gibt es eine Art Standard, sodass Sie ein nRF24-Modul Ihrer Wahl verwenden können. Wir empfehlen das E01-ML01DP5 von Ebyte, das einen SMA-Antennenanschluss und einen Antennenverstärker integriert hat (Abbildung 4). Unsere Trägerplatine ist auf dieses Modul vorbereitet – der Antennenanschluss sitzt am Rand, sodass es perfekt in ein Kunststoff- oder Metallgehäuse passt.

 

Audio transceiver board 4
Abbildung 4: Das nRF24-Modul von Ebyte hat zusätzlich zum Transceiver-Chip
einen SMA-Antennenanschluss und einen Antennenverstärker integriert.
Da der 2x4-Stecker auf unserer Platine auf die SPI-Schnittstelle des ESP32 geführt ist, können Sie hier problemlos auch andere SPI-Module anschließen – zum Beispiel einen Sensor.

SD-Karten-Slot
Die Platine enthält einen microSD-Karten-Slot, der eine komfortable lokale Speicherung für aufgezeichnete Daten, Konfigurationsdateien oder Audioinhalte bietet. Er ist über die SPI-Schnittstelle (MOSI, MISO, SCK und eine eigene CS-Leitung) mit dem ESP32-S3 verbunden und kann einfach mit den weit verbreiteten Arduino SD- oder SdFat-Bibliotheken verwendet werden. Der Slot ist auf der Oberseite der Platine montiert und leicht zugänglich. Entkopplungskondensatoren befinden sich in der Nähe der Stromversorgungspins für Stabilität beim Schreiben. Da sich die SD-Karte den SPI-Bus mit anderen Peripheriegeräten wie dem nRF24-Modul teilt, ist im Code auf eine korrekte Chip-Select-Steuerung zu achten, um Konflikte zu vermeiden.

Erweiterungsstecker

Die Platine verfügt über mehrere Erweiterungsstecker (J7 bis J10), an denen unbenutzte GPIOs des ESP32-S3 herausgeführt sind. Dadurch können leicht weitere Sensoren oder Module angeschlossen werden. Die Stecker eignen sich für allgemeine Zwecke, aber auch ideal für Bedienelemente wie Displays (z. B. OLED via I²C), Taster, LEDs oder IR-Empfänger. Jeder Stecker bietet außerdem Strom- und Masseanschlüsse für einfache Verdrahtung.

Stromversorgungsoptionen
Die Platine kann entweder über eine Standard-DC-Buchse oder eine Schraubklemme mit 5,08 mm Raster betrieben werden – je nach Aufbau. Ein TLV76733-Linearregler senkt die Eingangsspannung (bis zu 16 V) auf 3,3 V ab, die den ESP32-S3 und die angeschlossenen Module versorgt. Dieser LDO liefert bis zu 1 A und bietet hohe Präzision (±1 %), niedrigen Eigenverbrauch und Schutzfunktionen wie Übertemperatur- und Überstromabschaltung. Seine hohe PSRR (70 dB bei 1 kHz) sorgt für Stabilität auch bei störbehafteter Versorgung, und der geringe Dropout erlaubt einen effizienten Betrieb bis nahe 3,3 V Eingang.

Eine weitere Option ist die Stromversorgung über einen der USB-Anschlüsse des S3-DevKit-C-Moduls. Es ist auch möglich, die Platine über die DC-Buchse zu betreiben und gleichzeitig per USB mit dem PC zu verbinden – z. B. für den seriellen Datentransfer.

Der Schaltplan

Nachdem wir die anzuschließenden Module vorgestellt haben, ist der Schaltplan leicht verständlich. Das Schaltbild (Abbildung 5) zeigt ein Mikrocontroller-basiertes Audio-Transceiver-System rund um das ESP32-S3-DevKit-C-Entwicklungsboard. Die Stromversorgung erfolgt über einen 12-V-Eingang an Anschluss J1, der mit einem Low-Dropout-Spannungsregler (IC1) auf 3,3 V geregelt wird. Diese 3,3-V-Leitung versorgt das ESP32-S3-Board sowie alle anderen Niederspannungskomponenten, wobei mehrere Entkopplungskondensatoren (C1 bis C4) für Störunterdrückung und Stabilität sorgen. Das ESP32-S3 dient als zentrale Recheneinheit und verbindet sich über seine GPIOs mit verschiedenen Peripheriegeräten.

Schematic for the project
Abbildung 5: Der Schaltplan (PDF-Link) zeigt ein MCU-basiertes System rund um das ESP32-S3-DevKit-C-Board.

Drahtlose Kommunikation wird über das nRF24L01-Modul (MOD1) ermöglicht, das per SPI-Leitungen mit dem ESP32 verbunden ist: MISO, MOSI, SCK, CSN, CE und IRQ. Diese Leitungen sind mit 100-Ω-Widerständen (R1 bis R3) und einem Bypass-Kondensator (C6) zum Stabilisieren der Versorgung geschützt. Für die Speicherung ist ein MSD-11-A-microSD-Sockel (J4) über SDIO/SPI-Leitungen angebunden, mit zusätzlichen Leitungen für Kartenerkennung und Schreibschutz.

Das System bietet Peripherieerweiterung über mehrere GPIO-Header (J7 bis J10), die jeweils Strom, Masse und Signalleitungen für externe Displays, Tasten oder Geräte bereitstellen. Eine I2C-Schnittstelle ist über Grove (J6) und Qwiic-kompatible (J5) Stecker zugänglich, um digitale Sensoren und Module einfach einzubinden. Außerdem ist ein Pmod-Anschluss (MOD2) vorhanden, für Digilent-kompatible Erweiterungsmodule.

Abonnieren
Tag-Benachrichtigung zu Audio jetzt abonnieren!

Die Platine

Das PCB-Layout ist um das ESP32-S3-DevKitC organisiert (siehe Abbildung 6). Die Stecker befinden sich auf der Oberseite der Platine, einschließlich Netzteilbuchse, Schraubklemme, Qwiic-Anschluss und SD-Karten-Slot. Der Pmod-Anschluss ist an der Unterseite der Platine, um verschiedene Pmod-Module anschließen zu können. Das nRF24-Modul ist am rechten Rand platziert, und vier Stecker (J7 bis J10) befinden sich im mittleren rechten Bereich, um zusätzliche GPIOs für externe Module bereitzustellen. Die I2C-Leitungen sind kurz und schmal für typische Kommunikationsgeschwindigkeiten, und die Versorgungsleitungen sind breiter, um den Strom zu tragen; eine Massefläche bedeckt den Großteil der Platine.

PCB layout
Abbildung 6: Das PCB-Layout ist um das ESP32-S3-DevKitC organisiert.

Das Gehäuse

Die Platine des Audio-Transceiver-Projekts passt in ein 100 × 97 × 40 mm Aluminiumgehäuse mit Schiebeddeckel. Es kann direkt in die Führungsschienen eingesetzt werden, und der Deckel ermöglicht einfachen Zugang zum Inneren. Metallgehäuse bieten mechanischen Schutz und Abschirmung, schirmen aber auch Hochfrequenzsignale wie WLAN und Bluetooth ab. Das Metall wirkt als Faraday-Käfig, daher funktioniert die Funkkommunikation mit der PCB-Antennen-Version des ESP32-DevKits nicht – es sei denn, man lässt eine Öffnung. Deshalb ist der Antennenbereich des ESP32-S3 am unteren Rand der Platine positioniert, sodass man leicht eine Aussparung im Gehäuse schaffen kann. Bei Verwendung eines ESP32-S3-DevKit mit Antennenanschluss – z. B. aus dem Elektor-Shop – kann eine externe Antenne an der Front- oder Rückseite des Gehäuses montiert werden.

Der SMA-Anschluss des nRF24-Moduls ist so platziert, dass ein Loch in die Gehäusefront gebohrt werden kann, um die Antenne extern zu montieren (siehe Abbildung 7).
Audio transceiver board 7
Abbildung 7: Der SMA-Anschluss des nRF24-Moduls ist so positioniert,
dass ein Loch in die Gehäusefront gebohrt werden kann, um die Antenne extern zu montieren.
So bleibt das Modul auch im Metallgehäuse funktionsfähig.

Demo-Software

Wie gesagt, in den nächsten Ausgaben stellen wir Anwendungen und Weiterentwicklungen vor. Zum Beispiel präsentieren wir in der kommenden „Wireless“-Ausgabe von Elektor im September 2025 Software zum Senden und Empfangen von Audio. Aber wir wollten diesen Artikel zum Audio-Transceiver-Board nicht ohne eine erste Demo-Software abschließen.

Die Demo-Software ist ein einfacher WAV-Audio-Player. Sie können sie von der Labs-Seite zum Audio-Transceiver-Board herunterladen. Beim Start liest der ESP32 die Dateien auf der SD-Karte (keine Unterverzeichnisse) und erstellt eine kleine Liste mit allen WAV-Dateinamen. Danach spielt er die erste Audiodatei aus der Liste ab. Mit einem Taster, der an GPIO7 des ESP32 (an J8) angeschlossen ist, wird der aktuelle Track gestoppt und der nächste Track abgespielt. Abbildung 8 zeigt einen Prototyp mit Taster. Für den Prototypen haben wir nicht den SD-Karten-Slot auf der Platine verwendet, sondern ein extra kleines SD-Karten-Modul, das per SPI mit dem ESP32 verbunden ist. Als Anschluss für die SPI-Signale wurde die 2x4-„nRF24-Buchse“ verwendet.

The WAV player prototype
Abbildung 8: Der WAV-Player-Prototyp mit Taster zum Wechseln des Titels.
Für den Prototypen haben wir nicht den SD-Karten-Slot der Platine,
sondern ein extra kleines SD-Karten-Modul verwendet, das per SPI mit dem ESP32 verbunden ist.
Wenn Sie den ESP32 per USB mit dem PC verbinden, können Sie Befehle von einem Terminalprogramm senden. Ein „b“ springt zum nächsten Titel; ein „a“ zum vorherigen. Da unsere Software bisher keine MP3-Tracks abspielen kann, können Sie mit einem kostenlosen Konverter wie diesem Ihre Lieblings-MP3s in WAV-Dateien umwandeln.

Der Demo-Code ist modular aufgebaut. Vielleicht am interessantesten ist das Softwaremodul Stream_I2S.h, das das Schreiben der Musikdaten auf die I2S-Schnittstelle übernimmt. (Siehe Abschnitt „ESP32 I2S API“ unten.) Wir haben bewusst keine der großen Audiobibliotheken verwendet – etwa die Arduino Audio Tools von Phil Schatzmann. Sie sind sehr flexibel, haben viele Funktionen und sind sehr gut dokumentiert, verstecken aber die Musikdaten vor dem Anwender. Wir wollten zeigen, wie einfach man direkt mit den Audio-Bytes arbeiten kann.


Neben unserer einfachen Stream_I2S-Bibliothek gibt es eine kleine SDCardFiles.h-Lib, die direkt auf den Arduino-Standardbibliotheken für SD-Karten-Zugriff basiert. Eine sehr kleine Button.h-Lib verarbeitet die Tastendrücke.

Die wichtigste Schleife im Hauptprogramm ist:

 

uint8_t bBuffer[128];

...

while (SDCardFiles_DataLeftToRead())

{

      SDCardFiles_ReadInBuffer(bBuffer, 128);

      I2S_WriteFromBuffer(bBuffer, 128);

...

}

 

Zuerst lesen wir 128 Bytes von der SD-Karte, danach schreiben wir diese 128 Bytes an die I2S-Schnittstelle des ESP32. Anschließend bleibt genug Zeit, um abzufragen, ob ein Taster gedrückt oder ein Zeichen per serieller Schnittstelle empfangen wurde.

Betrachten Sie diese Software nur als Demonstration, wie einfach es ist, mit Audiodaten zu arbeiten. Natürlich sollte ein echter Player um ein Display und bessere Bedienelemente wie einen Drehgeber erweitert werden.

Component list

Espressif I2S API

Der ESP32-S3 besitzt zwei I2S-Peripherieblöcke, mit denen wir gleichzeitig Audio ausgeben und aufnehmen können. Auf der Platine sind acht Leitungen für die beiden Schnittstellen (außer 2x VCC und GND) verwendet. Generell können Sie die GPIOs des ESP32 für die I2S-Leitungen flexibel wählen.

Zum Ausgeben und Aufnehmen von Daten via I2S wird der DMA-Controller verwendet, sodass der Prozessorkern frei ist, während die Daten übertragen oder empfangen werden. Natürlich ist dazu ein DMA-Puffer notwendig. Mit der von Espressif bereitgestellten ESP32-I2S-API können Sie die Anzahl der Puffer (mindestens zwei) und die Anzahl der Musiksamples pro Puffer einstellen. Mehr dazu in einem der nächsten Artikel.

Die API zur Steuerung der I2S-Schnittstellen ist natürlich auch im Wandel. Für unsere Zwecke passt eine ältere Version [10] gut, weil sie etwas einfacher zu verstehen ist als die aktuellste API. Viele gute Arduino-Audiobibliotheken verstecken die API-Aufrufe meist mit Wrapper-Funktionen (z. B. [8]). Diese Audiobibliotheken sind sehr leistungsfähig und flexibel, aber wir dachten, es wäre gut, wenn Sie wissen, wie die I2S-API funktioniert. Zur komfortablen Nutzung haben wir alle Befehle zum Starten des ESP32-I2S-Treibers in eine Funktion gepackt (unser eigener Wrapper). Hier ist der Code zum Starten des Treibers für die Audioausgabe, Sie finden ihn in der Datei Stream_I2S.h:
 

// diese Pin-Definitionen stehen in BoardPin.h

#define I2S_MCK_OUT 36

#define I2S_WS_OUT  35  

#define I2S_SCK_OUT 48

#define I2S_SD_OUT  47

 

#define I2S_PORT   I2S_NUM_0

 

uint8_t audiochannelcount = 1;
uint16_t samplerate = 32000;
uint8_t samplebuffer_count = 4;
uint8_t samplebuffer_length = 32;

 

void I2S_Start()
{   
  i2s_channel_fmt_t audiochannelformat =  I2S_CHANNEL_FMT_ONLY_LEFT;  
 

  if (audiochannelcount == 2)
  {
    audiochannelformat = I2S_CHANNEL_FMT_RIGHT_LEFT;
  }

  
  i2s_comm_format_t communicationformat =  i2s_comm_format_t(I2S_COMM_FORMAT_I2S |                                                                                   I2S_COMM_FORMAT_I2S_MSB);  

 

  i2s_config_t i2s_config_out = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX),
    .sample_rate = samplerate,
    .bits_per_sample = i2s_bits_per_sample_t(16),
    .channel_format = audiochannelformat,
    .communication_format = communicationformat,
    .intr_alloc_flags = 0,
    .dma_buf_count = samplebuffer_count,
    .dma_buf_len = samplebuffer_length,
    .use_apll = true,
    .tx_desc_auto_clear = true, // Silence bei Unterlauf
    .fixed_mclk = samplerate * 256
  };

 

  i2s_driver_install(I2S_PORT, &i2s_config_out, 0, NULL);
 
  const i2s_pin_config_t pin_config_out = {
    .mck_io_num = I2S_MCK_OUT,
    .bck_io_num = I2S_SCK_OUT,
    .ws_io_num = I2S_WS_OUT,
    .data_out_num = I2S_SD_OUT,
    .data_in_num = -1
  };

  
  i2s_set_pin(I2S_PORT, &pin_config_out);
  i2s_start(I2S_PORT);
}


Sie müssen noch nicht alles im Detail verstehen, aber Sie sehen, dass es einfach ist, z. B. die Abtastrate oder die verwendeten GPIOs zu ändern.

Hier ist der API-Befehl, um 128 Bytes Audio über die I2S-Schnittstelle an den DAC zu senden:

i2s_write(I2S_PORT, &wBuffer, 128, &bytesWritten, portMAX_DELAY);

Damit senden Sie 128 Bytes Audio an den DAC, der im wBuffer stehen muss. Sie können ihn mit Daten von der SD-Karte, einem erzeugten Sinus- oder Rechtecksignal oder anderen Quellen befüllen. wBuffer kann ein Array einfacher Bytes (uint8_t wBuffer[128];) oder ein Array von 16-Bit-Musiksamples (int16_t wBuffer[64];) sein. Die Funktion arbeitet mit beiden Varianten, wichtig ist die Gesamtanzahl von 128 Bytes (dritter Parameter).

Praktisch ist, dass i2s_write mit portMAX_DELAY als fünftem Parameter blockiert, bis Platz im DMA-Puffer frei wird. Nach dem Auffüllen kehrt die Funktion zurück, und Sie können andere Aufgaben erledigen, während die Ausgabe im Hintergrund erfolgt. Sie müssen nur darauf achten, nicht zu lange zu warten, bevor Sie i2s_write erneut aufrufen und das nächste Paket schicken, damit die Puffer nicht leerlaufen. So ist eine kontinuierliche Ausgabe einfach möglich!

Für das andere Szenario – das Abtasten mit dem ADC – gibt es die Funktion i2s_read:


esp_err_t result = i2s_read(I2S_PORT, &rBuffer, 128, &bytesIn, portMAX_DELAY);

 

Diese Funktion werden wir in einem späteren Artikel nutzen.

Ausblick

Im nächsten Teil dieser Serie zum Audio-Transceiver-Board werden wir versuchen, Audiodaten drahtlos zu übertragen und zu empfangen. Als Vorgeschmack siehe Abbildung 7, die einen Prototyp des drahtlosen Empfängers zeigt. Bleiben Sie dran!


Redaktionshinweis: Dieser Artikel (250384-01) erscheint im Elektor Circuit Special 2025.


Fragen zum Audio-Transceiver-Projekt?

Wenn Sie Fragen zu diesem Artikel oder zum Audio-Transceiver-Projekt allgemein haben, schreiben Sie gerne eine E-Mail an die Elektor-Redaktion: editor@elektor.com.

Abonnieren
Tag-Benachrichtigung zu Embedded & AI jetzt abonnieren!