hvorfor dræber memcpy af usigneret lang min samplingshastighed?

Jeg bruger en Mega 2560 til at kommunikere med en blanding af analoge (dvs. målt via analogRead ()) og I2C-baserede sensorer. Samplede data placeres i en 16 byte array, derefter skrevet til et SD-kort, når en 512 byte buffer er fuldstændigt udfyldt. Problemet, jeg løber ind i er, at når jeg indsamler data fra et MAX30102 pulsoximeter ved hjælp af

measure.pox = pulseOx.getIR(); 

fra min kode nedenfor, falder cyklustiden for min collectHR () -sløjfe til ca. 20 mS. Hvis jeg forlokaliserer dette sted ved at bruge linjen lige under det (gemmer en konstant i stedet for at læse en ny uint32_t hver løkke), er min cyklustid ca. et halvt millisekund. Hvad der er forvirrende for mig, er at hvis jeg kaster uint32_t i en streng ved hjælp af dtostrf:

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

tager det kun ca. 1,2 mS at læse en prøve fra MAX30102. Det forekommer mig, at ved at favorisere en struct frem for en streng (fra en tidligere iteration af denne kode, der skrev alle data som en txt-fil i stedet for en bin-fil), så jeg kan skrive binært til mit SD-kort, jeg ” Jeg kvæler absolut min hastighed. Bør ikke arbejde bytevis være mere effektivt end at arbejde med en streng? Hvad sker der med de andre 18 mS, der opstår mellem at læse den usignerede long og placere den i byte buffer, buffer1? Implementere denne kode ved hjælp af streng arrays i stedet for en struct, Jeg var i stand til at køre ved cirka 125 Hz. Nu er jeg omkring 50 Hz. Jeg sætter pris på enhver indsigt her. Relevant kode vist nedenfor:

#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 af operationer ser lidt underligt ud. Overvej hvad der sker lige ved starten: buffLen er oprindeligt 0, så øger du det straks til 16 og derefter kopierer du dataene til den buffer ved offset 16. Men hvad med den første 16 bytes? Hvorfor forlod du dem ubrugte? Det er heller ikke klart, hvorfor du endda har brug for konstant at pumpe bytes fra measure til buffer1 , dvs. fra hukommelse til hukommelse. Hvorfor ikke ' t erklærer du bare en matrix med 32 struct measure elementer og bruge det direkte?
  • Tak for dit input! Du ' har helt ret i, at de første 16 bytes forbliver tomme. Jeg havde oprindeligt troet, at det ville lav det lettere at bestemme, hvornår hver collectHR () -sløjfe sluttede i filen ved at søge efter 16 0 ' s, men nu du påpeger det, virker det som et totalt spild af hukommelse. Jeg har flyttet stigningen til nedenunder. memcpy-opkaldet til regnskab for dette. Jeg havde ikke ' ikke tænkt på at kaste en række strukturer; Jeg ' giver det en chance. Har du noget indblik i, hvorfor specifikt memcpy af pulseOx.getIR () -opkaldet er så meget langsommere end den tid, det tager at hente de 4 bytes fra sensoren?
  • brug unsigned int til buffLen, fordi 15 * 3200 er mere end int kan tage
  • Er du sikker på at have 512 byte ledig RAM? SDfat-biblioteket har alligevel en 512 byte-buffer og en anden til selve filsystemet. Det skriver alligevel fysisk til SD kun fulde blokke.
  • Juraj God fangst, tak! Jeg ' har ændret dette ovenfor. @DataFiddler Jeg har angiveligt cirka 5800 byte tilbage at lege med. Jeg ' er opmærksom på, at SDfat bruger en 512 byte-buffer, men betyder det, at hvert skrive () -opkald skubber 512 byte til kortet, eller at der slet ikke sendes noget til kortet indtil 512 bytes værd at skrive () er samlet? Beklager millisSet () fornærmet dig, jeg ' har fjernet det. Jeg forsøgte at sende kun de relevante dele af koden, men synes at have savnet den variabel i det oprindelige indlæg. Affald fjernes …

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *