unsigned longのmemcpyがサンプリング速度を殺しているのはなぜですか?

Mega 2560を使用して、アナログ(つまり、analogRead()を介して測定)とI2Cベースのセンサーの混合物と通信しています。サンプルデータは次の場所に配置されます。 16バイトのアレイで、512バイトのバッファが完全にいっぱいになるとSDカードに書き込まれます。私が直面している問題は、

以下のコードから、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しかかかりません。 MAX30102。文字列よりも構造体を優先することで(すべてのデータをbinファイルではなくtxtファイルとして書き込んだこのコードの以前の反復から)、SDカードにバイナリを書き込むことができるように思えます。」 m絶対に私の速度を抑えます。文字列を操作するよりもバイト単位で作業する方が効率的ではありませんか?unsignedlongを読み取ってからバイトバッファ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バイト?なぜそれらを未使用のままにしたのですか?また、なぜバイトをmeasureからbuffer1に絶えずポンピングする必要があるのかは明らかではありません。 、つまりメモリからメモリへ。' 32 struct measure要素を直接使用しますか?

  • 入力していただきありがとうございます!'最初の16バイトが空のままであることは間違いありません。当初はそうなると思っていました。成功する16個の0 'を検索することで、各collectHR()ループがファイル内でいつ終了したかを簡単に判断できますが、指摘すると、メモリが完全に浪費されているように見えます。増分を以下に移動しました。これを説明するためのmemcpy呼び出し。 '構造体の配列をキャストすることを考えていませんでした。 '試してみます。特にpulseOx.getIR()呼び出しのmemcpyが、センサーからこれらの4バイトを取得するのにかかる時間よりもはるかに遅い理由について何か洞察がありますか?
  • for buffLen、15 * 3200はintが取ることができる以上であるため
  • 512バイトの空きRAMがありますか? SDfatライブラリはとにかく512バイトのバッファを保持し、もう1つはファイルシステム自体用です。とにかく、SDには完全なブロックのみを物理的に書き込みます。
  • ジュラジグッドキャッチ、ありがとう! '上記でこれを修正しました。 @DataFiddler伝えられるところでは、約5800バイトが残っています。 ' SDfatが512バイトのバッファを使用していることを認識していますが、これは、すべてのwrite()呼び出しが512バイトをカードにプッシュするか、カードに何も送信されないことを意味します。 512バイト相当のwrite()が蓄積されていますか?申し訳ありませんが、millisSet()はあなたを怒らせました、私はそれを削除しました'。コードの関連部分だけを投稿しようとしましたが、最初の投稿でその変数を見逃したようです。ゴミが取り除かれます…
  • コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です