perché memcpy di unsigned long uccide la mia velocità di campionamento?

Sto usando un Mega 2560 per comunicare con una miscela di sensori analogici (cioè misurati tramite analogRead ()) e sensori basati su I2C. I dati campionati vengono inseriti in un array di 16 byte, quindi scritto su una scheda SD una volta che un buffer da 512 byte è completamente riempito. Il problema che sto incontrando è che quando raccolgo dati da un pulsossimetro MAX30102 utilizzando

measure.pox = pulseOx.getIR(); 

dal mio codice qui sotto, il tempo di ciclo del mio ciclo collectHR () scende a circa 20 mS. Se prealloco questo punto utilizzando la linea direttamente sotto di esso (memorizzando una costante invece di leggere un nuovo uint32_t ogni ciclo), il mio tempo di ciclo è di circa mezzo millisecondo. Quello che mi confonde è che se eseguo il cast di uint32_t in una stringa usando dtostrf:

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

ci vogliono solo circa 1,2 mS per leggere effettivamente un campione da il MAX30102. Mi sembra che preferendo una struttura a una stringa (da uniterazione precedente di questo codice che ha scritto tutti i dati come file txt invece di un file bin) in modo da poter scrivere binario sulla mia scheda SD, io ” Sto assolutamente rallentando la mia velocità. Il lavoro bytewise non dovrebbe essere più efficiente che lavorare con una stringa? Cosa sta succedendo agli altri 18 mS che si verificano tra la lettura del long senza segno e il suo inserimento nel buffer by byte, buffer1? Implementare questo codice utilizzando array di stringhe invece di una struttura, Sono stato in grado di funzionare a circa 125 Hz. Adesso sono a circa 50 Hz. Apprezzerei qualsiasi informazione qui. Codice pertinente mostrato di seguito:

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

Commenti

  • La sequenza delle operazioni sembra un po strano. Considera cosa succede allinizio: buffLen inizialmente è 0, quindi aumentalo immediatamente a 16 e poi copi i dati in quel buffer alloffset 16. Ma per quanto riguarda il primo 16 byte? Perché li hai lasciati inutilizzati? Inoltre, non è chiaro perché devi pompare costantemente byte da measure a buffer1 , cioè dalla memoria alla memoria. Perché non ' dichiarare semplicemente un array di 32 struct measure elementi e usarlo direttamente?
  • Grazie per il tuo contributo! ' hai assolutamente ragione che i primi 16 byte rimangono vuoti. Inizialmente avevo pensato che sarebbe stato fallo è più facile determinare quando ogni ciclo collectHR () è terminato nel file cercando 16 0 ', ma ora che lo indichi sembra un totale spreco di memoria. Ho spostato lincremento in basso. la chiamata memcpy per rendere conto di questo. Non avevo ' pensato di eseguire il cast di un array di strutture; ' ci provo. Hai qualche idea sul perché specificamente la memcpy della chiamata pulseOx.getIR () sia molto più lenta del tempo necessario per recuperare quei 4 byte dal sensore?
  • usa unsigned int per buffLen, perché 15 * 3200 è più di int può prendere
  • Sei sicuro di avere 512 byte di RAM libera? La libreria SDfat contiene comunque un buffer da 512 byte e un altro per il file system stesso. In ogni caso, scrive fisicamente su SD solo blocchi interi.
  • Juraj Buona presa, grazie! Ho ' modificato quanto sopra. @DataFiddler Presumibilmente mi restano circa 5800 byte con cui giocare. ' so che SDfat utilizza un buffer da 512 byte, ma ciò significa che ogni chiamata write () spinge 512 byte alla scheda o che non viene inviato nulla alla scheda finché Si accumulano 512 byte di write ()? Mi spiace millisSet () ti ha offeso, lho ' rimosso. Ho provato a pubblicare solo le parti pertinenti del codice ma sembra che non sia stata rilevata quella variabile nel post iniziale. La spazzatura viene rimossa …

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *