Feather M0 Adalogger independent operation

I am using Feather M0 Adalogger with customized EMG amplifier, BMI160(Accelerometer), Mic. And, I want to save the sensor data to an SD card and operate the device alone when turning the battery on. But, it's not working with my code. When I uploaded my code to Feather M0 adalogger, the green LED started to turn on but did not turn off after 10sec that I set for the while loop.

Could you please check my code and give me some comments to increase the sampling rate? My sampling rate is just about 700Hz. I want to get about a 1 kHz sampling rate.

#include <SPI.h>
#include <SD.h>
#include <BMI160Gen.h>
#include <Arduino.h>
#include <stdio.h>
#include <math.h>

#define SAMPLERATE_HZ 1600
int32_t audiosamples = 5;


// Set the pins used
#define cardSelect 4
unsigned long timer = 0;
File logfile;

int A_0; // EMG data
int A_1; //Mic Pos
int A_2; //Mic Neg

// BMI160 setting
const int i2c_addr = 0x68; // BMI160 acc address
int16_t x = 0; //Acc_X
int16_t y = 0; //Acc_Y
int16_t z = 0; //Acc_Z
int axRaw, ayRaw, azRaw;

// Timer for time stamping setting
unsigned long time_start;
unsigned long time_end;
unsigned long sampling_rate;

uint8_t i=0;

//HPF
int sensorValue = 0;
float EMG_a = 0.3;
int EMG_s = 0;
int highpass = 0;


// blink out an error code
void error(uint8_t errno) {
while(1) {
uint8_t i;
for (i=0; i<errno; i++) {
digitalWrite(13, HIGH);
delay(100);
digitalWrite(13, LOW);
delay(100);
}
for (i=errno; i<10; i++) {
delay(200);
}
}
}



void setup() {
// connect at 115200 so we can read the GPS fast enough and echo without dropping chars
// also spit it out
pinMode(13, OUTPUT); // Red led

pinMode(8, OUTPUT); // Green led
digitalWrite(8, HIGH); //Green LED ON

Serial.begin(115200);

while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

Serial.println("\r\nAnalog logger test");

// see if the card is present and can be initialized:
if (!SD.begin(cardSelect)) {
Serial.println("Card init. failed!");
error(2);
}
char filename[15];
strcpy(filename, "/ANALOG00.TXT"); // Copy ANALOG00.TXT and paste to filename
//Create filename by screening existing files
for (uint8_t i = 0; i < 100; i++) {
filename[7] = '0' + i/10; //Divide i to 10
filename[8] = '0' + i%10; //Remaining i to 10
// create if does not exist, do not open existing, write, sync after write
if (! SD.exists(filename)) {
break;
}
}

logfile = SD.open(filename, FILE_WRITE);
if(!logfile ) {
Serial.print("Couldnt create "); //Just print
Serial.println(filename); // Print and /n
error(3);
}

BMI160.begin(BMI160GenClass::I2C_MODE, i2c_addr);
BMI160.setAccelerometerRate(2000);
BMI160.gyroOffsetEnabled();
BMI160.autoCalibrateAccelerometerOffset(X_AXIS, 0);
BMI160.autoCalibrateAccelerometerOffset(Y_AXIS, 0);
BMI160.autoCalibrateAccelerometerOffset(Z_AXIS, 0);


Serial.print("Writing to ");
Serial.println(filename);
Serial.println("Ready!");




EMG_s = analogRead(A5); // Set EMG s for t=1

while((micros()-timer)< 10000000){
String dataString = "";
time_start = micros();

sensorValue = analogRead(A5); //EMG
EMG_s = (EMG_a*sensorValue) + ((1-EMG_a)*EMG_s);
highpass = sensorValue - EMG_s;


A_1 = analogRead(A1); //Mic Pos
A_2 = analogRead(A2); //Mic Neg
BMI160.readAccelerometer(axRaw, ayRaw, azRaw);

dataString += time_start;
dataString += ",";
dataString += String(highpass); // EMG
dataString += ",";
dataString += String(A_1); // Mic Pos
dataString += ",";
dataString += String(A_2); // Mic Neg
dataString += ",";
dataString += String(axRaw);
dataString += ",";
dataString += String(ayRaw);
dataString += ",";
dataString += String(azRaw);

logfile.println(dataString);

}

logfile.close();
Serial.println("Its done");
digitalWrite(8, LOW); //Green LED OFF

}


void loop() {

}

Please use autoformat, </>, in the IDE before posing the code.
Odd way to code. Usually setup is used to set things up and the work is done in loop().

What does "independent" in your topic title mean? Not connected to a PC?

If so, you're application is stuck on

I'm not familiar with the M0 but my experience with 32U4 boards (also nativeUSB) says that there are pittfalls when using it standalone that you need to be aware of. More details once I know if you want to use it without a PC.

I am using Adafruit Feather 32u4 Bluefruit LE and trying to transfer sensors data from analog input and I2C. Then are there any examples for this bluetooth module to measure the sensor data and transfer the data to the App or Web? And how much sampling rate we can get using this module? Can I get about 1 kHz sampling rate using this one?

Thanks

@adafruitree

Your two topics on the same subject have been merged.

Please do not duplicate your questions as doing so wastes the time and effort of the volunteers trying to help you as they are then answering the same thing in different places.

Repeated duplicate posting could result in a temporary or permanent ban from the forum.

Could you take a few moments to Learn How To Use The Forum

It will help you get the best out of the forum in the future.

Other general help and troubleshooting advice can be found here.
It will help you get the best out of the forum in the future.

Thank you.

I just put the while((micros()-timer)< 10000000) loop on setup() to compare the operation time with on loop(). I can change it but that is not the problem.

I meant standalone data saving from sensors during the assigned time.

So your board is connected to a PC? If so, did you open the Serial Monitor (or other terminal program?

I connected the board to upload code and disconnected the board to work standalone with the battery. When I connected the board and opened the serial monitor, it worked well. But, after disconnecting, the LED was turned on but did not save the sensor data.

A few things to know about boards with native USB (my experience is with 32U4).

  1. If you run it with an external power supply and no connection to a PC, it will get stuck on the while(!Serial). You can get past that by connecting it to the PC and opening serial monitor.
  2. Once the board has seen a connection with the serial monitor, it will continue; it however can not get rid of the serial data that you send to the PC if you disconnect it and will eventually slow down significantly (to a near grinding halt). You can work around that by using Serial.availableForWrite() and make sure that there is enough space to send the message to the PC.

Why do You think the execution time would be different?
You have no code in loop.
Correct, no change in execution time.
Your terminology is a bit home brew. What is "save data"? You have no external device, memory, SD.......

Thank you for helping me. Finally, I solved this problem by deleting while(!Serial).
If you don't mind, may I ask one more question? From the above code, I just could get about 700 Hz sampling rate. But, I need more than 1 kHz sampling rate. So, could you give me some advice to improve the sampling rate by modifying the code? And, do you have some information or examples about Bluetooth communication using Feather Bluetooth device? I want to get the sensor data from Feather to App or Webpage.

And, I want to save the data for more than 2 hrs. But, it didn't work. Like this code ( while((micros()-timer)< 7200000000)). Is there a data type length limit on micros?

micros() is a 32 bit unsigned number so can only count up to 4294967295 which is about 71 minutes.

You should be using millis() which rolls over every 49 days

Thank you. I solve the problem. But still, I need to improve the sampling rate. Do you have some idea or advice to get more high sampling rate?

I suggest that you post the latest version of your sketch. Before posting, please properly format your sketch using tools -> autoformat in the IDE.

If you still have delay() in your sketch, that is probably the reason that you can't achieve a higher sampling.

#include <SPI.h>
#include <SD.h>
#include <BMI160Gen.h>
#include <Arduino.h>
#include <stdio.h>
#include <math.h>

#define SAMPLERATE_HZ 16000
int32_t audiosamples = 5;


// Set the pins used
#define cardSelect 4
unsigned long timer = 0;
File logfile;

int A_0; // EMG data
int A_1;  //Mic Pos
int A_2;  //Mic Neg

// BMI160 setting
const int i2c_addr = 0x68; // BMI160 acc address
int16_t x = 0; //Acc_X
int16_t y = 0; //Acc_Y
int16_t z = 0; //Acc_Z
int axRaw, ayRaw, azRaw;

// Timer for time stamping setting
unsigned long time_start = 0;
unsigned long time_end;
unsigned long sampling_rate;

uint8_t i=0;
float sound;
int32_t left,right;

//HPF
//int sensorPin = 0;
int sensorValue = 0;
float EMG_a = 0.3;
int EMG_s = 0;
int highpass = 0;


// blink out an error code
void error(uint8_t errno) {
  while(1) {
    uint8_t i;
    for (i=0; i<errno; i++) {
      digitalWrite(13, HIGH);
      delay(100);
      digitalWrite(13, LOW);
      delay(100);
    }
    for (i=errno; i<10; i++) {
      delay(200);
    }
  }
}



void setup() {
  // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
  // also spit it out
  pinMode(13, OUTPUT); // Red led
  pinMode(8, OUTPUT); // Green led
  
  
  Serial.begin(115200);
  Serial.println("\r\nAnalog logger test");

  // see if the card is present and can be initialized:
  if (!SD.begin(cardSelect)) {
    Serial.println("Card init. failed!");
    error(2);
  }
  char filename[15];
  strcpy(filename, "/ANALOG00.TXT"); // Copy ANALOG00.TXT and paste to filename
  //Create filename by screening existing files
  for (uint8_t i = 0; i < 100; i++) {
    filename[7] = '0' + i/10; //Divide i to 10
    filename[8] = '0' + i%10; //Remaining i to 10
    // create if does not exist, do not open existing, write, sync after write
    if (! SD.exists(filename)) {
      break;
    }
  }

  logfile = SD.open(filename, FILE_WRITE);
  if(!logfile ) {
    Serial.print("Couldnt create "); //Just print
    Serial.println(filename); // Print and  /n
    error(3);
  }
  
  BMI160.begin(BMI160GenClass::I2C_MODE, i2c_addr);
  BMI160.setAccelerometerRate(2000);
  BMI160.gyroOffsetEnabled();
  BMI160.autoCalibrateAccelerometerOffset(X_AXIS, 0);
  BMI160.autoCalibrateAccelerometerOffset(Y_AXIS, 0);
  BMI160.autoCalibrateAccelerometerOffset(Z_AXIS, 0);

  
  Serial.print("Writing to "); 
  Serial.println(filename);
  Serial.println("Ready!");
    

  EMG_s = analogRead(A5); // Set EMG s for t=1
  digitalWrite(8, HIGH); //Green LED ON
  while((millis()-timer)< 14400000){
    String dataString = "";    
    time_start = millis();  
    
    sensorValue = analogRead(A5); //EMG
    EMG_s = (EMG_a*sensorValue) + ((1-EMG_a)*EMG_s);
    highpass = sensorValue - EMG_s;

    
    A_1 = analogRead(A1); //Mic Pos
    A_2 = analogRead(A2); //Mic Neg
    BMI160.readAccelerometer(axRaw, ayRaw, azRaw);

    dataString += time_start;
    dataString += ",";
    dataString += String(highpass); // EMG
    dataString += ",";
    dataString += String(A_1); // Mic Pos
    dataString += ",";
    dataString += String(A_2); // Mic Neg
    dataString += ",";
    dataString += String(axRaw);
    dataString += ",";
    dataString += String(ayRaw);
    dataString += ",";
    dataString += String(azRaw);
    logfile.println(dataString);
  }
  
  logfile.close();
  Serial.println("Its done");
  digitalWrite(8, LOW); //Green LED OFF 
}


void loop() {
  //exit(0);

}

I2C communication is much slower than SPI. You might want to test your system and see how fast you can simply read your sensors. You can't go faster than that.

Just comment out the logfile.println() call and insert a counter that increments each time through your loop to figure out how many times you loop in the given timeframe.

You may also improve performance if you reserve some space for your String variable beforehand so it doesn't have to grow as you go through the loop.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.