왜 unsigned의 memcpy가 샘플링 속도를 죽이는 걸까요?

저는 Mega 2560을 사용하여 아날로그 (예 : analogRead ()를 통해 측정) 및 I2C 기반 센서의 혼합과 통신합니다. 샘플링 된 데이터는 512 바이트 버퍼가 완전히 채워지면 SD 카드에 16 바이트 배열이 기록됩니다. 문제는

아래 코드에서 collectHR () 루프의주기 시간이 약 20mS로 떨어집니다. 바로 아래에있는 줄을 사용하여이 지점을 미리 할당하면 (각 루프마다 새 uint32_t를 읽는 대신 상수 저장) 사이클 시간은 약 0.5 밀리 초입니다. 저에게 혼란스러운 점은 dtostrf를 사용하여 uint32_t를 문자열로 캐스트하는 경우 :

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

실제로 샘플을 읽는 데 약 1.2mS 밖에 걸리지 않습니다. 이진 파일을 SD 카드에 쓸 수 있도록 모든 데이터를 bin 파일 대신 txt 파일로 작성한이 코드의 이전 반복에서 나온 문자열보다 구조체를 선호하는 것 같습니다. 내 속도를 절대적으로 제한합니다. 바이트 단위로 작업하는 것이 문자열로 작업하는 것보다 더 효율적이어야하지 않습니까? 부호없는 long을 읽고이를 바이트 버퍼 buffer1에 배치하는 사이에 발생하는 다른 18mS는 어떻게됩니까? 구조체 대신 문자열 배열을 사용하여이 코드를 구현하면 약 125Hz에서 실행할 수 있었지만 이제는 약 50Hz입니다. 여기에 대한 정보가 있으면 감사하겠습니다. 관련 코드는 다음과 같습니다.

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

댓글

  • 순서 작업 수가 약간 이상해 보입니다. 처음에 어떤 일이 발생하는지 고려하세요. buffLen는 처음에는 0이고 즉시 16 그런 다음 오프셋 16의 해당 버퍼에 데이터를 복사합니다.하지만 첫 번째 16 바이트? 왜 사용하지 않은 상태로 두 셨나요? 또한 measure에서 buffer1로 바이트를 지속적으로 펌프해야하는 이유도 명확하지 않습니다. 즉, 메모리에서 메모리로. ' 32 struct measure 요소를 사용하고 직접 사용 하시겠습니까?
  • 입력 해 주셔서 감사합니다. ' 처음 16 바이트가 비어 있다는 점에 절대적으로 맞습니다. 처음에는 그렇게 될 것이라고 생각했습니다. 그것을 만드십시오 16 0 ' s를 검색하여 파일에서 각 collectHR () 루프가 언제 끝났는지 쉽게 확인할 수 있지만 이제는 총 메모리 낭비처럼 보입니다. 증분을 아래로 이동했습니다. 이것을 설명하는 memcpy 호출. 나는 ' 구조체 배열을 캐스팅 할 생각이 없었습니다. 저는 ' 해보겠습니다. 특히 pulseOx.getIR () 호출의 memcpy가 센서에서 4 바이트를 검색하는 데 걸리는 시간보다 훨씬 느린 이유에 대한 통찰력이 있습니까?
  • buffLen의 경우 15 * 3200은 int가 차지할 수있는 것보다 많기 때문입니다.
  • 512 바이트의 여유 RAM이 있습니까? SDfat 라이브러리는 어쨌든 512 바이트 버퍼와 파일 시스템 자체를위한 다른 버퍼를 보유합니다. 어쨌든 물리적으로 SD에 전체 블록 만 기록합니다.
  • Juraj 잘 잡았습니다, 감사합니다! 위의 내용을 ' 수정했습니다. @DataFiddler 나는 약 5800 바이트가 남아 있다고 주장합니다. 저는 ' SDfat가 512 바이트 버퍼를 사용한다는 것을 알고 있지만 이는 모든 write () 호출이 512 바이트를 카드에 푸시하거나 카드에 아무것도 전송되지 않음을 의미합니다. 512 바이트 상당의 write ()가 축적됩니까? 죄송합니다. millisSet ()이 (가) 기분을 상하게했습니다. ' 제거했습니다. 코드의 관련 부분 만 게시하려고했지만 초기 게시물에서 해당 변수를 놓친 것 같습니다. 쓰레기 제거 …

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다