1

I'm working on a system of acquisition and ECG datalogging with the Arduino, and I'm having the following problem: I'm losing data every 103 points (just 103). No matter the sampling frequency to use, every 103 points, some points are lost, damaging the signal sampling. It could be the recording time on the SD card, but even when the SD.close () command is run only once, the data is lost. Here is a simple test algorithm with a 100 Hz sine wave at the entrance.


#include <SD.h>
#include <SPI.h>

int CS = 4;
int ECG_PIN = 1;
int voltage;

int index = 0;
const int bufferSize = 5;
int vetor[bufferSize];
int RECORD_TIME = 20000;
File logFile;

void setup(){
  pinMode(CS, OUTPUT);
  pinMode(ECG_PIN,INPUT);

  if(!SD.begin(CS)){
    return;
  }
  logFile = SD.open("ECG_log.txt", O_CREAT | O_WRITE);


}

void loop(){
  while(millis() <= RECORD_TIME){

      voltage = analogRead(ECG_PIN);
    if(logFile){

       logFile.println(voltage);

       delay(0.5); 
    }
  }
  logFile.close();
}

enter image description here

What could it be? Speed analogRead ()? Problem on the SD card?

Sorry if the question is very basic, I am beginner, in a way, the Arduino platform. Any help will be very welcome.

Thanks!...

0

1 Answer 1

4

It's all to do with writing to the SD card.

You have a buffer of 512 bytes which is one "block" of the SD card. When you have written to the card enough to fill that buffer up it has to write that buffer to the SD card and empty the buffer so you can start filling it again.

That writing to the SD card takes time - lots and lots of time (relatively), and it can't be doing anything else at the same time as writing to the SD card.

The only way you can get around that is to have your sampling performed within an interrupt - maybe a timer interrupt - so that it can interrupt the writing to the SD card. However, that's not a simple task.

You would need to implement a system known as ping-pong buffers. You have a pair of buffers for storing incoming samples within your interrupt routine. When one buffer is filled up you switch to the other buffer and signal to your main loop() routine that you have filled the buffer. It's then the job of loop() to save that buffer to the SD card and empty it ready for when the second buffer has been filled up. The name ping-pong comes from the game of table tennis (also known as ping-pong) as you are switching from one buffer to the other and back again in a constant backwards-and-forwards motion like the ball in a game of table tennis.

Getting the right size of buffers is also critical. You have to ensure that the time taken to fill one buffer is always going to be longer than the longest amount of time it takes to write a buffer to the SD card, including any flushing of the internal SD card buffer. The best size is probably going to be to match that internal SD card buffer so every ping or pong you will be doing an entire SD card block's worth of data - so 512 bytes.

That means you have 3 buffers of 512 bytes - your two ping-pong buffers and the SD card's buffer, which is 1536 bytes - not far off the limit of an Uno, so you may struggle with that. For this kind of thing it is better to use one of the boards with a more meaty chip, like the Mega2560.

Also the line:

delay(0.5);

is meaningless. delay() takes an integer value, so 0.anything is actually truncated to 0. To delay for less than a millisecond you should use delayMicroseconds().

4
  • Thank you for quick and didatic response, @Majenko. I've been having insufficient memory problems with the Uno from the start of the project. I will purchase a Mega as soon as possible. I got the idea of ping pong buffer, but still can not understand how to put it in the form of code. Could you point me some material or program as a reference? Thank you very much.
    – rnt_42
    Commented Jul 15, 2015 at 14:20
  • I don't have any examples online at the moment. It's simple enough - 2 buffers, 2 flags. One flag says which buffer is being filled at the moment, the other flag is used to indicate that a buffer is ready for writing. When the writing flag is set loop() notices it, writes out the non-filling buffer by checking the first flag, and clears the second flag. When you have filled a buffer you set or clear the filling flag and set the writing (ready-to-empty) flag.
    – Majenko
    Commented Jul 15, 2015 at 14:58
  • 512 bytes divided by 5 bytes per datapoint (three digits + carriage return + newline) = 102.4 (rounds up to 103)
    – Gerben
    Commented Jul 15, 2015 at 16:12
  • 1
    @Gerben What a coincidence ;)
    – Majenko
    Commented Jul 15, 2015 at 16:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.