Verzögerungspeaks beim Speichern von Daten

Hallo zusammen,

ich lese mit meinem Arduino Uno analoge Sensorwerte ein, filtere diese und speichere sie über ein SD-Karten-Shield von Adafruit auf einer SD-Karte. Das funktioniert alles reibungslos. Ich nimm über den Befehl “millis()” noch die Millisekunden auf. Nun wollte ich mal sehen, nach wievielen Millisekunden meine Werte im Durchschnitt gespeichert werden und habe diese Peaks entdeckt, wo der Arduino fast 10 mal solange braucht um diese Werte zu speichern (Siehe Bild/ Diagramm - x-Achse: Zeit in ms; y-Achse Zeit bis zum nächsten Messwert in ms).
Das merkwürdige daran ist, dass die Werte 5 mal periodisch auftreten und zwar immer nach 486 Werten und dann auf einmal keine Peaks mehr kommen. Das Programm läuft im Loop immer einmal komplett durch und speichert am Ende die Werte.

Hat jemand eine Idee an was es liegen könnte?
Falls ihr noch irgendwelche Infos braucht gebe ich die gerne noch weiter.

Grüße
arpe

Die Sektor Größe ist 512 Byte.
Ein solcher Buffer wird immer in einem Rutsch geschrieben/gelesen.

Auch braucht das Wearleveling zwischendurch Verwaltungszeit.

combie:
Die Sektor Größe ist 512 Byte.
Ein solcher Buffer wird immer in einem Rutsch geschrieben/gelesen.

Ok. Das heißt nach einem "Sektor" braucht er immer mehr Zeit, um die ganzen Daten zu schreiben?
Falls ich das so richtig verstanden habe, wie kann man dann die Zeit danach erklären, wo die Peaks nicht mehr erscheinen?

arpe:
Ok. Das heißt nach einem "Sektor" braucht er immer mehr Zeit, um die ganzen Daten zu schreiben?
Falls ich das so richtig verstanden habe, wie kann man dann die Zeit danach erklären, wo die Peaks nicht mehr erscheinen?

Die Daten werden in den Buffer im RAM geschrieben (geht sschnell) und wenn dieser voll ist wird dieser auf die SD geschrieben (scheint lngsam zu sein).

grüße Uwe

?

Wie schon gesagt: Die Dinger haben ein Eigenleben.
Der jeweilige Hersteller könnte Auskunft geben.

Danke schon mal für die schnellen Antworten!

Das heißt ihr meint die Peaks könnten an dem liegen, dass die Speicher immer im Packet übergeben werden. Wenn das so sein sollte, warum gibts dann ab einem bestimmten Zeitpunkt kein Verzögerungspeak mehr? Ich messe da ja andauernd weiter ohne Unterbrechung. An dem was ich messe kann es eigentlich auch nicht liegen (siehe Bild2).
Aus meiner Sicht müsste sich das durchziehen oder keine geben. So wie es aber auf dem Bild ist verstehe ich es nicht.

Teste doch spaßeshalber eine andere sd-Karte

Merkwürdigerweise kamen diese Peaks nur noch gelegentlich und überhaupt nicht periodisch.

Zu der Zeitthematik hätte ich noch eine Frage. So viel ich jetzt gelesen habe sollte der Arduino Uno mit dem ADC und dem Befehl analogRead ca. alle 100 us ein Wert einlesen. In den Bilder oben kann man erkennen, dass nur alle 25ms ein Wert gelesen wird.
Könnte das an dem Shield liegen? So viel ich weiß wird das über SPI kommuniziert. Gibt es da auch soetwas wie eine Standardgeschwindigkeit wie beim seriellen Monitor die Baudrate?

Grüße arpe

Hi

Versendest Du auch irgendwelche Variablen/Texte per Serial.print()?
Bei 9600 Baud braucht jedes Byte - also JEDES ZEICHEN - eine ms Zeit.
9600 Baud = 9600 Bit in der Sekunde - bei der seriellen Übertragung werden 10 Bit für einen 8-Bit-Wert benötigt, macht 1/1000stel Sekunde (also knapp - bei 10000 Baud würde Das ganz genau hinkommen).

Bedenke: Wir sehen bis jetzt nur zwei Bilder - vom Sketch fehlt noch jede Spur.
Oder vom Aufbau - wobei Der (noch) nicht wichtig sein dürfte.

MfG

arpe:
In den Bilder oben kann man erkennen, dass nur alle 25ms ein Wert gelesen wird.
Könnte das an dem Shield liegen?

Ich bin mir ziemlich sicher, dass das jemand in deinem Sketch so programmiert hat.

#include <SPI.h>
#include <SD.h>

File myFile;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  start = 1;
}

void loop() {
  // put your main code here, to run repeatedly:
  if (start == 1)
  {
    while (!Serial)
    {
      ;
    }
    if (!SD.begin(10))
    {
      while(1);
    }
    myFile = SD.open("R5G4V19.txt", FILE_WRITE);
    if (myFile)
    {
      myFile.println("time[ms] Rohwert MWFilter1 MWFilter2 MWFilter3  OffsetfreiRC Offsetfrei");
    myFile.close();
    }
    analogA0 = analogRead(A0);
    Offset = analogA0 - 512; 
    start = 0;
  }


    timems = millis();
    
    analogA0 = analogRead(A0);
    analogA3 = analogRead(A3);
    analogOffsetfrei = analogA0 - Offset;
    analogOffsetfreiRC = analogA3 - Offset;
  
    Index++;
    if (Index > 7)
    {
      Index = 0;
    }
    ArrayMittelwert[Index] = analogOffsetfrei;
    for (int i = 0; i < 7; i++)
    {
      analogFilter += ArrayMittelwert[i];
    }
    analogFilter = analogFilter / 8;

    Index2++;
    if (Index2 >21)
    {
      Index2 = 0;
    }
    ArrayMittelwert2[Index2] = analogFilter;
    for (int j = 0; j < 21; j++)
    {
      analogFilter2 += ArrayMittelwert2[j];
    }
    analogFilter2 = analogFilter2 / 22;

    Index3++;
    if (Index3 >65)
    {
      Index3 = 0;
    }
    ArrayMittelwert3[Index3] = analogFilter;
    for (int k = 0; k < 65; k++)
    {
      analogFilter3 += ArrayMittelwert3[k];
    }
    analogFilter3 = analogFilter3 / 66;

    myFile = SD.open("R5G4V19.txt", FILE_WRITE);
    if (myFile)
    {
      myFile.print(timems);
      myFile.print("\t");
      myFile.print(analogA0);
      myFile.print("\t");
      myFile.print(analogFilter);
      myFile.print("\t");
      myFile.print(analogFilter2);
      myFile.print("\t");
      myFile.print(analogFilter3);
      myFile.print("\t");
      myFile.print(analogOffsetfreiRC);
      myFile.print("\t");
      myFile.println(analogOffsetfrei);
    }
    myFile.close(); 
  
}

Das ist mein Code, falls das vielleicht weiterhelfen kann. Ich übertrage keine Werte über den Seriellen weg, weshalb mein Anfang vom Code wohl unnötig ist. Fällt mir erst jetzt auf…
Könnte neben der SD-Karte selbst, die Kommunikation über SPI der zeitkritische Weg sein? Oder meint ihr es hat auf jeden Fall mit dem Programm zu tun?

Grüße arpe

das ist aber nicht der Sketch von den Diagrammen?

Der Code ist nicht mal kompilierfähig, da die Variablendeklarationen fehlen.

Gruß Tommy

Und die seriellen Ausgaben fehlen auch

Tommy56:
Der Code ist nicht mal kompilierfähig, da die Variablendeklarationen fehlen.

Gruß Tommy

Die hatte ich rausgeschmissen, damit das ganze nicht so lang wird hier.

ElEspanol:
Und die seriellen Ausgaben fehlen auch

Wie im letzten Post erwähnt, habe ich keine serielle Kommunikation sondern schreibe alle Daten nur auf die SD Karte. D.h. ich habe auch kein “Serial.print”.

Hier mal der gesamte Code komplett ohne Veränderung. Tatsächlich war der Ausschnitt von einer anderen Version, im gesamten hat sich aber eigentlich nichts verändert:

#include <FilterDerivative.h>
#include <FilterOnePole.h>
#include <Filters.h>
#include <FilterTwoPole.h>
#include <FloatDefine.h>
#include <RunningStatistics.h>
#include <SPI.h>
#include <SD.h>

int start;
float analogA0;
float Offset;
float analogOffsetfrei = 0;
float analogFilter = 0;
float analogFilter2 = 0;
float analogFilter3 = 0;
float Spannung;
float Drehmoment;
int Index = 10;
int Index2 = 30;
int Index3 = 100;
int ArrayMittelwert[8];
int ArrayMittelwert2[22];
int ArrayMittelwert3[66];
unsigned long timems;
unsigned int timesec;
unsigned int timemin;
float filterFrequency = 5.0;
unsigned long n;

File myFile;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  start = 1;
  n = 1;
}

