varför dödar minnet av osignerad länge min samplingshastighet?

Jag använder en Mega 2560 för att kommunicera med en blandning av analoga (dvs mätt via analogRead ()) och I2C-baserade sensorer. Samplade data placeras i en 16 byte array, sedan skriven till ett SD-kort när en 512 byte buffert är helt fylld. Problemet jag stöter på är att när jag samlar in data från en MAX30102 pulsoximeter med hjälp av

measure.pox = pulseOx.getIR(); 

från min kod nedan sjunker cykeltiden för min collectHR () -slinga till cirka 20 mS. Om jag förlokaliserar den här platsen genom att använda linjen direkt under den (lagra en konstant istället för att läsa en ny uint32_t varje slinga), är min cykeltid ungefär en halv millisekund. Det som är förvirrande för mig är att om jag kastar uint32_t i en sträng med dtostrf:

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

tar det bara cirka 1,2 mS att faktiskt läsa ett prov från MAX30102. Det verkar för mig att genom att gynna en struktur framför en sträng (från en tidigare iteration av den här koden som skrev all data som en txt-fil istället för en bin-fil) så att jag kan skriva binärt till mitt SD-kort, jag ” jag stryker absolut min hastighet. Borde inte arbeta bytevis mer effektivt än att arbeta med en sträng? Vad händer med de andra 18 mS som uppstår mellan att läsa den osignerade longen och placera den i byte-buffert, buffer1? Implementera den här koden med hjälp av strängarrayer istället för en struktur Jag kunde springa vid cirka 125 Hz. Nu är jag ungefär 50 Hz. Jag uppskattar all insikt här. Relevant kod som visas nedan:

#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()); } } 

Kommentarer

  • Sekvensen av operationer ser lite konstigt ut. Tänk på vad som händer i början: buffLen är initialt 0, sedan ökar du omedelbart till 16 och sedan kopierar du data till den bufferten vid offset 16. Men hur är det med den första 16 byte? Varför lämnade du dem oanvända? Det är inte klart varför du ens behöver pumpa byte hela tiden från measure till buffer1 , dvs. från minne till minne. Varför don ' t du bara förklarar en matris med 32 struct measure element och använda det direkt?
  • Tack för din inmatning! Du ' har helt rätt att de första 16 bytes förblir tomma. Jag hade ursprungligen trott att det skulle gör det lättare att bestämma när varje collectHR () -slinga slutade i filen genom att söka efter 16 0 ' s, men nu när du påpekar det verkar det som ett totalt slöseri med minne. Jag har flyttat steget till nedan. memcpy-anropet till konto för detta. Jag hade inte ' tänkt på att kasta en rad strängar; Jag ' Jag ger det en chans. Har du någon inblick i varför specifikt memcpy av pulseOx.getIR () -samtalet är så mycket långsammare än den tid det tar att hämta dessa 4 byte från sensorn?
  • använd unsigned int för buffLen, eftersom 15 * 3200 är mer än int kan ta
  • Är du säker på att du har 512 byte ledigt RAM-minne? SDfat-biblioteket har ändå en 512 byte buffert och en annan för själva filsystemet. Det skriver fysiskt bara till SD till alla block.
  • Juraj Bra fångst, tack! Jag ' har ändrat detta ovan. @DataFiddler Jag har enligt uppgift cirka 5800 byte kvar att spela med. Jag ' är medveten om att SDfat använder en 512 byte buffert, men betyder det att varje skriv () -anrop driver 512 byte till kortet, eller att ingenting skickas till kortet alls tills 512 bytes värd att skriva () samlas? Tyvärr millisSet () förolämpade dig, jag ' har tagit bort den. Jag försökte bara posta relevanta delar av koden men verkar ha missat den variabeln i det första inlägget. Avfall tas bort …

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *