waarom is mijn geheugen van unsigned lang het doden van mijn bemonsteringssnelheid?

Ik gebruik een Mega 2560 om te communiceren met een combinatie van analoge (dwz gemeten via analogRead ()) en op I2C gebaseerde sensoren. De steekproefgegevens worden in een array van 16 bytes, en vervolgens naar een SD-kaart geschreven zodra een buffer van 512 bytes volledig is gevuld. Het probleem dat ik tegenkom is dat wanneer ik gegevens van een MAX30102-pulsoximeter verzamel met

measure.pox = pulseOx.getIR(); 

uit mijn onderstaande code, daalt de cyclustijd van mijn collectHR () -lus tot ongeveer 20 mS. Als ik deze plek vooraf toewijs door de regel er direct onder te gebruiken (een constante opslaan in plaats van elke lus een nieuwe uint32_t te lezen), is mijn cyclustijd ongeveer een halve milliseconde. Wat voor mij verwarrend is, is dat als ik de uint32_t in een string cast met dtostrf:

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

het slechts ongeveer 1,2 mS duurt om daadwerkelijk een sample te lezen van de MAX30102. Het lijkt mij dat door de voorkeur te geven aan een struct boven een string (van een eerdere iteratie van deze code die alle gegevens als een txt-bestand schreef in plaats van een bin-bestand), zodat ik binair naar mijn SD-kaart kan schrijven, ik ” Ik beperk mijn snelheid absoluut. Zou bytesgewijs werken niet efficiënter moeten zijn dan werken met een string? Wat gebeurt er met de andere 18 mS die optreedt tussen het lezen van de unsigned long en het plaatsen in bytebuffer, buffer1? Implementatie van deze code met behulp van string-arrays in plaats van een struct, Ik kon draaien op ongeveer 125 Hz. Nu ben ik op ongeveer 50 Hz. Ik zou hier elk inzicht op prijs stellen. Relevante code hieronder weergegeven:

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

Opmerkingen

  • De volgorde van bewerkingen ziet er een beetje vreemd uit. Bedenk wat er aan het begin gebeurt: buffLen is aanvankelijk 0, daarna verhoog je het onmiddellijk naar 16 en vervolgens kopieer je de gegevens naar die buffer op offset 16. Maar hoe zit het met de eerste 16 bytes? Waarom heb je ze ongebruikt gelaten? Het is ook niet duidelijk waarom je constant bytes moet pompen van measure naar buffer1 , dwz van geheugen naar geheugen. Waarom ' t u niet gewoon een array van 32 struct measure elementen en direct gebruiken?
  • Bedankt voor je input! Je ' hebt helemaal gelijk dat de eerste 16 bytes leeg blijven. Ik had aanvankelijk gedacht dat Maak het gemakkelijker te bepalen wanneer elke collectHR () -lus in het bestand eindigde door te zoeken naar 16 0 ' s, maar nu je erop wijst, lijkt het een totale verspilling van geheugen. Ik heb de stap naar beneden verplaatst. de memcpy-oproep om hier rekening mee te houden. Ik had niet ' er aan gedacht om een reeks structs te casten; Ik ' zal het proberen. Heb je enig inzicht waarom specifiek de memcpy van de pulseOx.getIR () aanroep zoveel langzamer is dan de tijd die nodig is om die 4 bytes van de sensor op te halen?
  • gebruik unsigned int voor buffLen, omdat 15 * 3200 meer is dan int aankan
  • Weet je zeker dat je 512 byte vrij RAM hebt? De SDfat-bibliotheek bevat sowieso een buffer van 512 bytes en een andere voor het bestandssysteem zelf. Het schrijft hoe dan ook fysiek naar SD.
  • Juraj Goede vangst, bedankt! Ik ' heb dit hierboven gewijzigd. @DataFiddler Ik heb naar verluidt ongeveer 5800 bytes over om mee te spelen. Ik ' ben me ervan bewust dat SDfat een buffer van 512 bytes gebruikt, maar betekent dit dat elke write () aanroep 512 bytes naar de kaart duwt, of dat er helemaal niets naar de kaart wordt verzonden totdat 512 bytes aan write () zijn verzameld? Sorry millisSet () heeft u beledigd, ik ' heb het verwijderd. Ik heb geprobeerd om alleen de relevante delen van de code te posten, maar het lijkt erop dat ik die variabele in de eerste post heb gemist. Afval wordt verwijderd …

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *