proč je memcpy nepodepsaného dlouhého zabití mé vzorkovací rychlosti?

Používám Mega 2560 ke komunikaci se směsí analogových (tj. měřených pomocí analogRead ()) a senzorů založených na I2C. Vzorkovaná data se ukládají do 16 bajtové pole, poté zapsané na SD kartu, jakmile je 512 bajtová vyrovnávací paměť zcela zaplněna. Problém, se kterým se setkávám, spočívá v tom, že když shromažďuji data z pulzního oxymetru MAX30102 pomocí

measure.pox = pulseOx.getIR(); 

z mého kódu níže klesne doba cyklu mé smyčky collectHR () na asi 20 mS. Pokud toto místo předem určím pomocí řádku přímo pod ním (uložení konstanty namísto čtení nové smyčky uint32_t každé smyčky), můj čas cyklu je asi půl milisekundy. Co je pro mě matoucí, je to, že když vrhnu uint32_t do řetězce pomocí dtostrf:

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

trvá to jen asi 1,2 mS, aby se skutečně odečetl vzorek z MAX30102. Zdá se mi, že upřednostňováním struktury před řetězcem (z dřívější iterace tohoto kódu, který zapsal všechna data jako soubor txt namísto souboru bin), abych mohl na svoji SD kartu psát binárně, Absolutně škrtím svou rychlostí. Neměl by být bytewisewise efektivnější než práce s řetězcem? Co se děje s ostatními 18 mS, ke kterému dochází mezi čtením nepodepsaného dlouhého a jeho vložením do byte bufferu, buffer1? Implementace tohoto kódu pomocí řetězcových polí místo struktury, Byl jsem schopen běžet na přibližně 125 Hz. Teď jsem zhruba na 50 Hz. Ocenil bych zde jakýkoli přehled. Relevantní kód zobrazený níže:

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

Komentáře

  • Sekvence operací vypadá trochu divně. Zvažte, co se stane na samém začátku: buffLen je zpočátku 0, pak jej okamžitě zvýšíte na 16 a potom zkopírujete data do této vyrovnávací paměti při offset 16. A co první 16 bajty? Proč jste je nechali nevyužité? Také není jasné, proč dokonce potřebujete neustále pumpovat bajty z measure do buffer1 , tj. z paměti do paměti. Proč ' t prostě deklarovat pole 32 struct measure a používat je přímo?
  • Děkujeme za váš příspěvek! Máte ' úplnou pravdu, že prvních 16 bajtů zůstane prázdných. Původně jsem si myslel, že to bude Udělej to snazší určit, kdy každá smyčka collectHR () skončila v souboru, hledáním 16 0 ' s, ale nyní, když na to poukazujete, to vypadá jako úplné plýtvání pamětí. Posunul jsem přírůstek níže. Memcpy volání k účtu za to. Nenapadlo mě ' t obsazení řady struktur; ' to vyzkouším. Máte nějaký přehled o tom, proč je konkrétně memcpy volání pulseOx.getIR () mnohem pomalejší než čas potřebný k načtení těchto 4 bajtů ze senzoru?
  • use unsigned int pro buffLen, protože 15 * 3200 je více než int může trvat
  • Opravdu máte 512 bajtů volné paměti RAM? Knihovna SDfat stejně obsahuje 512 bajtovou vyrovnávací paměť a další pro samotný systém souborů. Fyzicky stejně zapisuje na SD pouze plné bloky.
  • Juraj Dobrý úlovek, díky! Toto jsem ' změnil výše. @DataFiddler Údajně mi zbývá asi 5800 bytů na hraní. Jsem si ' vědom toho, že SDfat využívá vyrovnávací paměť 512 bajtů, ale znamená to, že každé volání write () tlačí na kartu 512 bajtů, nebo že na kartu není odesláno vůbec nic, dokud Shromážděno je 512 bajtů za zápis ()? Omlouváme se, millisSet () vás urazil, odstranil jsem ho '. Snažil jsem se zveřejnit pouze příslušné části kódu, ale zdálo se, že mi tato proměnná v původním příspěvku chyběla. Odpadky jsou odstraněny …

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *