miksi muistittamaton pitkä tappaa näytteenottonopeuteni?

Käytän Mega 2560 -laitetta yhteydenpitoon analogisten (ts. mitattujen analogRead () kautta) ja I2C-pohjaisten antureiden seoksen kanssa. Näytetiedot sijoitetaan 16-tavuinen taulukko, joka sitten kirjoitetaan SD-kortille, kun 512-tavuinen puskuri on täysin täytetty. Ongelma, johon törmään, on se, että kun kerään tietoja MAX30102-pulssioksimetristä käyttämällä

measure.pox = pulseOx.getIR(); 

alla olevasta koodistani collectHR () -silmukan sykliaika laskee noin 20 mS: iin. Jos varaan tämän paikan uudelleen käyttämällä suoraan sen alapuolella olevaa viivaa (tallentamalla vakion uuden uint32_t: n lukemisen sijaan), jakson kesto on noin puoli millisekuntia. Minua hämmentää se, että jos heitän uint32_t-merkkijonoon käyttämällä dtostrf-tiedostoa:

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

näytteen lukeminen tosiasiassa kestää vain noin 1,2 mS MAX30102. Minusta näyttää siltä, että suosimalla rakennetta merkkijonon yli (tämän koodin aikaisemmasta iteraatiosta, joka kirjoitti kaikki tiedot txt-tiedostoksi roskatiedoston sijaan), jotta voin kirjoittaa binaarisen SD-kortilleni, ” m ehdottomasti kuristin nopeutta. Eikö tavujen työskentelyn pitäisi olla tehokkaampaa kuin merkkijonolla työskenteleminen? Mitä tapahtuu muille 18 mS: lle, joka tapahtuu allekirjoittamattoman pitkän lukemisen ja tavutyyppisen puskurin, puskurin1, asettamisen välillä? Tämän koodin käyttöönotto merkkijonorakenteilla strukturin sijaan Pystyin juoksemaan noin 125 Hz: n tahdilla. Nyt olen noin 50 Hz: n taajuudella. Arvostan mitään näkemystä täällä. Asiaankuuluva koodi näkyy alla:

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

kommentit

  • järjestys Toimintojen näyttäminen hieman oudolta. Harkitse mitä tapahtuu heti alussa: buffLen on alun perin 0 ja korotat sen välittömästi arvoon 16 ja sitten kopioit tiedot puskuriin siirtymällä 16. Mutta entä ensimmäinen 16 tavua? Miksi jätit ne käyttämättä? Ei ole myöskään selvää, miksi sinun on jopa pumpattava tavuja jatkuvasti measure -kohdasta buffer1 , ts. muistista muistiin. Miksi ' t ilmoitetaan vain taulukko 32 struct measure elementtejä ja käyttää sitä suoraan?
  • Kiitos panoksestasi! Olet ' täysin oikeassa siinä, että ensimmäiset 16 tavua pysyvät tyhjinä. Alun perin ajattelin, että se tee se on helpompaa määrittää, milloin kukin collectHR () -silmukka päättyi tiedostoon etsimällä 16 0 ' s, mutta nyt kun osoitat sen, se näyttää olevan muistin tuhlausta. Olen siirtänyt lisäyksen alapuolelle. memcpy-kutsu tilille tätä varten. En ollut ' ajatellut heittää joukkoa rakenteita; ' Annan sen mennä. Onko sinulla käsitystä siitä, miksi erityisesti pulseOx.getIR () -kutsun memcpy on niin paljon hitaampi kuin aika, joka kuluu näiden 4 tavun noutamiseen anturista?
  • käytä unsigned int buffLenille, koska 15 * 3200 on enemmän kuin int voi kestää
  • Onko sinulla varmasti 512 tavua vapaata RAM-muistia? SDfat-kirjastossa on joka tapauksessa 512 tavun puskuri ja toinen itse tiedostojärjestelmälle. Se kirjoittaa fyysisesti SD: lle vain täydet lohkot.
  • Juraj Hyvä saalis, kiitos! Olen ' muuttanut tätä yllä. @DataFiddler Minulla on väitetysti jäljellä noin 5800 tavua pelata. ' Tiedän, että SDfat käyttää 512 tavun puskuria, mutta tarkoittako tämä sitä, että jokainen kirjoitus () -kutsu työntää 512 tavua kortille tai että kortille ei lähetetä mitään, ennen kuin 512 tavun arvoinen kirjoitus () kerääntyy? Valitettavasti millisSet () loukkoi sinua, olen ' poistanut sen. Yritin lähettää vain koodin asiaankuuluvat osat, mutta näyttää siltä, että olen unohtanut kyseisen muuttujan alkuperäisessä viestissä. Roskat poistetaan …

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *