Forum: Mikrocontroller und Digitale Elektronik ESP32 WAV-Player: Praxiswert der CPU-Geschwindigkeit gesucht


von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Moin.

Ich habe mal eine Frage zur Geschwindigkeit eines ESP32:

Wenn man mehrere Audio-Streams in eine Datei auf einer SD-Karte packen 
möchte, was schafft der ESP32 an Daten zu lesen, zu splitten und dadurch 
einen dieser Streams über sein I2S Audio-Interface auszugeben?

Angenommen, man nimmt zwei Streams mit 48kHz 16bit Stereo, dann kommt 
einer davon auf 48.000 x 2bytes (16bit) x 2 Kanäle = 192kbyte/s. Mal 
zwei Streams sind das schon 384kbyte/s. Wenn man die Streams in Frames 
zu sagen wir 25ms aufteilt, sind das 4,8kbyte Audio-Daten pro Stream 
(zwei Streams 9,6kbyte), aber man muss pro Sekunde 40 dieser Frames an 
das I2S-Interface schicken.

Bevor ich das nun ausprobiere und am Ende enttäuscht feststelle, daß es 
nicht geht, frage ich lieber mal nach: Ist der ESP32 schnell genug, 
40mal pro Sekunde 9,6kbyte aus einer Datei von einer SD-Karte zu lesen, 
daraus 4,8kbyte Daten zu extrahieren und diese an das I2S-Interface zu 
schicken? Es wäre schön, wenn jemand da Erfahrungswerte aus der Praxis 
hat.

Alle Bibliotheken, die ich dazu auf die Schnelle gefunden habe, benutzen 
irgendwelche Subroutinen, die das Lesen der Daten von der SD-Karte und 
die Ausgabe auf dem I2C-Interface alles alleine machen. Das ist 
natürlich super simpel, bietet aber nicht die Möglichkeit, eigene 
Datenformate zu nutzen und schleust alle Daten wenn man das so sagen 
möchte, an der CPU vorbei.

Ich würde das gerne mit der Arduino-Plattform probieren, gibts da 
entsprechende Funktionen, um die DMA-Fähigkeit des I2C-Interfaces zu 
nutzen bzw. einen Audio-Puffer unterbrechungsfrei aufzufüllen, so daß es 
zu keinen Störgeräuschen beim Audio kommt?

Etwas ähnliches hatte ich vor langer Zeit schon mit dem 486er bzw. 
Pentium und einer Soundblaster-Karte probiert, einen eigenen WAV-Player 
zu basteln. Da waren die Frames am Ende glaube ich 64kbyte lang und die 
Soundkarte hat sich die Daten per DMA geholt, aber der Rechner war trotz 
Assembler nicht schnell genug, am Ende eines DMA-Transfers neue Daten in 
den Puffer zu schreiben und einen neuen DMA-Transfer zu starten. Das 
führte zu Störgeräuschen durch die kurze Pause und man musste den 
DMA-Transfer so konfigurieren, daß er automatisch wiederholt wird und 
dann immer eine Hälfte des Puffers updaten während die andere abgespielt 
wurde. Keine Ahnung, ob der ESP32 was ähnliches kann, so daß die Daten 
unterbrechungsfrei zum I2S-Interface kommen, obwohl sie in Stücken in 
den Puffer kopiert werden.

von Richie (mikro123)


Lesenswert?

Grundsätzlich, also mit ESP-IDF, ist das gar kein Problem.
Mit Arduino kenne ich mich nicht aus, aber da muss man halt darauf 
achten, dass man keine der doch häufiger vorkommenden schlechten 
Bibliotheken benutzt.

Du hast aber nicht geschrieben, ob die Hardware bereits vorgegeben ist 
oder noch ausgewählt werden kannst. Da gibt es dann natürlich auch noch 
Stellschrauben:
- Ist der ursprüngliche ESP32 gemeint oder kann es auch ein ESP32-S3 
oder ESP32-P4 sein?
- Wird PSRAM als Puffer genutzt?
- Falls ja, mit welcher Taktfrequenz läuft der PSRAM (bei P4 bis zu 
200MHz)?
- Wie ist die SD-Karte angeschlossen (SPI, 1Bit, 4Bit)

Ich denke, selbst im ungünstigsten Fall sollte das reichen, aber wenn Du 
noch die Hardware auswählen kannst, dann musst Du Dir sowieso keine 
Gedanken machen.

von Harald K. (kirnbichler)


Lesenswert?

Der potentielle Flaschenhals dürfte die SD-Karte sein. Zwar versprechen 
deren Hersteller Wunderdinge in Sachen Geschwindigkeit, die harte 
Realität sieht aber meist sehr anders aus - und hier kommt die Anbindung 
der SD-Karte nochmal ganz deutlich zum Tragen.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Bei der Auswahl der Hardware bin ich absolut flexibel, das Projekt wenn 
man es überhaupt schon so nennen will, ist noch im Ideen-Stadium. Ich 
hatte nur den ESP32 im Auge, weil ich damit (und mit der 
Arduino-Plattform) ein gutes Benutzer-Interface hinkriege (WLAN).

Also es darf ruhig eine leistungsstarke ESP32-Variante sein, da nehme 
ich gerne Vorschläge an, sollte aber von der Arduino-Plattform 
unterstützt werden. So wie ich das mitbekommen habe, gibts da bei neuen 
Modellen gerne mal Probleme.

> - Ist der ursprüngliche ESP32 gemeint oder kann es auch
> ein ESP32-S3 oder ESP32-P4 sein?
Wenn der -S3 oder -P4 von der Arduino-Plattform unterstützt wird und man 
das Modul vielleicht sogar bastelfreundlich wie die ursprünglichen ESP32 
(-WROOM) bekommt, dann darf es auch gerne ein -S3 oder -P4 sein. Ich 
werde mal schauen, was diese beiden Varianten besser können als der 
ursprüngliche ESP32.

Edit: Gerade gelesen, der -P4 hat kein WiFi mehr,
damit ist der eigentlich raus.

> - Wird PSRAM als Puffer genutzt?
Meinst Du nicht, daß das interne RAM des ESP32 ausreicht wenn man mit 
25ms langen Audio-Frames arbeitet? Oder ist das zu langsam?

> - Falls ja, mit welcher Taktfrequenz läuft der PSRAM
> (bei P4 bis zu 200MHz)?
Wenn nötig, dann nehme ich 200Mhz - aber müsste dann irgendwie bereits 
im ESP32-Modul verbaut sein, weil 200Mhz krieg ich mit einer 
Bastelplatine bestimmt nicht so locker zusammen.

> - Wie ist die SD-Karte angeschlossen (SPI, 1Bit, 4Bit)
Gerne 4 Bit, wenn das das WLAN-Modul, das I2S-Interface und ein 
SPI/UART-Interface nicht behindert.

: Bearbeitet durch User
von Richie (mikro123)


Lesenswert?

Ich hab das mal schnell mit dem Arduino-Zeugs für Dich ausprobiert:

Als Richtwert für eine untere Grenze habe ich ein altes ESP32 Modul 
genommen und die SD-Karte mit SPI angesteuert.
Die SD-Karte ist eine SanDisk 32GB SDHC(UHS-I 10). Formatiert war sie 
mit FAT32.

Damit komme ich auf 432kB/s.
Das liegt schon über den von Dir geforderten 375kB/s.
Mit dem SDIO 4Bit Modus kommst Du dann auf ein Vielfaches.

von René H. (mumpel)


Lesenswert?

Was möchtest Du erreichen? Wieviel Musik möchtest Du speichern?

: Bearbeitet durch User
von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

@Richie
Danke Dir für Deine Mühe, das stimmt doch schon mal zuversichtlich.

Also die grundlegende Idee ist, in einer WAV-ähnlichen Datei sowas wie 
Subchannel-Daten abzulegen, die dann synchron mit einem Audio-Inhalt zur 
Verfügung stehen, oder eben auch zwei (oder mehrere) Audio-Streams.

So eine Datei zu basteln ist eigentlich trivial, vor allem wenn man eine 
konstante Frame-Länge benutzt. Damit kann man diese Datei aber nicht 
mehr einfach so an Standard-Bibliotheken übergeben und dem ESP32 einfach 
sagen "Spiel mal diese Datei von der SD-Karte ab", sondern man muss die 
Daten einlesen, die Datenströme splitten und dann den Audio-Inhalt so 
über das I2S-Interface ausgeben, daß dabei der Audio-Puffer nicht 
leerläuft und es keine Störgeräusche gibt.

Im Moment denke ich am meisten über den Standard-ESP32 nach, also die 
ursprüngliche Variante. Da bekäme man zwei 240Mhz-Cores, man könnte den 
zeitkritischen Programmteil (der die Daten in Echtzeit lesen, 
verarbeiten und das I2S füttern muss) auf einem Core laufen lassen und 
das WLAN-User-Interface-Gedöns auf dem anderen Core.

Leider weiß ich im Moment noch nicht viel über das I2S-Interfache, also 
was es kann... wie lang der Audio-Puffer sein kann und ob man den 
aktuellen Füllstand des Audio-Puffers irgendwo her ermitteln kann.

Eine Alternative wäre evtl. - falls man zwei Dateien von der SD-Karte 
gleichzeitig lesen kann - die Streams in verschiedenen Dateien 
abzulegen. Wenn die Standard-Audio-Bibliotheken in schneller Folge und 
ausreichend hoher Auflösung die aktuelle Spielzeit übermitteln können, 
dann könnte man die Subchannel-Daten aus einer anderen Datei lesen und 
über die Spielzeit synchronisieren. Nachteil: mehrere Dateien, Vorteil: 
man braucht sich praktisch nicht um den zeitkritischen Audio-Kram zu 
kümmern.

von Jan H. (jan_h74) Flattr this


Lesenswert?

Mit die SD_MMC library (1bit) und eine standard ESP32 geht bei mir noch 
etwas schneller : SD_MMC Read speed= 679 ms/MB Write speed= 1414 ms/MB s
Daneben ist die richtige audio library auch wichtig, shau mal hier : 
https://github.com/pschatzmann/arduino-audio-tools
Auch hilfsreich (yt Andreas Spiess) : 
https://www.youtube.com/watch?v=a936wNgtcRA

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Danke für die Tipps!

Die Youtube-Videos habe ich durch, die waren mehr oder weniger der 
Auslöser für die "Idee". Leider findet man immer nur Beispiele, die 
ausschließlich die Libs, aber nicht die Schnittstellen direkt verwenden, 
so daß man z.B. gar nicht ohne weiteres herausbekommt, wie man das 
I2S-Interface des ESP32 unterbrechungsfrei mit WAV-Daten füttern muss, 
also ob das einen Puffer hat und wie groß der ist. Das über was ich da 
nachgedacht habe war etwas mehr
als I2S_Play(sd_card_file);forget_about_the_rest;

: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Ben B. schrieb:
> Alle Bibliotheken, die ich dazu auf die Schnelle gefunden habe,

war da earlephilhower/ESP8266Audio mit darunter?

von Stephan (stephan_h623)


Lesenswert?

Hier könntest die relevanten Teile rausnehmen: 
https://github.com/schreibfaul1/ESP32-audioI2S

90% oder mehr könnte für deinen Zeck aber weg.

Wenn ich mich recht erinnere:

Puffergröße und Anzahl kann in Grenzen im Code definiert werden.

Wenn ein Puffer voll ist geht der an die I2s-Einheit und wird per DMA 
abgespielt.

Gesamtpuffergröße halt so wählen, dass es bei Latenzen der SD Karte 
nicht stockt. Aber auch nicht zu viel, weil du sonst nicht schnell 
reagieren kannst falls du weiterschalten willst oder ausfaden etc. Was 
in den Puffer geschrieben ist kann nicht geändert werden.

2 Puffer sind eher zu wenig. Erst wenn ein Puffer komplett voll ist kann 
er abgespielt werden und erst wenn ein Puffer komplett geleert ist 
kannst du wieder was reinschreiben:

Puffer 1 wird abgespielt, noch 1 Sample. Puffer 2 ist voll. Dann kannst 
nichts nachfüllen. Also nächster Task. Dann kommst frühestens nach 1 ms 
wieder in den Nachfülltask und der muss den dann freien Puffer 1 
vollmachen bevor Puffer 2 zu Ende gespielt ist.

Da laufen 4 oder 8 Puffer gleichmäßiger.

von Richie (mikro123)


Lesenswert?

Ben B. schrieb:
> Danke für die Tipps!
>
> Die Youtube-Videos habe ich durch, die waren mehr oder weniger der
> Auslöser für die "Idee". Leider findet man immer nur Beispiele, die
> ausschließlich die Libs, aber nicht die Schnittstellen direkt verwenden,
> so daß man z.B. gar nicht ohne weiteres herausbekommt, wie man das
> I2S-Interface des ESP32 unterbrechungsfrei mit WAV-Daten füttern muss,
> also ob das einen Puffer hat und wie groß der ist. Das über was ich da
> nachgedacht habe war etwas mehr
> als I2S_Play(sd_card_file);forget_about_the_rest;


Ich habe vor vielen Jahren auf ESP32-Basis einen Player für meine 
Tochter gebaut.
Die Hauptfunktion war das Abspielen von MP3-Dateien als Dateien und per 
Internet-Stream. Genutzt habe ich das esp-idf.

Ich habe allerdings keine SD-Karten verwendet, sondern USB-Sticks (davon 
hatte ich aus einer Werbeaktion noch knapp 100 Stück übrig...).
Angeschlossen habe ich das über den ch372-Chip mit seiner kruden API, da 
der ESP32 im Gegensatz zum S2 oder S3 heute keine USB-Schnittstelle hat. 
Das Ganze funktioniert aber bis heute einwanfrei.
Die Dateien oder Streams werden beim Abspielen vom USB-Stick eingelesen, 
per Helix-Decoder dekodiert, in einen Ringpuffer geschrieben und dann 
per i2s_write an die esp-idf API übergeben, die das dann per DMA 
ausgibt. Das Ganze findet in einer Schleife statt. i2s_write blockiert 
den Task, bis wieder Platz im DMA-Puffer ist.
Die API hat sich allerdings geändert, die 5er gab es damals noch nicht.

Der Ringpuffer ist deutlich größer als die an die API übergebenen 
Datenhäppchen, um den "Jitter" beim Einlesen vom USB-Stick abzufangen.
Das Ganze funktioniert problemlos, es ist auch noch genug Zeit übrig, um 
z.B. die Lautstärke der eingelesenen Daten zu verändern oder anderes 
damit zu machen.
Ausgegeben wird das dann über einen PCM1502A.

Es reicht übrigens ein Puffer.

von Christoph M. (mchris)


Angehängte Dateien:

Lesenswert?

Eigentlich müsste das ESP32-A1S AudioKit für diese Anwendung passen. Es 
hat ja den DAC und den SD-Kartenslot gleich eingebaut.

Ich habe mal vor ein paar Jahren eines gekauft aber zugegebenermaßen nie 
zum laufen bekommen. Ich habe alle möglichen Methoden ausprobiert, aber 
ein Ton kam nie aus dem Lautsprecher. Ich vermute mein Board hat einfach 
einen Defekt.

von Harald K. (kirnbichler)


Lesenswert?

Christoph M. schrieb:
> Eigentlich müsste das ESP32-A1S AudioKit für diese Anwendung passen.

Ich hab' auf genauso einem Ding "Squeezelite" installiert.

https://github.com/sle118/squeezelite-esp32

Läuft; man muss nur darauf achten, daß man, wenn man kein "LMS" 
verwendet, das Autoreset-Feature deaktiviert, siehe Kommentar am Ende 
von 
https://github.com/sle118/squeezelite-esp32#additional-configuration-notes-from-the-web-ui

Ich nutze das Ding als Airplay-Empfänger.

von Christoph M. (mchris)


Angehängte Dateien:

Lesenswert?

Harald K. schrieb:
> Läuft; man muss nur darauf achten, daß man, wenn man kein "LMS"

Bei mir scheitert es an der grundlegenden Initialisierung des I2C 
Codecs.
Scheinbar hat sich beim ESP32-AS1 die interne Pinbelegung des 
I2C-Interface zum Codec über die verschiedenen Modulversionen geändert. 
Leider findet aber der I2C Scanner (siehe Code) mit allen gezeigten 
Pinvarianten die ich in verschiedenen Foren und Dokumenten gefunden 
habe, kein I2C Device.

von Alexander (alecxs)


Lesenswert?

Ich glaube das Thema war I2S‑DMA Ringbuffer, nicht I2C.

von Harald K. (kirnbichler)


Lesenswert?

Christoph M. schrieb:
> Bei mir scheitert es an der grundlegenden Initialisierung des I2C
> Codecs.

I2C? Falsche Fährte; Du willst I2S nutzen.

Das sind zwei komplett unterschiedliche Schnittstellen; I2C ist für 
Audioausgabe viel zu langsam.

von Richie (mikro123)


Lesenswert?

Harald K. schrieb:
> Christoph M. schrieb:
>> Bei mir scheitert es an der grundlegenden Initialisierung des I2C
>> Codecs.
>
> I2C? Falsche Fährte; Du willst I2S nutzen.
>
> Das sind zwei komplett unterschiedliche Schnittstellen; I2C ist für
> Audioausgabe viel zu langsam.

Was meinst Du wohl, wie der DAC/Codec konfiguriert wird?
Sicher nicht über I2S...

Natürlich läuft das über I2C.

Also: Falsche Fährte; Du willst I2C nutzen.

von Christoph M. (mchris)


Lesenswert?

Harald K. schrieb:
> I2C? Falsche Fährte; Du willst I2S nutzen.

Ja. Aber erst will man den Codec über I2C konfigurieren.

edit: Ich sehe gerade, Richie war schneller.

: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Will man das? Wohl nur für externe Hardware die über I2C konfigurierbar 
ist. Für den PCM1502A sicher nicht.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Richie schrieb:
> Was meinst Du wohl, wie der DAC/Codec konfiguriert wird?
> Sicher nicht über I2S...

Die I2S-Dinge, die ich bislang verwendet habe, die habe ich nicht via 
I2C konfiguriert, sondern mit ein paar Jumpern bzw. Lötbrücken. Ich gebe 
zu, mit dem auf dem Audiokit hab' ich mich nicht weiter beschäftigt; 
Squeezelite funktioniert, ohne daß ich mir da irgendwas ansehen musste.

Da mich Audioeingänge auch nicht interessiert haben, habe ich nur einen 
I2S-DAC genutzt, wie z.B. PCM1502, den es günstig auf netten "breakout 
boards" gibt.

https://www.adafruit.com/product/6250

von Richie (mikro123)


Lesenswert?

Alexander schrieb:
> Will man das? Wohl nur für externe Hardware die über I2C konfigurierbar
> ist. Für den PCM1502A sicher nicht.

Um den ging es hier aber nicht.
Sondern um per I2C konfigurierbare Codecs...

von Alexander (alecxs)


Lesenswert?

Eigentlich ging es um ein eigenes kleines Containerformat das mehrere 
Audio‑Streams enthält die über DMA laufen sollen. Das können auch 
Daten-Streams sein. Wo liest Du da irgendwo was von Codecs?

von Christoph M. (mchris)


Lesenswert?

Alexander schrieb:
> Eigentlich ging es um ein eigenes kleines Containerformat das mehrere
> Audio‑Streams enthält die über DMA laufen sollen.

Gleich im ersten Post steht:
>Ich habe mal eine Frage zur Geschwindigkeit eines ESP32:

Und als Hardware dafür nimmt man am besten ein Board, das dafür gemacht 
ist und alle Komponenten integriert hat. Dafür sollte das ESP32-A1S 
Board mit integriertem I2C konfigurierbarem Audio-Codec und auf dem 
Board befindlichem SD-Kartenslot ziemlich geeignet sein.

von Alexander (alecxs)


Lesenswert?

Dafür reicht schon ein nackter ESP32 mit seinem DAC.

von Harald K. (kirnbichler)


Lesenswert?

Alexander schrieb:
> Dafür reicht schon ein nackter ESP32 mit seinem DAC.

Klingt halt bescheiden. Deswegen nimmt man einen externen DAC.

Ein "codec" ist in diesem Kontext ein Stück Hardware, nämlich die 
Kombination aus einem DAC und einem ADC, der für Audiozwecke via I2S 
angebunden wird.

von Alexander (alecxs)


Lesenswert?

Zur Klangqualität kann ich nichts sagen, hatte nur einen Transistor mit 
PC Speaker dran. Aus Gründen der Lautstärke hab ich dann so einen Mono 
Verstärker angeschlossen. Hab noch welche da gegen Porto.

Alexander schrieb:
> https://www.aliexpress.com/item/1005001981842370.html

von Harald K. (kirnbichler)


Lesenswert?

Alexander schrieb:
> Zur Klangqualität kann ich nichts sagen, hatte nur einen Transistor mit
> PC Speaker dran.

Mir ging es um Musik, nicht irgendwelches Gequäke.

von Alexander (alecxs)


Lesenswert?

Für audiophile Anwendungsfälle wäre ein ESP32 wohl meine letzte Wahl.

von Harald K. (kirnbichler)


Lesenswert?

Alexander schrieb:
> Für audiophile Anwendungsfälle

Von Religion war bei mir nicht die Rede.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.