de ce memcpy de nesemnat omoară mult timp viteza de eșantionare?

Utilizez un Mega 2560 pentru a comunica cu un amestec de senzori analogici (adică măsurați prin analogRead ()) și I2C. Datele eșantionate sunt plasate în o matrice de 16 octeți, apoi scrisă pe un card SD odată ce un buffer de 512 octeți este complet umplut. Problema pe care o „întâlnesc este că atunci când colectez date dintr-un oximetru de impuls MAX30102 folosind

measure.pox = pulseOx.getIR(); 

din codul meu de mai jos, timpul ciclului buclei mele collectHR () scade la aproximativ 20 mS. Dacă prealocez acest loc folosind linia direct sub el (stocând o constantă în loc să citesc un nou uint32_t fiecare buclă), durata ciclului meu este de aproximativ o jumătate de milisecundă. Ceea ce este confuz pentru mine este că, dacă arunc uint32_t într-un șir folosind dtostrf:

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

este nevoie de aproximativ 1,2 mS pentru a citi de fapt un eșantion din MAX30102. Mi se pare că, favorizând o structură peste un șir (dintr-o iterație anterioară a acestui cod care scria toate datele ca fișier txt în loc de fișier bin), astfel încât să pot scrie binare pe cardul meu SD, Îmi strâng absolut viteza. Nu ar trebui să funcționeze bytewise să fie mai eficient decât să lucrați cu un șir? Ce se întâmplă cu celelalte 18 mS care se întâmplă între citirea lungului nesemnat și plasarea acestuia în buffer byte, buffer1? Implementarea acestui cod folosind matrice de șiruri în loc de struct, Am reușit să rulez la aproximativ 125 Hz. Acum sunt la aproximativ 50 Hz. Aș aprecia orice perspectivă aici. Codul relevant prezentat mai jos:

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

Comentarii

  • Secvența operațiunilor pare puțin ciudat. Luați în considerare ce se întâmplă la început: buffLen este inițial 0, apoi îl măriți imediat la 16 și apoi copiați datele în acel tampon la offset 16. Dar ce zici de primul 16 octeți? De ce i-ați lăsat neutilizați? De asemenea, nu este clar de ce trebuie chiar să pompați în mod constant octeți de la measure la buffer1 , adică de la memorie la memorie. De ce nu ' doar declarați o matrice de 32 struct measure elemente și utilizați-l direct?
  • Vă mulțumim pentru contribuția dvs.! ' aveți perfectă dreptate că primii 16 octeți rămân goi. Crezusem inițial că va fi Fă-o mai ușor de determinat când fiecare buclă collectHR () s-a încheiat în fișier căutând 16 0 ' s, dar acum, când îl subliniați, pare o pierdere totală de memorie. Am mutat incrementul mai jos. apelul memcpy pentru a contabiliza acest lucru. Nu m-am gândit ' să mă gândesc să arunc o serie de structuri; ' voi face asta. Aveți vreo perspectivă despre motivul în care memcpy în mod specific apelului pulseOx.getIR () este mult mai lent decât timpul necesar pentru a prelua acei 4 octeți de la senzor?
  • utilizați unsigned int pentru buffLen, deoarece 15 * 3200 este mai mult decât poate dura int
  • Sigur aveți 512 octeți de memorie RAM gratuită? Biblioteca SDfat deține oricum un buffer de 512 octeți și altul pentru sistemul de fișiere în sine. Oricum scrie fizic pe SD numai blocuri complete.
  • Juraj Bună captură, mulțumesc! Am ' modificat mai sus. @DataFiddler Mi-ar fi rămas aproximativ 5800 de octeți cu care să mă joc. ' știu că SDfat folosește un tampon de 512 octeți, dar înseamnă că fiecare apel write () împinge 512 octeți pe card sau că nimic nu este trimis deloc pe card până 512 octeți în valoare de write () sunt adunați? Ne pare rău, millisSet () v-a jignit, l-am eliminat '. Am încercat să postez doar porțiunile relevante ale codului, dar par să fi ratat acea variabilă în postarea inițială. Gunoaiele sunt eliminate …

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *