Forum: Mikrocontroller und Digitale Elektronik Arduino: ESP32 mit MAX98357A via i2s


von Torsten (Gast)


Lesenswert?

Durch Zufall bin ich auf das Tonuino-Projekt 
(https://www.voss.earth/tonuino/) gestoßen und würde das Ganze gerne auf 
einem ESP32 zum Laufen bringen. Einerseits deshalb, damit ich OTA nutzen 
kann und andererseits würde ich neue mp3s gerne via WLAN auf die Karte 
laden.

Um das Ganze zu bewerkstelligen verwende ich ein ESP32-devBoard 
(Wroom32) und habe einen SD-Card-Reader 
(https://www.az-delivery.com/products/cop...-arduino), der per SPI 
angebunden ist. Der externe DAC (Adafruit MAX98357A) ist per i2s an den 
ESP32 angebunden und treibt einen 13cm-Lautsprecher von Visaton (4 Ohm) 
an. Nachdem ich zwischenzeitlich mit nem anderen Pin-Layout 
experimentiert habe bin ich, um etwaige Fehler auszuschließen, dass auf 
das SPI-Layout zurück gegangen, welches für den ESP32 per Default 
vorgesehen ist (VSPI). Die Verdrahtung sieht also exakt so aus: 
https://github.com/schreibfaul1/ESP32-au...57A%20.JPG

Nun habe ich folende Libs ausprobiert:

https://github.com/schreibfaul1/ESP32-audioI2S
https://github.com/earlephilhower/ESP8266Audio

Während das Streamen von Webradio mit der ersten Lib einwandfrei läuft, 
habe ich mit beiden Libs das Problem, dass das Spielen von lokalen 
mp3-Titeln von SD-Karte zu ziemlich verzerrtem Sound führt. Auch mit 
.wav habe ich es mit der Lib 
https://github.com/nhatuan84/esp32-i2s-s...d_wav_.ino und habe exakt das 
gleiche Problem: Der Sound ist total verzerrt.

Card-Reader (besitzt einen Spannungsregler auf 3.3V) und MAX98357A sind 
beide mit 5V angeschlossen, dh sie hängen zwar am DevBoard, allerdings 
vor dem Spannungsregler. Mit nem einfachen Multimeter gemessen liegt die 
Spannung so bei 4,5V etwa und unterscheidet sich auch nicht, ob via WLAN 
oder SD gelesen wird.

Ein Beispiel-Sketch von Espressif besitzt einen i/o-Test für SD. Da hat 
das Schreiben von 10 Mb ca. 4,5s gedauert. Also ein Problem mit dem 
Durchsatz kann es auch nicht sein.


Es sei an dieser Stelle erwähnt, dass der Sound via SD auf jeden Fall 
nicht deswegen verzerrt, weil die Ausgabe zu laut ist. Bei der ersten 
Lib kann man die Lautstärke von 1 bis 21 einstellen; auch auf der 
niedrigsten Stufe klingt es total verzerrt, während ich via Web es auch 
schon auf 18 hatte und alles gut war. Ich habe auch schon versucht den 
Gain hardwareseitig auf dem DAC von 9dB (Default) auf 3dB (das 
Niedrigste, was im Handbuch beschrieben ist) zu setzen, aber auch das 
brachte keine Abhilfe.

Hat hier im Forum vielleicht jmd. eine Ahnung/Vermutung, warum ich einen 
Stream via Web problemlos abspielen kann und das lokale Abspielen jedoch 
Probleme macht?

von Michael U. (amiga)


Lesenswert?

Hallo,

erstmal Danke für diesen Link:
https://github.com/schreibfaul1/ESP32-audioI2S
kannte ich noch nicht.

Play von SD-Card ist hier völlig ok, ESP32 und UDA1334A als I2S Decoder.
Ich habe auch eine Kombi mit 2x MAX98357A also Stereoverstärker, das 
habe ich jetzt aber nicht rausgekramt.
Stream-Play geht prinzipiell auch richtig, da ist mein WLAN-Umgebung 
aber im Moment hier anderer Meinung...

Das der MAX mit 4 Ohm Last recht kräftige Spannungsversorgung braucht, 
ist Dir sicher bewußt, würde aber auch den Streamplay stören.

Mein Projekt benutzt ansonsten die ESP8266Audio-Lib, die macht auch 
keine prinzipiellen Probleme mit Play von SD-Card. Beim Streamplay ist 
die Anzahl DMA-Buffer bei seiner Buffergröße etwas knapp, hier auf 32 
Buffer a 128 Byte geändert. Das liegt aber auch daran, daß noch ein 4" 
Touch-Display benutzt wird, das auch manchmal etwas Last erzeugt und 
keine Aussetzer beim Bedienen erzeugen soll.

Gruß aus Berlin
Michael

von Torsten (Gast)


Lesenswert?

Auflösung: Es waren Konnektierungsprobleme im SPI-Bus.

von Brain 2.0 (Gast)


Lesenswert?

Torsten schrieb:
> Auflösung: Es waren Konnektierungsprobleme im SPI-Bus.

Schlechte Lötstellen ?

von Torsten (Gast)


Lesenswert?

Nee, ich hatte es per Jumperwires nur gesteckt. Da ich sowas mit einem 
Ethernet-Modul im Experimentierstadium auch mal gemacht hatte, war mir 
da jetzt keine Problematik bewusst.

Ich habe auf jeden Fall nochmal "frische" Jumperwires genommen und damit 
ging es an. Final werde ich es dann eh löten.

von André K. (ashtorak)


Angehängte Dateien:

Lesenswert?

Hat es sich so angehört, wie im Anhang?
Vermutlich nicht, denn ich bekomme das zum Verrecken nicht weg mit auch 
mit neuen Kabeln tut sich da nichts bei mir. Ich habe allerdings 
folgende Komponenten:

Adafruit I2S Stereo Decoder - UDA1334A breakout:
https://www.adafruit.com/product/3678

SPI reader:
https://www.az-delivery.de/en/products/copy-of-spi-reader-micro-speicherkartenmodul-fur-arduino?_pos=2&_sid=636bd39db&_ss=r

ESP32-WROOM-32:
https://www.az-delivery.de/en/products/esp32-developmentboard?_pos=2&_sid=9b0935b0b&_ss=r

Mit dem schreibfaul code läuft der Webstream problemlos. Mit der 
SD-Karte sind diese Hänger drin. Wenn ich es mir genau angucke, ist es 
so, dass bei jedem Auslesevorgang der I2S kurz aussetzt. Das fällt 
besonders auf, wenn ich z.B. einen Sinus aus dem RAM abspiele und dann 
irgendwas von der SD-Karte auslese ohne es überhaupt abzuspielen. Bei 
jedem Lesevorgang ist ein kurzer Aussetzer drin. Irgendeine Idee, woran 
das liegen könnte?

von Christoph M. (mchris)


Lesenswert?

>Hat es sich so angehört, wie im Anhang?

Üblicherweise hören sich so Verstärker mit defektem Ausgangstransistor 
an.
Ich tippe mal auf eine zu schlechte Stromversorgung.

von André K. (ashtorak)


Angehängte Dateien:

Lesenswert?

Anbei noch mal der Sinus-Test. Dabei werden jede Sekunde 512 byte von 
der SD-Karte gelesen und in ein Array geschrieben, also in dem Fall ist 
das von SDFat die Funktion FatFile::Read(). (das ist von meinem eigenen 
Programm, wo ich wav auslesen will, nicht mp3)
Denkst du, der Kartenleser zieht den kompletten Controller runter bzw. 
den 5V-Pin, wenn er die Karte ausliest? Wie könnte ich das 
prüfen/beheben? Ich habe mal testweise den Leser mit einem separaten 
Netzteil versorgt, was aber nur dazu führte, dass die SD-Karte nicht 
mehr erkannt wurde. So geht es wohl schon mal nicht :D

Mit einem Arduino Due funktioniert das ganze übrigens mit dem gleichen 
Kartenleser, aber ohne I2S. Da war ich über den DAC gegangen. Jetzt 
wollte ich halt zu ESP32 konvertieren das ganze Projekt.
Es geht um einen Fahrgeräuschsimulator, wen es interessiert: 
https://youtu.be/-sQAT78AEd8

: Bearbeitet durch User
von André K. (ashtorak)


Angehängte Dateien:

Lesenswert?

Hab jetzt mal ein 5 V / 3000 mA Netzteil auf den 5 V Pin probiert. Kein 
Unterschied. Ein Kondensator zwischen 5 V und GND hat entsprechend auch 
nichts gebracht.
Anbei noch mal mein Aufbau. Sollte eigentlich so sein, wie bei 
schreibfaul: 
https://github.com/schreibfaul1/ESP32-audioI2S/blob/master/additional_info/ESP32_I2S_UDA1334A.JPG
Nur, dass ich den Kondensator am EN noch dran habe zum Hochladen ohne 
den Boot-Knopf drücken zu müssen.

Vom Programm her ist es eigentlich nichts anderes, wie ein Sinus-Array 
mit i2swrite() an den DMA-Buffer zu schicken und dann den file.read() 
von der SD-Karte zu machen. Ohne file.read() kommt ein glatter Sinus-Ton 
raus, mit kommen die Aussetzer wie oben zu hören.
Ich kann ja nachher noch mal ein Minimal-Beispiel draus machen.

von Christoph M. (mchris)


Lesenswert?

>Anbei noch mal der Sinus-Test.

Der Sinus an sich klingt ja ziemlich klar und rein. Die Aussetzer 
zwischendrinn könnten nach Bufferleerlauf und Timingproblem klingen.
Kommt der Sinus von der SD-Karte oder wird er generisch per Programmcode 
erzeugt?
Wenn der Sinus nicht so klar wäre, wäre noch die Möglichkeit des 
falschen I2S Formats in Betrachtung zu ziehen gewesen.

von Wolfgang F. (schreibfaul1)


Lesenswert?

Wenn ich mir das beigefügte Foto ansehe fällt mir auf, dass sie 
Jumperkabel zum SD-Kartenleser zu lang sind. Standard läuft der SPI mit 
40MHz für die SD. MISO/MOSI/SCK parallel im Flachbandkabel ist ganz 
ungünstig.

von André K. (ashtorak)


Lesenswert?

Ja, der Aufbau ist nicht ideal, aber zum Testen sollte es reichen. Ich 
habe es auch nur mit 10 MHz laufen. Siehe auch unten.
Ich habe jetzt mal das Minimalbeispiel zusammengebaut, womit ich diese 
Aussetzer erzeugen kann:
1
#include "Arduino.h"
2
#include "driver/i2s.h"
3
#include "SdFat.h"
4
5
int         chipSelectPin = 5;
6
SdFat       sd;
7
SdFile      myFile;
8
int16_t     buf[512];               // buffer for SD data
9
int16_t     m_outBuff[512];         // buffer for i2s data
10
size_t      m_bytesWritten=0;       // set in i2s_write() but not used
11
12
// timing stuff
13
long        lastmillis = 0;
14
int         ticks = 1000;
15
int         dt;
16
17
void setup() {
18
    
19
    sd.begin(chipSelectPin,SD_SCK_MHZ(10));
20
21
    //i2s configuration
22
    
23
    i2s_config_t i2s_config = {
24
         .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
25
         .sample_rate = 22050,
26
         .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
27
         .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
28
         .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
29
         .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
30
         .dma_buf_count = 8,  // max buffers
31
         .dma_buf_len = 1024, // max value
32
         .use_apll=1,
33
         .tx_desc_auto_clear= true,  // new in V1.0.1
34
         .fixed_mclk=-1
35
    };
36
    i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
37
 
38
    i2s_pin_config_t pins = {
39
      .bck_io_num = 27,             // Bit Clock
40
      .ws_io_num =  26,             //  wclk, Left/Right Clock
41
      .data_out_num = 25,           // Data Out
42
      .data_in_num = I2S_PIN_NO_CHANGE
43
    };
44
    i2s_set_pin(I2S_NUM_0, &pins);
45
46
    // create sinus lookup table
47
    for(int i=0; i<512;i++)
48
    {
49
        m_outBuff[i]=sin(10*PI*i/512.0)*30000;
50
    }
51
52
    myFile.open("320k_test.mp3", O_READ);
53
54
    Serial.begin(115200);
55
}
56
57
void loop()
58
{
59
    i2s_write(I2S_NUM_0, m_outBuff, sizeof(m_outBuff), &m_bytesWritten, 100);
60
61
    if(millis()>lastmillis+ticks)
62
    {
63
        lastmillis = millis();
64
        //delay(400); // if I use this delay instead of myFile.read the output sounds similar
65
        myFile.read(&buf, sizeof(buf));
66
        dt = millis()-lastmillis;
67
        Serial.println(dt); // file read takes about 2 to 3 ms
68
    } 
69
}

Das ganze wird mit PIO (Arduino Framework) in VS Code compiliert.

Ohne delay oder file read kommt ein sauberer Sinus raus.

: Bearbeitet durch User
von Christoph M. (mchris)


Lesenswert?


von Torsten (Gast)


Lesenswert?

Also ich habe mir das Ganze mal angehört, aber ganz so übel klang das 
bei mir nicht. Bei mir war das wie gesagt eher ein Knacken, welches mehr 
oder weniger stark ausgeprägt war. Verzerrung auch ein bisschen, aber 
doch nicht so stark. Ich habe allerdings auch nur mit der MAX-Amp bisher 
gearbeitet.

Ein paar Anmerkungen:
- Grundsätzlich gelöst bekommen habe ich es damit, dass ich es 
aufgelötet habe auf eine Streifenraster-Platine
- Ein Stück weit verbessern konnte ich das Ganze, wenn ich den Takt auf 
dem SPI-Bus herabgesetzt habe: 
https://github.com/biologist79/Tonuino-ESP32-I2S/blob/master/src/main.cpp#L2912 
(ist vermutlich nicht notwendig, wenn es aufgelötet ist, aber ich war am 
End froh, dass es gelaufen ist und habe es dann so gelassen.)
- Via mp3-Stream hatte ich das Problem nicht, was für mich letztlich ein 
Indiz war, dass es von SPI kommt


Ein "neuer Benutzer" meiner Tonuino-Portierung schrieb heute Morgen noch 
was. Ich zitiere das einfach mal an dieser Stelle, vielleicht hilft es 
ja weiter:

"Hab mir dann die Stromversorgung genauer angesehen.

Der UDA1334 hat die Möglichkeit mit 5V oder 3.3V betrieben zu werden.

Ich hatte das USB-Versorgungskabel aufgedöselt und sowohl den SD-Card 
Reader als auch den DAC direkt mit den 5V gespeist.
Testweise hab ich dann den DAC mit 3.3V direkt vom ESP32 angeschlossen 
und voilà, das Brummen war sofort weg.
Juhuu! Glasklarer Sound!"

von André K. (ashtorak)


Lesenswert?

Torsten schrieb:
> Testweise hab ich dann den DAC mit 3.3V direkt vom ESP32 angeschlossen
> und voilà, das Brummen war sofort weg.

Das war's! Ich habe den I2S Decoder an die 3.3V vom ESP gehängt, während 
der SPI Reader an den 5 V blieb. Jetzt geht's! :)
Aber fragt mich nicht wieso. Würde mich sehr freuen, wenn mir das jemand 
erklären könnte. Das hat mich einiges an Nerven gekostet!

Dann mal vielen Dank Leute! Jetzt kann's weitergehen mit dem 
eigentlichen Projekt :D

von André K. (ashtorak)


Lesenswert?

Christoph M. schrieb:
> ESP32-SD-Kartenleser sind gerade in:
> 
https://hackaday.com/2020/06/14/esp32-becomes-music-player-in-under-40-lines-of-code/

Klasse Überschrift! Aber warum haben sie es nicht gleich mit nur einer 
Zeile Code gemacht?? :D

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.