¿Por qué memcpy de unsigned long está matando mi velocidad de muestreo?

Estoy usando un Mega 2560 para comunicarme con una combinación de sensores analógicos (es decir, medidos a través de analogRead ()) e I2C. Los datos muestreados se colocan en una matriz de 16 bytes, luego se escribe en una tarjeta SD una vez que un búfer de 512 bytes está completamente lleno. El problema con el que me encuentro es que cuando recopilo datos de un oxímetro de pulso MAX30102 usando

measure.pox = pulseOx.getIR(); 

de mi código a continuación, el tiempo de ciclo de mi ciclo collectHR () cae a unos 20 mS. Si preasigno este lugar usando la línea directamente debajo de él (almacenando una constante en lugar de leer un nuevo uint32_t en cada ciclo), mi tiempo de ciclo es de aproximadamente medio milisegundo. Lo que me confunde es que si lanzo el uint32_t en una cadena usando dtostrf:

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

solo se necesitan alrededor de 1.2 mS para leer una muestra de el MAX30102. Me parece que al favorecer una estructura sobre una cadena (de una iteración anterior de este código que escribió todos los datos como un archivo txt en lugar de un archivo bin) para poder escribir binario en mi tarjeta SD, yo » Estoy estrangulando absolutamente mi velocidad. ¿No debería ser más eficiente trabajar bytewise que trabajar con una cadena? ¿Qué sucede con los otros 18 mS que ocurren entre la lectura del unsigned long y su ubicación en el búfer byte, buffer1? Implementando este código usando matrices de cadenas en lugar de una estructura, Pude correr a aproximadamente 125 Hz. Ahora estoy aproximadamente a 50 Hz. Agradecería cualquier información aquí. El código relevante se muestra a continuación:

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

Comentarios

  • La secuencia de operaciones parece un poco extraño. Considere lo que sucede desde el principio: buffLen es inicialmente 0, luego lo aumenta inmediatamente a 16 y luego copia los datos a ese búfer en el desplazamiento 16. Pero, ¿qué pasa con el primer 16 bytes? ¿Por qué no los usaste? Además, no está claro por qué necesitas bombear bytes constantemente desde measure a buffer1 , es decir, de memoria a memoria. ¿Por qué no ' t simplemente declara una matriz de 32 struct measure y usarlo directamente?
  • ¡Gracias por tu entrada! Tienes ' tienes toda la razón en que los primeros 16 bytes permanecen vacíos. Inicialmente pensé que hazlo Es más fácil determinar cuándo terminó cada bucle de CollectHR () en el archivo buscando 16 0 ' s, pero ahora que lo señala, parece una pérdida total de memoria. He movido el incremento hacia abajo. la llamada memcpy para dar cuenta de esto. No había ' t pensado en lanzar una matriz de estructuras; ' lo intentaré. ¿Tiene alguna idea de por qué específicamente la memoria de la llamada pulseOx.getIR () es mucho más lenta que el tiempo que lleva recuperar esos 4 bytes del sensor?
  • use unsigned int para buffLen, porque 15 * 3200 es más de lo que int puede tomar
  • ¿Está seguro de tener 512 bytes de RAM libre? La biblioteca SDfat tiene un búfer de 512 bytes de todos modos y otro para el sistema de archivos en sí. De todos modos, escribe físicamente en SD solo bloques completos.
  • Juraj ¡Buena captura, gracias! ' he modificado esto anteriormente. @DataFiddler Supuestamente me quedan unos 5800 bytes para jugar. Soy ' consciente de que SDfat utiliza un búfer de 512 bytes, pero ¿eso significa que cada llamada de escritura () envía 512 bytes a la tarjeta, o que no se envía nada a la tarjeta hasta ¿Se acumulan 512 bytes de write ()? Lo siento, millisSet () te ofendió, ' lo eliminé. Intenté publicar solo las partes relevantes del código, pero parece que me perdí esa variable en la publicación inicial. La basura se elimina …

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *