dlaczego memcpy unsigned long zmniejsza prędkość próbkowania?

Używam Mega 2560 do komunikacji z mieszanką czujników analogowych (tj. mierzonych za pomocą analogRead ()) i czujników opartych na I2C. Próbkowane dane są umieszczane w 16-bajtowa tablica, a następnie zapisywana na karcie SD po całkowitym zapełnieniu 512-bajtowego bufora. Problem, z którym się spotykam, polega na tym, że kiedy zbieram dane z pulsoksymetru MAX30102 za pomocą

measure.pox = pulseOx.getIR(); 

z mojego kodu poniżej, czas cyklu mojej pętli collectHR () spada do około 20 mS. Jeśli wstępnie przydzielę to miejsce, używając linii bezpośrednio pod nim (przechowując stałą zamiast odczytywania nowej pętli uint32_t), mój czas cyklu wynosi około pół milisekundy. Mylące jest dla mnie to, że jeśli rzucę uint32_t na łańcuch za pomocą dtostrf:

dtostrf(pulseOx.getIR(),3,0,pOxBuf); // read pulseOx, convert it into a 3 byte string 

odczytanie próbki z MAX30102. Wydaje mi się, że faworyzując strukturę nad ciągiem (z wcześniejszej iteracji tego kodu, który zapisywał wszystkie dane jako plik txt zamiast pliku bin), dzięki czemu mogę zapisać plik binarny na mojej karcie SD, ja ” m absolutnie dławi moją prędkość. Czy praca „bajtowo” nie powinna być bardziej wydajna niż praca ze stringiem? Co dzieje się z pozostałymi 18 ms, które zachodzą między odczytem długości bez znaku i umieszczeniem go w buforze bajtowym, buffer1? Implementacja tego kodu przy użyciu tablic ciągów zamiast struktury, Mogłem pracować z częstotliwością około 125 Hz. Teraz mam około 50 Hz. Byłbym wdzięczny za wszelkie uwagi tutaj. Odpowiedni kod pokazany poniżej:

#include <Wire.h> #include "MAX30105.h" #include <SPI.h> #include <SdFat.h> #define moisture0 A0 // Upper back sensor analog pin #define moisture1 A7 // Trunk sensor analog pin #define ECGpin A3 // ECG analog pin SdFat SD; // replace SD with SDfat. File sdLog; // placeholder to create datalogger struct meas // a 16 byte structure to hold all of our measurements { unsigned long mils; int ECG; uint32_t pox; int tempInt; int m1; int m2; }; struct meas measure; // create an instance of the above structure byte buffer1[512]; byte *measureLoc = (byte *) &measure; // to access measure structure as bytes char fileName[] = "WIHMSlog.bin"; void setup { Serial.begin(230400); } void loop() { sdLog = SD.open(fileName, O_WRITE | O_CREAT | O_AT_END); // Create file for the datalogging and verify its existance collectHR(); sdlog.close() } void collectHR() { unsigned int loopCount = 0; int buffLen = 0; // starting position in buffer int buffSize = 16; while (loopCount < 3200) { // some multiple of 32 (since 512 byte/sd block divided by 16 bytes per loop cycle = 32 cycles per sd write cycle measure.ECG = analogRead(ECGpin); // read ECG and stick the int into measures measure.pox = pulseOx.getIR(); //measure.pox = 5555; // Placeholder value measure.mils = micros(); measure.m1 = analogRead(moisture0); measure.m2 = loopCount; // just a test to ensure this is actually iterating in the card if (buffLen == 512) { // SD buffer is full, time to write! sdLog.write(buffer1, 512); buffLen = 0; } memcpy(buffer1 + buffLen, measureLoc, buffSize); // place the 16 byte data structure into the buffer buffLen = buffLen + buffSize; // increase the index size in the array loopCount++; Serial.println(micros()); } } 

Komentarze

  • Sekwencja operacji wygląda trochę dziwnie. Zastanów się, co dzieje się na samym początku: buffLen to początkowo 0, a następnie natychmiast zwiększasz do 16, a następnie kopiujesz dane do tego bufora z przesunięciem 16. Ale co z pierwszym 16 bajtów? Dlaczego zostawiłeś je nieużywane? Poza tym nie jest jasne, dlaczego musisz nawet ciągle pompować bajty z measure do buffer1 , tj. z pamięci do pamięci. Dlaczego nie ', po prostu deklarujesz tablicę 32 struct measure i użyć go bezpośrednio?
  • Dziękujemy za informację! ' masz absolutną rację, że pierwsze 16 bajtów pozostaje pustych. Początkowo myślałem, że tak Zrób to łatwiej jest określić, kiedy każda pętla collectHR () zakończyła się w pliku, wyszukując 16 0 ' s, ale teraz, kiedy to wskazałeś, wydaje się, że jest to całkowita strata pamięci. Przeniosłem przyrost poniżej. wezwanie memcpy do wyjaśnienia tego. Nie pomyślałem ' o rzutowaniu tablicy struktur; ' dam sobie radę. Czy masz jakiś wgląd w to, dlaczego w szczególności memcpy wywołania pulseOx.getIR () jest o wiele wolniejsze niż czas potrzebny do pobrania tych 4 bajtów z czujnika?
  • użyj unsigned int dla buffLen, ponieważ 15 * 3200 to więcej niż int może zająć
  • Czy na pewno masz 512 bajtów wolnej pamięci RAM? Biblioteka SDfat i tak przechowuje 512-bajtowy bufor i inny dla samego systemu plików. Fizycznie i tak zapisuje do SD tylko pełne bloki.
  • Juraj Dobry chwyt, dzięki! ' zmieniłem to powyżej. @DataFiddler Mam podobno około 5800 bajtów do zabawy. ' Jestem świadomy, że SDfat używa 512-bajtowego bufora, ale czy to oznacza, że każde wywołanie write () wypycha 512 bajtów na kartę, czy też nic nie jest wysyłane na kartę, dopóki Zgromadzono 512 bajtów funkcji write ()? Przepraszam, że millisSet () cię obraził, ' usunąłem go. Próbowałem opublikować tylko odpowiednie fragmenty kodu, ale wydaje mi się, że przegapiłem tę zmienną w początkowym poście. Śmieci są usuwane …

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *