Probleme beim Upload

Ah ok, good to know!
Ich hatte vorher noch eine sehr alte Version laufen, mit der neuen Version bekomme ich praktisch keine Datei mehr hochgeladen. Dann gehe ich mal zurück auf eine ältere.

In der seriellen Ausgabe sehe ich nun auch den Fehler.

Leider hat mich der Old-Tree auch nicht weitergebracht. Nun hängt er sich nach dem Upload auf - es landen leider keine vollständigen MP3s mehr auf der SD-Karte.
Werde nun erstmal ohne Wifi-Transfer weitermachen

Ich werde nochmal ein bisschen rumprobieren. Also was du mal testen kannst:

In der markierten Zeile wird 6 ms gewartet. Ggf. bessert sich das Verhalten, wenn man das auf 10 ms ändert. Aber da muss ich gleich dazu sagen, dass das auch schwer zulasten der Performance geht.

Kurz zur Funktionsweise: Die Daten landen über den Webserver in einem Ringpuffer, aus dem sie dann auf SD geschrieben werden.

Beim letzten Link siehst du auch die Auswertung/Analyse, ob das geklappt hat oder nicht. Die Schleife wird ganz oft durchlaufen und die „kaputten“ oder „intakten“ Bytes werden dann akkumuliert. Das Ganze funktioniert also mehr oder weniger lange und ab dann schlägt das Schreiben plötzlich fehl. Warum das passiert, habe ich bislang noch nicht rausgefunden.

Wie gesagt: Der einzige Fix, den ich aktuell kenne, ist SD_MMC zu benutzen. Da hat man auch die Vorteile, dass der Durchsatz eher so bei 320 bis 350 kB/s liegt und man nur drei statt vier GPIOs braucht. Leider sind muss man aber zwingend die GPIOs 15/14/2 benutzen für SD_MMC und das ist mit dem GPIO-Layout des Lolin D32 pro nicht kompatibel :frowning:. Um das zu adressieren, habe ich jetzt (wie im anderen Thread erwähnt) man einen PCB gemacht, der den Lolin D32 pro zusammen mit einem externen SD-Reader verwendet. Das mag unsinnig erscheinen, aber das ist halt der Grund. Aber der ist noch auf dem Versandweg.

Wie auch immer: Die Lolin D32pro/RC522/SPI-SD-Lösung verwenden hier einige Leute. Mir wäre auch daran gelegen, wenn ich das fixen könnte.

1 „Gefällt mir“

Danke dir, werde ich heute Abend mal testen und dir dann eine Rückmeldung geben.
Habe mir parallel mal das Lolin32 / SD_MMC /PN5180 Board bestellt… Fand das Wakeup durch Kartenauflegen und die höhere Empfindlichkeit eh reizvoll :smiley:

Mit dem Aufwecken könnte es ggf. Probleme geben - ich muss mir da endlich mal selbst ne Testplattform machen. Aber ansonsten ist das auch sowas wie meine Lieblingsplattform :slight_smile:. Naja, mit dem neuen PCB wird man dann hoffentlich alles haben: WROVER (16 MB Flash), SD_MMC und auch PN5180 :slight_smile:. Richtig zur Höchstform läuft der PN5180 ja mit ISO15693-Karten auf: In meinem Freiluftaufbau werden da Karten schon in 12cm Entfernung erkannt. Die Karten sind aber auch bissl teurer. Aber die anderen Karten sind auch ausreichend.
Interessanterweise kriegt man den PN5180 offenbar nur in China.

Ich probiere mal etwas damit herum. WROVER wäre auch toll…aber fürs erste wird der einfache reichen.
Das bestellen in China stört mich immer weniger, durch die Pflicht-Steuer hat sich die Lieferzeit massiv reduziert. Meistens sind die Sachen schon nach zwei Wochen da.

Hmm, also bei der Lieferzeit merke ich da nicht groß nen Unterschied. War gefühlt vorher nicht anders.
Aber gut, soll der Staat halt seinen Obulus kriegen; passt schon. Günstig ist es ja weiterhin.

Das erhöhen auf 10ms hat leider keine Besserung gebracht.

Blockzitat
Schreibe Datei: /Kinderlieder/01 - Haende waschen.mp3
ws[/ws][2] text-message[24]: ping
Datei geschrieben: Kinderlieder/01 - Haende waschen.mp3 => 1433084 bytes in 7420 ms (193 kB/s)
Bytes [ok] 67780 / [not ok] 1365304

Irgendwer hatte hier mal berichtet, dass das Formatieren mit einer speziellen Software was diesbzgl. gebracht habe. Finde es leider gerade nicht.

Hier hatten wir das Problem übrigens mal diskutiert: Probleme beim Webtransfer bzw. Probleme beim Upload per Web/FTP.
Da hatte ich noch den Lösungsansatz, immer nur 4k en bloc zu schreiben. Das habe ich bisher noch nicht getestet.

Ich hab das nur in Erinnerung für das Abspielen

1 „Gefällt mir“

Ich hatte da noch etwas rumprobiert und entsprechend erweitert, dass darauf gewartet wird, dass der Buffer gefüllt wird. Mit 8K Buffer 2K Blöcken habe ich die besten Ergebnisse bekommen. Die Übertragung ist nicht wesentlich höher, aber stabiler.
Ob das etwas für diesen Fehler bringt weiß ich leider nicht. Ich hatte diesen Fehler bei mir nie - und benutze inzwischen auch nur noch SD_MMC.

@@ -588,7 +588,7 @@ void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, s
 
         // Create Ringbuffer for upload
         if (explorerFileUploadRingBuffer == NULL) {
-            explorerFileUploadRingBuffer = xRingbufferCreate(4096, RINGBUF_TYPE_BYTEBUF);
+            explorerFileUploadRingBuffer = xRingbufferCreate(8192, RINGBUF_TYPE_BYTEBUF);
         }
 
         // Create Queue for receiving a signal from the store task as synchronisation
@@ -609,7 +609,14 @@ void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, s
 
     if (len) {
         // stream the incoming chunk to the ringbuffer
+        // unsigned long currentMillis=millis();
         xRingbufferSend(explorerFileUploadRingBuffer, data, len, portTICK_PERIOD_MS * 1000);
+        // DEBUG
+        // if ( (millis() - currentMillis) > 1 ) {
+        //     Serial.print("X");
+        // } else {
+        //     Serial.print("|");
+        // }
     }
 
     if (final) {
@@ -621,6 +628,7 @@ void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, s
 
         // delete task
         vTaskDelete(fileStorageTaskHandle);
+        vRingbufferDelete(explorerFileUploadRingBuffer);
     }
 }
 
@@ -637,17 +645,32 @@ void explorerHandleFileStorageTask(void *parameter) {
     BaseType_t uploadFileNotification;
     uint32_t uploadFileNotificationValue;
 
+    UBaseType_t wait;
+
     uploadFile = gFSystem.open((char *)parameter, "w");
 
+    // wait for initial fillup
+    while (true) { 
+        size_t wait = xRingbufferGetCurFreeSize(explorerFileUploadRingBuffer);
+        if (wait > 1400 ) {
+            vTaskDelay(portTICK_PERIOD_MS * 1);
+            //#TODO: fix loop for very small files 
+        } else {
+            break;
+        }
+    }
+ 
     for (;;) {
         //esp_task_wdt_reset();
-
-        item = (uint8_t *)xRingbufferReceive(explorerFileUploadRingBuffer, &item_size, portTICK_PERIOD_MS * 100);
+        //item = (uint8_t *)xRingbufferReceive(explorerFileUploadRingBuffer, &item_size, portTICK_PERIOD_MS * 1000);
+        item = (uint8_t *)xRingbufferReceiveUpTo(explorerFileUploadRingBuffer, &item_size, portTICK_PERIOD_MS * 1000,2048); // 1440
+        
         if (item != NULL) {
-            if (!uploadFile.write(item, item_size)) {
-                bytesNok += item_size;
+            uploadFile.write(item, item_size);
+            if (item_size < 2048) {
+                //Print Buffer Size if it is smaller than 2048
+                Serial.print(item_size);
             } else {
-                bytesOk += item_size;
             }
             vRingbufferReturnItem(explorerFileUploadRingBuffer, (void *)item);
         } else {
@@ -657,19 +680,25 @@ void explorerHandleFileStorageTask(void *parameter) {
                 uploadFile.close();
                 snprintf(Log_Buffer, Log_BufferLength, "%s: %s => %zu bytes in %lu ms (%lu kB/s)", (char *)FPSTR (fileWritten), (char *)parameter, bytesNok+bytesOk, (millis() - transferStartTimestamp), (bytesNok+bytesOk)/(millis() - transferStartTimestamp));
                 Log_Println(Log_Buffer, LOGLEVEL_INFO);
-                snprintf(Log_Buffer, Log_BufferLength, "Bytes [ok] %zu / [not ok] %zu\n", bytesOk, bytesNok);
-                Log_Println(Log_Buffer, LOGLEVEL_DEBUG);
                 // done exit loop to terminate
                 break;
             }
-            vTaskDelay(portTICK_PERIOD_MS * 100);
         }
-        #ifdef SD_MMC_1BIT_MODE
-            vTaskDelay(portTICK_PERIOD_MS * 1);
-        #else
-            vTaskDelay(portTICK_PERIOD_MS * 6);
-        #endif
+        //vTaskDelay(portTICK_PERIOD_MS * 1);
+        unsigned long waitStartMillis=millis();
+        while (true) {
+            vRingbufferGetInfo(explorerFileUploadRingBuffer,NULL,NULL,NULL,&wait);
+            if (wait < 2048 && ( (millis() - waitStartMillis) < 500 ) ) { // wait for buffer to fill up but max 500 ms
+                vTaskDelay(portTICK_PERIOD_MS * 1);
+            } else {
+                break;
+            }
+        }
     }
+
+    Serial.print("Stack watermark Upload-Task :");
+    Serial.println(uxTaskGetStackHighWaterMark(NULL));
+
     // send signal to upload function to terminate
     xQueueSend(explorerFileUploadStatusQueue, &value, 0);
     vTaskDelete(NULL);
-- 

Ich habe in meiner „Dev-Version“ aber auch die Tasks verändert: Kein „CPU-Pinning“, Loop in eigenen Task, Änderung der Prios. Deshalb weiß ich gerade nicht, wie reproduzierbar das wäre.

Wie quantifizierst du „stabiler“? Datenrate schwankt wenig?
Danke für den Input!

Ja, genau. Ich hatte ein paar „Debug-Ausgaben“ mit dabei und dann sieht man recht gut, dass manchmal der Buffer nicht gefüllt wird, weil die Daten nicht schnell genug (vom Browser) kommen. Er wird dann trotzdem geschrieben. Manchmal konnte der Buffer nicht neu befüllt werden, weil er noch nicht leer (auf die SD geschrieben) war.
In dieser Kombination traten beide Effekte weniger auf.

Ich hatte die Karte neu formatiert mit dem integrierten Windows Tool aber den Haken raus bei schnellfornatierung.

Ich gucke mal ob ich das die Tage testen kann. Leider ist mein Gehäuse extrem unpassend und ich komme daher nicht so einfach an die SD-Karte. Dann werde ich auch noch eine andere Karte testen.

Siehe Probleme beim Webtransfer - #20 von biologist.

Also ich verwende nach wie vor den uSD-Reader mittels SPI, wie auch den RC522.
Ich habe im Prinzip den Code von hier esp-idf/examples/protocols/http_server/file_serving at master · espressif/esp-idf · GitHub getestet bzw. adaptiert. Im Detail ist der code hier esp-idf/file_server.c at 97fb98a91b308d4f4db54d6dd1644117607e9692 · espressif/esp-idf · GitHub in der Funktion upload_post_handler().

Wie man sieht ist es da einfach eine Endlosschleife wo ein Buffer empfangen wird und mit fwrite() geschrieben wird. Relativ simpel, keine Semaphore, kein Ringbuffer oder ähnliches.

Funktioniert stabil, jedoch nicht gerade schnell. Ich komme auf etwa 1MB pro Sekunde, wenn keine Audio Wiedergabe stattfindet. Das ganze mit 16KB Buffer, ohne sonst noch was optimiert zu haben.

Mit Audio Wiedergabe nebenbei wird das langsamer, und die Audio-Wiedergabe kriegt Aussetzer. Was klar ist, weil der Flaschenhals ja der SPI-Bus ist, der dann doppelt belastet wird.
gut, da könnte man sicher den Buffer der Wiedergabe erhöhen - genug RAM ist ja da, aber der ist ja auch wieder mittels SPI angebunden :man_facepalming:

Was ich aber nicht hatte waren korrupte Files oder ähnliches. :+1:

Also besteht wohl die Hoffnung, dass mit einem Update von PIO bzw. der ESP-IDF hier auch noch Stabilität einkehrt mit SPI. :ok_hand:

„Nur“ 1 MB/s? Das wäre mal gut das Dreifache von dem, was wir per SDMMC haben :thinking:

Hast recht, vertan. 10MB pro Minute. Also ungefähr 1Mbps.

Ich hatte tatsächlich schon überlegt, ob ich alles neu machen muss und auf IDF wechsele :rofl:. Das wäre echt krass gewesen.
Aber ja, wäre schön, das SPI-Problem auch unter Arduino in den Griff zu kriegen.