void loop() {
  // put your main code here, to run repeatedly:
  if (start == 1)
  {
    while (!Serial)
    {
      ;
    }
    if (!SD.begin(10))
    {
      while(1);
    }
    myFile = SD.open("R5G4V11.txt", FILE_WRITE);
    if (myFile)
    {
      myFile.println("time  time[ms]  Rohwert Offsetfrei LPFilter  MWFilter1 MWFilter2 MWFilter3");
      myFile.close();
    }
    analogA0 = analogRead(A0);
    Offset = analogA0 - 512; 
    start = 0;
  }
  
  RunningStatistics inputStats;
  FilterOnePole lowpassFilter(LOWPASS, filterFrequency);
  RunningStatistics lowpassFilterStats;

  while (true)
  {
    timems = millis();
    if (timems > n * 1000)
    {
      n ++;
      timesec ++;
      if (timesec >= 60)
      {
        timesec = 0;
        timemin ++;
      }
    }
        
    analogA0 = analogRead(A0);
    analogOffsetfrei = analogA0 - Offset;
  
    Index++;
    if (Index > 7)
    {
      Index = 0;
    }
    ArrayMittelwert[Index] = analogOffsetfrei;
    for (int i = 0; i < 7; i++)
    {
      analogFilter += ArrayMittelwert[i];
    }
    analogFilter = analogFilter / 8;

    Index2++;
    if (Index2 >21)
    {
      Index2 = 0;
    }
    ArrayMittelwert2[Index2] = analogFilter;
    for (int j = 0; j < 21; j++)
    {
      analogFilter2 += ArrayMittelwert2[j];
    }
    analogFilter2 = analogFilter2 / 22;

    Index3++;
    if (Index3 >65)
    {
      Index3 = 0;
    }
    ArrayMittelwert3[Index3] = analogFilter;
    for (int k = 0; k < 65; k++)
    {
      analogFilter3 += ArrayMittelwert3[k];
    }
    analogFilter3 = analogFilter3 / 66;

    Spannung = (analogFilter3 / 1024) * 5;
    Drehmoment = ((analogFilter3 / 1024) * 100) - 50;

    inputStats.input (analogOffsetfrei);
    lowpassFilter.input(analogOffsetfrei);
    lowpassFilterStats.input(lowpassFilter.output());

    myFile = SD.open("R5G4V11.txt", FILE_WRITE);
    if (myFile)
    {
      myFile.print(timemin);
      myFile.print(":");
      myFile.print(timesec);
      myFile.print("\t");
      myFile.print(timems);
      myFile.print("\t");
//      myFile.print(Durchlauf);
//      myFile.print("\t");
      myFile.print(analogA0);
      myFile.print("\t");
      myFile.print(analogOffsetfrei);
      myFile.print("\t");
      myFile.print(lowpassFilterStats.mean());
      myFile.print("\t");
      myFile.print(analogFilter);
      myFile.print("\t");
      myFile.print(analogFilter2);
      myFile.print("\t");
      myFile.println(analogFilter3);
/*      myFile.print("\t");
      myFile.print(Out);
      myFile.print("\t");
      myFile.print(Spannung);
      myFile.print("\t");
      myFile.print(Drehmoment);
      myFile.print("\t");
      myFile.println(DrehmomentRund); */
    }
    myFile.close(); 
  }
}

Wie auch schon im letzten Post erwähnt ist mir aufgefallen, dass das “Serial.begin” eigentlich überflüssig ist, weil ich keine Serielle Kommunikation habe bzw. nur SPI zum Shield.
Falls noch was benötigt wird, was man noch wissen müsste, nur zu :slight_smile:

Grüße arpe

Und woher kommen die Diagramme im ersten Beitrag?

Und schreibst du wirklich in jedem loop auf die Karte? Oder hab ich da was übersehen?

ElEspanol:
Und woher kommen die Diagramme im ersten Beitrag?

Die erstelle ich nachträglich mithilfe der Daten auf der SD-Karte.

ElEspanol:
Und schreibst du wirklich in jedem loop auf die Karte? Oder hab ich da was übersehen?

Ja das siehst du richtig. Der Gedanke war da ursprünglich, dass man immer mit relativ gleicher Zeit die Daten überträgt und nicht alle 50 Werte oder so die Werte übertragen werden, wo dann eine hohe Verzögerung erzeugt wird.

Bin gerade dabei, deinen Sketch zu verstehen.

Wie kommst du aus der „while (true)“ Schleife raus?

ElEspanol:
Wie kommst du aus der „while (true)“ Schleife raus?

Gar nicht mehr, es ist quasi mein selbsterzeugter Loop. Der Sketch ist jetzt nicht gerade ein Vorzeigeskatch, aber er funktioniert soweit, nur das mit der Zeit ist komisch.

"das mit der Zeit" bei SD Karten ist normal, und zeigt, dass so eine Karte weit mehr als nur ein Speicher ist.

Auf Arduino - Seite optimieren (im Mittel schneller schreiben) geht nur, wenn du seltener close() aufrufst.

Dass dein Sketch kein Vorzeigesketch ist, stimme ich dir zu :wink: