por que memcpy de unsigned está matando minha velocidade de amostragem?

Estou usando um Mega 2560 para me comunicar com uma mistura de sensores analógicos (ou seja, medidos via analogRead ()) e sensores baseados em I2C. Os dados amostrados são colocados em uma matriz de 16 bytes, depois gravada em um cartão SD assim que um buffer de 512 bytes estiver completamente preenchido. O problema que estou enfrentando é que quando eu coleto dados de um oxímetro de pulso MAX30102 usando

measure.pox = pulseOx.getIR(); 

a partir do meu código abaixo, o tempo de ciclo do meu loop collectHR () cai para cerca de 20 ms. Se eu pré-alocar este ponto usando a linha diretamente abaixo dele (armazenando uma constante em vez de ler um novo uint32_t a cada loop), meu tempo de ciclo é de cerca de meio milissegundo. O que é confuso para mim é que se eu converter o uint32_t em uma string usando dtostrf:

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

leva apenas cerca de 1,2 ms para realmente ler uma amostra de o MAX30102. Parece-me que, ao favorecer uma estrutura em vez de uma string (de uma iteração anterior deste código que gravava todos os dados como um arquivo txt em vez de um arquivo bin) para que eu pudesse gravar binário em meu cartão SD, eu ” estou absolutamente estrangulando minha velocidade. Não deveria trabalhar bytewise ser mais eficiente do que trabalhar com uma string? O que está acontecendo com os outros 18 ms que ocorre entre a leitura do long sem sinal e colocá-lo em byte buffer, buffer1? Implementar este código usando arrays de string em vez de uma estrutura, Consegui funcionar a aproximadamente 125 Hz. Agora estou a cerca de 50 Hz. Agradeço qualquer insight aqui. Código relevante mostrado abaixo:

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

Comentários

  • A sequência de operações parece um pouco estranho. Considere o que acontece logo no início: buffLen é inicialmente 0, então você aumenta imediatamente para 16 e, em seguida, você copia os dados para esse buffer no deslocamento 16. Mas e quanto ao primeiro 16 bytes? Por que você os deixou sem uso? Além disso, não está claro por que você precisa bombear bytes constantemente de measure para buffer1 , ou seja, de memória para memória. Por que não ' você apenas declara uma matriz de 32 struct measure elementos e usá-los diretamente?
  • Obrigado por sua contribuição! Você ' está absolutamente certo de que os primeiros 16 bytes permaneceriam vazios. Eu inicialmente pensei que ficaria Faça mais fácil de determinar quando cada loop collectHR () terminou no arquivo procurando por 16 0 ' s, mas agora que você indicou, parece um total desperdício de memória. Mudei o incremento para baixo. a chamada memcpy para explicar isso. Eu não ' pensei em lançar uma série de estruturas; Eu ' vou tentar. Você tem alguma ideia de por que especificamente o memcpy da chamada pulseOx.getIR () é muito mais lento do que o tempo que leva para recuperar esses 4 bytes do sensor?
  • use unsigned int para buffLen, porque 15 * 3200 é mais do que int pode levar
  • Tem certeza de que possui 512 bytes de RAM livre? A biblioteca SDfat mantém um buffer de 512 bytes de qualquer maneira, e outro para o próprio sistema de arquivos. De qualquer forma, ele grava fisicamente apenas em blocos completos.
  • Juraj Boa pegada, obrigado! Eu ' alterei isso acima. @DataFiddler Supostamente tenho cerca de 5800 bytes restantes para brincar. Eu ' m ciente que SDfat utiliza um buffer de 512 bytes, mas isso significa que cada chamada write () empurra 512 bytes para o cartão, ou que nada é enviado ao cartão até 512 bytes de write () são acumulados? Desculpe, millisSet () ofendeu você, eu ' o removi. Tentei postar apenas as partes relevantes do código, mas parece que perdi essa variável na postagem inicial. O lixo é removido …

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *