Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 22 of 22

Thread: Using Teensy 3.5 Built-in SD card reader for data acquisition

  1. #1
    Junior Member
    Join Date
    Nov 2019
    Posts
    11

    Using Teensy 3.5 Built-in SD card reader for data acquisition

    Hi, I am trying to use Teensy 3.5 to write data that I acquire from two sensors (encoder and an EMG). I found that there are previous forum mentioning about this too and I've also tried it. I tried changing the code from the forum. It does made new file in my SD card but the data sensor isn't saved, so basically it's just an empty csv data.

    I use the SdFat library.

    This is the code
    Code:
    #include <SdFat.h>
    #define outputA 5
    #define outputB 6
    #define RawEMG A0
    #define MaxCount 10000
    int counter = 0;
    int derajat = 0;
    int EMG;
    int aState;
    int aLastState;
    SdFatSdio sd;
    File file;
    
    void setup()
    {
      pinMode (outputA, INPUT_PULLUP);
      pinMode (outputB, INPUT_PULLUP);
      Serial.begin(9600);
      //Reads the initial state of the outputA
      aLastState = digitalRead(outputA);
    
      if (!sd.begin()) {
        sd.initErrorHalt();
    
      }
    }
    void doLogging(uint32_t timeStamp, int *data1,int *data2, int *data3, int nb)
    {
      // following is for logging
      static uint32_t ifl = 0;
      static uint32_t count = 0;
      char filename[32];
    
      if(!count)
      {
         //open file
         sprintf(filename,"Data.csv",ifl); ifl++;
         if (!file.open(filename, O_RDWR | O_CREAT)) {
           sd.errorHalt("open failed");
         count=1;
         }
      }
      //
      if(count>0)
      {
        // write to file
        file.print(timeStamp);
        for(int ii=0; ii<nb; ii++)
        { file.print(',');
          file.print(data1[ii]);
          file.print(',');
          file.print(data2[ii]);
          file.print(',');
          file.print(data3[ii]);
        }
        file.println();
        count++;
        if(count>MaxCount) count=0;
      }
      //
      if(!count)
      {
         // close file
         file.close();
      }
    }
    
    
    void loop()
    {
      uint32_t t0 = millis();
      EMG = analogRead(RawEMG); //reads EMG sensor
      //float EMG = EMG * (5.0 / 1023.0);
      aState = digitalRead(outputA); //reads the 'current' state of the outputA
      //if outputB state is different to the outputA state, that means the encoder is rotating clockwise
      if (aState != aLastState){
        //if outputB state is different to the outputA state, that means the encoder is rotating clockwise
        if (digitalRead(outputB) != aState){
          counter ++;
        } else {
          counter --;
        }
        if (counter > 2048 or counter < -2048) //omron sebelumnya 1200 yang 600ppr, resolusi x 2
        {
          counter = 0;
        }
        derajat = counter * 360/2048;
    
      }
       aLastState = aState;
       Serial.print(counter);
       Serial.print(",");
       Serial.print(derajat);
       Serial.print(",");
       Serial.println(EMG);
      doLogging(t0,&counter, &derajat, &EMG,1); //insert data (?)
    }
    Is there anything wrong with it? How can I make it work? I think there's something wrong with the dologging void but I'm not entirely sure how to work my way around. Please help me, thank you.

  2. #2
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,398
    I would first apply the following change
    Code:
    //open file
         sprintf(filename,"Data%03d.csv",ifl); ifl++;
    than can you tell us what the serial monitor is printing

  3. #3
    Junior Member
    Join Date
    Nov 2019
    Posts
    11
    Quote Originally Posted by WMXZ View Post
    I would first apply the following change
    Code:
    //open file
         sprintf(filename,"Data%03d.csv",ifl); ifl++;
    than can you tell us what the serial monitor is printing
    Thank you for replying. I've tried your code but it doesn't have any effect. It was saving empty csv files instead and there were a lot of it. When I run your code, I have this warning.

    Code:
    SaveToSDCard: In function 'void doLogging(uint32_t, int*, int*, int*, int)':
    C:\Users\HP\Documents\Arduino\SaveToSDCard\SaveToSDCard.ino:37:41: warning: format '%d' expects argument of type 'int', but argument 3 has type 'uint32_t {aka long unsigned int}' [-Wformat=]
    The serial monitor is actually printing the values of the sensors this can be seen from the loop void.

    Code:
       Serial.print(counter);
       Serial.print(",");
       Serial.print(derajat);
       Serial.print(",");
       Serial.println(EMG);
    I would like to save the values of the sensors to SD card within a range of time that we can change, but still maintain its frequency sampling.

  4. #4
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,398
    next thing I would try is to move the print to serial adjacent to prints to file move from loop into doLogging
    Code:
    for(int ii=0; ii<nb; ii++)
        { file.print(',');
          file.print(data1[ii]);
          file.print(',');
          file.print(data2[ii]);
          file.print(',');
          file.print(data3[ii]);
    
       Serial.print(",");
       Serial.print(data1[ii]);
       Serial.print(",");
       Serial.print(data3[ii]);
       Serial.print(",");
       Serial.println(data3[ii]);    }
    to see what is exactly coming into subroutine

  5. #5
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,235
    your logic around the file.open() is flawed. You only would set count = 1 if the open() failed! so count is never set to 1, and all your dologger() does is open the file then close the file. Your flawed logic doesn't write any data to the file.

  6. #6
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,398
    Quote Originally Posted by manitou View Post
    your logic around the file.open() is flawed. You only would set count = 1 if the open() failed! so count is never set to 1, and all your dologger() does is open the file then close the file. Your flawed logic doesn't write any data to the file.
    I completely missed that.
    For me that is the reason, why I never liked '{' at the end of the line. I prefer that in line with '}'.

  7. #7
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,061
    Quote Originally Posted by WMXZ View Post
    I completely missed that.
    For me that is the reason, why I never liked '{' at the end of the line. I prefer that in line with '}'.
    Keeping code formatted helps - doing it manually of course is suspect to seeing things like that. In the IDE a Ctrl+T will do formatting the their uniform standard.

    That is an easy way to find missing syntax thingies. Very handy as the IDE cascades problems from the syntax error into who knows what.

    Most other IDE's have such things - for Sublimetext I found it and mapped to Ctrl+Alt+F.

  8. #8
    Junior Member
    Join Date
    Nov 2019
    Posts
    11
    Quote Originally Posted by manitou View Post
    your logic around the file.open() is flawed. You only would set count = 1 if the open() failed! so count is never set to 1, and all your dologger() does is open the file then close the file. Your flawed logic doesn't write any data to the file.
    Hi, thank you for your reply. I realized that the dologger() function is not right. But I had seen it from a forum, he said that it works for him. I thought it would work for me too. Is there any suggestion on how I should change the code? I'm actually not good with this.

  9. #9
    Junior Member
    Join Date
    Nov 2019
    Posts
    11
    Quote Originally Posted by WMXZ View Post
    next thing I would try is to move the print to serial adjacent to prints to file move from loop into doLogging
    Code:
    for(int ii=0; ii<nb; ii++)
        { file.print(',');
          file.print(data1[ii]);
          file.print(',');
          file.print(data2[ii]);
          file.print(',');
          file.print(data3[ii]);
    
       Serial.print(",");
       Serial.print(data1[ii]);
       Serial.print(",");
       Serial.print(data3[ii]);
       Serial.print(",");
       Serial.println(data3[ii]);    }
    to see what is exactly coming into subroutine
    Nothing happens when I try to comment my serial.print in the loop function and tried the code that you suggested. The serial monitor didn't show anything.

  10. #10
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,061
    Code:
    void setup()
    {
      pinMode (outputA, INPUT_PULLUP);
      pinMode (outputB, INPUT_PULLUP);
      Serial.begin(9600);
      while( !Serial ); // Add this when seeing output is needed  // or to wait 2 seconds // while( !Serial && millis()<2000 ); 
      //...

  11. #11
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,398
    Quote Originally Posted by AmeliaLita View Post
    Is there any suggestion on how I should change the code? I'm actually not good with this.
    Simply use
    Code:
      if(!count)
      {
         //open file
         sprintf(filename,"Data%03d.csv",ifl); ifl++;
         if (!file.open(filename, O_RDWR | O_CREAT))  sd.errorHalt("open failed");
         count=1;
      }

  12. #12
    Junior Member
    Join Date
    Nov 2019
    Posts
    11
    Thank you! Your suggestions work! Just a quick question, is there a way to add an id and a column title? I am also wondering if using an SD card to record a data would have a fix frequency sampling?

  13. #13
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,398
    Quote Originally Posted by AmeliaLita View Post
    Thank you! Your suggestions work! Just a quick question, is there a way to add an id and a column title? I am also wondering if using an SD card to record a data would have a fix frequency sampling?
    Code:
      if(!count)
      {
         //open file
         sprintf(filename,"Data%03d.csv",ifl); ifl++;
         if (!file.open(filename, O_RDWR | O_CREAT))  sd.errorHalt("open failed");
    
        // write header to file
        file.println("timeStamp,counter,derajat,EMG");
    
        // flag open file
        count=1;
      }
    And No the sampling rate in not fixed, it is as fast as 'loop() and ADC allow

    If you need precise sampling then you need a more complex program with timed interrupt.
    But I would simply try it out, you have a timestamp, so you can assess the regularity of the ADC

  14. #14
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,398
    what is your expected data rate?

    The following code may be a start
    Code:
    //
    #define SDFAT_BETA 0
    #if SDFAT_BETA == 0
      #include <SdFat.h>
    #else
      #include <SdFat-beta.h> // latest SdFat needed for SDIO and (renamed SdFat.h into SdFat-beta.h)
    #endif
    #define outputA 5
    #define outputB 6
    #define RawEMG A0
    #define MaxCount 10000
    
    uint32_t t0 = 0;
    int counter = 0;
    int derajat = 0;
    int EMG = 0;
    
    int aState;
    int aLastState;
    
    #if SDFAT_BETA == 0
      SdFatSdio sd;
      File file;
    #else
      SdFs sd;
      FsFile file;
    #endif
    #define SD_CONFIG SdioConfig(FIFO_SDIO)
    
    #define F_SAMP 500
    #define PIT_PERIOD (F_BUS/F_SAMP)
    
    uint32_t ADC_ready=0;
    uint32_t ADC_overflow=0;
    
    void ADC_input(void)
    {
      t0 = millis();
      EMG = analogRead(RawEMG); //reads EMG sensor
      //float EMG = EMG * (5.0 / 1023.0);
      aState = digitalRead(outputA); //reads the 'current' state of the outputA
    
      //if outputB state is different to the outputA state, that means the encoder is rotating clockwise
      if (aState != aLastState){
        //if outputB state is different to the outputA state, that means the encoder is rotating clockwise
        if (digitalRead(outputB) != aState){
          counter ++;
        } else {
          counter --;
        }
        if (counter > 2048 or counter < -2048) //omron sebelumnya 1200 yang 600ppr, resolusi x 2
        {
          counter = 0;
        }
        derajat = counter * 360/2048;
    
      }
       aLastState = aState;
       //
       ADC_ready=1; //flag to loop that we have new data
    }
    
    void ADC_Trigger_isr(void)
    {
      PIT_TFLG2=1;
      static uint16_t busy;
      digitalWriteFast(13,!digitalReadFast(13));
      if(busy && ADC_ready) { ADC_overflow++; return; }
      busy=1;
      ADC_input();
      busy=0;
    }
    
    void ADC_Trigger_init(void)
    {  // check with AudioStream if we are responsable for updates
      const int prio=10;
      // assign local function as ISR
      _VectorsRam[IRQ_PIT_CH2 + 16] = ADC_Trigger_isr;
      NVIC_SET_PRIORITY(IRQ_PIT_CH2, prio*16);
      NVIC_ENABLE_IRQ(IRQ_PIT_CH2);
    
      // turn on PIT clock
      SIM_SCGC6 |= SIM_SCGC6_PIT;
      // turn on PIT     
      PIT_MCR = 0x00;
      
      // Timer 0     
      PIT_LDVAL2 = PIT_PERIOD;
      PIT_TCTRL2 = 2; // enable Timer 2 interrupts
      PIT_TCTRL2 |= 1; // start Timer 2
    }
    
    
    void setup()
    {
      pinMode (outputA, INPUT_PULLUP);
      pinMode (outputB, INPUT_PULLUP);
    
      Serial.begin(9600);
      while(!Serial);
    
      //Reads the initial state of the outputA
      aLastState = digitalRead(outputA);
    
      if (!sd.begin(SD_CONFIG)) {
        sd.initErrorHalt(&Serial);
      }
      pinMode(13,OUTPUT);
      ADC_Trigger_init();
    }
    void doLogging(uint32_t timeStamp, int *data1,int *data2, int *data3, int nb)
    {
      // following is for logging
      static uint32_t ifl = 0;
      static uint32_t count = 0;
      char filename[32];
    
      if(!count)
      {
         //open file
         sprintf(filename,"Data%03u.csv",(unsigned int)ifl); ifl++;
         if (!file.open(filename, O_RDWR | O_CREAT)) sd.errorHalt("open failed");    
    
         Serial.println(filename);
         // write header to file
         file.println("timeStamp,counter,derajat,EMG");
    
         // flag open file     
         count=1;
      }
      //
      if(count>0)
      {
        // write to file
        file.print(timeStamp);
        for(int ii=0; ii<nb; ii++)
        { file.print(',');
          file.print(data1[ii]);
          file.print(',');
          file.print(data2[ii]);
          file.print(',');
          file.print(data3[ii]);
        }
        file.println();
        count++;
        if(count>MaxCount) count=0;
      }
      //
      if(!count)
      {  Serial.print("Overflow: "); Serial.println(ADC_overflow);
         ADC_overflow=0;
         // close file
         file.close();
      }
    }
    
    void loop()
    {
      if(ADC_ready)  
      { doLogging(t0,&counter, &derajat, &EMG,1); //insert data (?)
        ADC_ready=0;
      }
    }
    Last edited by WMXZ; 12-03-2019 at 01:17 PM.

  15. #15
    Junior Member
    Join Date
    Nov 2019
    Posts
    11
    I have tried your code but there's an error in #define SD_CONFIG SdioConfig(FIFO_SDIO). Is that a library that I need to download? Where can I download it?

    I was expecting a sampling rate that can acquire both sensors values properly without any data missing I hope.

  16. #16
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,398
    Sorry, that is my fault.
    I'm using the latest (beta) version of SdFat.

    You could change code to become
    Code:
    #if SDFAT_BETA == 0
      SdFatSdio sd;
      File file;
    #else
      SdFs sd;
      FsFile file;
      #define SD_CONFIG SdioConfig(FIFO_SDIO)
    #endif
    and
    Code:
    #if SDFAT_BETA == 0
      if (!sd.begin()) {
        sd.initErrorHalt();
      }
    #else
      if (!sd.begin(SD_CONFIG)) {
        sd.initErrorHalt(&Serial);
      }
    #endif

  17. #17
    Junior Member
    Join Date
    Nov 2019
    Posts
    11
    Quote Originally Posted by WMXZ View Post
    Sorry, that is my fault.
    I'm using the latest (beta) version of SdFat.

    You could change code to become
    Code:
    #if SDFAT_BETA == 0
      SdFatSdio sd;
      File file;
    #else
      SdFs sd;
      FsFile file;
      #define SD_CONFIG SdioConfig(FIFO_SDIO)
    #endif
    and
    Code:
    #if SDFAT_BETA == 0
      if (!sd.begin()) {
        sd.initErrorHalt();
      }
    #else
      if (!sd.begin(SD_CONFIG)) {
        sd.initErrorHalt(&Serial);
      }
    #endif
    Where should I paste this? I have tried running the first code with the previous code you shared and the error is that FIFO_SDIO was not declared.

  18. #18
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,061
    Looking at Post #14 code - it looks like nothing gets pasted - but the line
    Code:
    #define SDFAT_BETA 0
    is removed

  19. #19
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,398
    lets try again:
    actually post #14 says
    Code:
    #if SDFAT_BETA == 0
      SdFatSdio sd;
      File file;
    #else
      SdFs sd;
      FsFile file;
    #endif
    #define SD_CONFIG SdioConfig(FIFO_SDIO)
    that should become
    Code:
    #if SDFAT_BETA == 0
      SdFatSdio sd;
      File file;
    #else
      SdFs sd;
      FsFile file;
      #define SD_CONFIG SdioConfig(FIFO_SDIO)
    #endif
    you see the difference?
    also later in the code we have in setup()
    Code:
      if (!sd.begin(SD_CONFIG)) {
        sd.initErrorHalt(&Serial);
      }
    this should become
    Code:
    #if SDFAT_BETA == 0
      if (!sd.begin()) {
        sd.initErrorHalt();
      }
    #else
      if (!sd.begin(SD_CONFIG)) {
        sd.initErrorHalt(&Serial);
      }
    #endif
    Why this changes?
    this allows me to run the code with latest SdFat-beta library and using ExFAT formatted disks, and you with the older SdFat library, by simply changing a number

    use old SdFat library:
    Code:
    #define SDFAT_BETA 0
    use new SdFat-beta
    Code:
    #define SDFAT_BETA 1
    clearer now?

  20. #20
    Junior Member
    Join Date
    Nov 2019
    Posts
    11
    Okay, thanks. It's more clearer now and I've changed the code. There is no error when I compiled it but I tried printing the sensor values using the code below.

    Code:
     if (count > 0)
      {
        // write to file
        file.print(timeStamp);
        for (int ii = 0; ii < nb; ii++)
        { file.print(',');
          file.print(data1[ii]);
          file.print(',');
          file.print(data2[ii]);
          file.print(',');
          file.print(data3[ii]);
    
          Serial.print(data1[ii]); //counter
          Serial.print(",");
          Serial.print(data2[ii]); //derajat
          Serial.print(",");
          Serial.println(data3[ii]); //EMG
        }
    But there's nothing printed in the serial monitor and when I checked the SD card, there's no file saved there.

  21. #21
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,398
    Quote Originally Posted by AmeliaLita View Post
    But there's nothing printed in the serial monitor and when I checked the SD card, there's no file saved there.
    which seems to indicate, that opening files fails.
    I'm on travel for a week and have no Teensy with me, so I cannot check the program.

  22. #22
    Junior Member
    Join Date
    Nov 2019
    Posts
    11
    Hi, it's okay. I can wait and while at it, I will find other ways. I think I will try to compare with the previous code that works.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •