Go Down

Topic: Guidance with I2C Sensor (Read 294 times) previous topic - next topic

only4zubair

Hi Everyone,
I am working on getting pressure measurements from an I2C pressure sensor and I am using an arduino yun to interface with the sensors. The objective of this is to eventually gather high frequency (~500 Hz) data for relatively short periods of time (5-10 minutes of continuous acquisition). I have used an Arduino Uno before but never used it to capture data or control frequency of response/acquisition. I'm in the very initial phase of the project and I've written the following code to get a sense of the frequency that I can gather. The following code gets data from the sensor and writes it to the SD card on the yun. The data being recorded is the pressure reading (temperature is read but not recorded), and time in milliseconds.

Code: [Select]
//Arduino Datalogger Example Modified to use I2C pressure sensor
#include "Wire.h"                  //needed to talk to I2C devices
#include <FileIO.h>
#include <Arduino.h>
#include <Bridge.h>
#include <Console.h>

#define HSCDANN004NG2A3_I2C 0x28 // each I2C object has a unique bus address
unsigned long timeInMilli=0;

void setup()
{
  Bridge.begin();
  FileSystem.begin();
  Wire.begin(); // wake up I2C bus
 
  delay(5);   //this delay is to give the pressure sensor time to start up
}

void loop()
{
 // getting the data from the sensor
 Wire.beginTransmission(HSCDANN004NG2A3_I2C); // begin transmission
 Wire.write(1);  // send a bit asking for register one, the data register (as specified by the pdf)
 Wire.endTransmission(); // "Thanks, goodbye..."

  //reading the data
 Wire.requestFrom(HSCDANN004NG2A3_I2C, 4);
 while(Wire.available() == 0);
 byte a     = Wire.read(); // first received byte stored here ....Example bytes one: 00011001 10000000
 byte b     = Wire.read(); // second received byte stored here ....Example bytes two: 11100111 00000000
 byte c     = Wire.read(); // third received byte stored here
 byte d     = Wire.read(); // fourth received byte stored here
 
 // confirming that the first 2 bits of the first byte is null
 byte status1 = (a & 0xc0) >> 6;  // first 2 bits from first byte

 //getting the pressure and temperature (if it has) in binary code
 // a and b bytes used to get the pressure with 12bits of accurancy
 int bridge_data = ((a & 0x3f) << 8) + b;

 //time in microseconds
 timeInMilli=millis();

 String dataString=String(bridge_data);
 dataString += ",";
 dataString += String(timeInMilli);
 
 
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  // The FileSystem card is mounted at the following "/mnt/FileSystema1"
  File dataFile = FileSystem.open("/mnt/sda1/datalog.txt", FILE_APPEND);

  // if the file is available, write to it:
  if (status1 == 0)
  {
      if (dataFile)
      {
        dataFile.println(dataString);
        dataFile.close();
        // print to the serial port too:
        //Serial.println(dataString);
      }
      // if the file isn't open, pop up an error:
      else
      {
        //Console.println("error opening datalog.txt");
      }
  }

   delayMicroseconds(500); // minimum delay between measurements as per sensor specs
}


This gives me the following output (few lines are shown):
1629,3450
1627,3523
1629,3581
1627,3636

Based on this initial test, it looks like my frequency varies considerably (SD Card latency?) anywhere from 4-24 Hz. I've looked at posts where people are logging high speed data (analog) using the SD card library but I don't believe I can use the library with the arduino yun. Can anyone provide suggestions on how I should proceed to bump up the frequency or is it better to make the switch to a different arduino/microcontroller?

Thanks!

Peter_n

The Arduino Yun is a Arduino Leonardo plus a wifi/linux/OpenWRT module (via the Bridge using pin 0 (RX) and pin 1 (TX)).

You can add a SD logger shield, as long as pin 0 and pin 1 are not used.
If the SD logger shield is compatible with an Arduino Uno and also for a Leonardo, you could test the sketch on the Uno and after that try to make it work for the Yun.

The normal Arduino SD library is not the fastest. It is based upon an older sdfat library, but the sdfat library has been optimized a lot since.
https://github.com/greiman/SdFat

Please don't use this:
Code: [Select]
while(Wire.available() == 0);The Wire.requestFrom() returns after the I2C transmission has completely ended. There is no need to wait for something.

You can't use the String object, when you want fast code.

Are you opening a file for every sample ? That is very slow.

Johnny010

I'd assume something to do with the SD. Is the sensor definitely capable of 500Hz cycles?
 Try just incrementing a counter in a loop on getting a reading. Have the for loop break if there after 1000 millis (). If counter > 500 { turn on a green led} else turn on red.

only4zubair

Thanks for the pointers on the code optimization, I will remove the while wire available piece from the code. I'll also look at writing the data using non-string types, thanks for that catch. I will look for an SD logger shield and post results.


I'd assume something to do with the SD. Is the sensor definitely capable of 500Hz cycles?
According the pressure sensor datasheet, I should be able to get up to 2KHz, but you are right, I will confirm this using a counter to validate that portion of the setup.

Thanks for the replies!

chucktodd

Thanks for the pointers on the code optimization, I will remove the while wire available piece from the code. I'll also look at writing the data using non-string types, thanks for that catch. I will look for an SD logger shield and post results.

According the pressure sensor datasheet, I should be able to get up to 2KHz, but you are right, I will confirm this using a counter to validate that portion of the setup.

Thanks for the replies!
The only way I can see you capturing 150k samples evenly spaced 2ms apart would be to reprogram one of the timers to create a 1ms heartbeat interrupt, every interrupt you do:

Code: [Select]


volatile static uint8_t activeBuf=0
volatile static uint16_t activeOfs=0;
volatile uin8_t bufs[2,512];
volatile uin8_t stage=0;
volatile bool bufDirty[2];

void timerISR(){
if(stage==0){ // send Sensor address set
  Wire.beginTransmission(sensorAddress);
  Wire.begin((uint8_t)1);
  Wire.endTransmission();
  stage=1;
  }
else { // not stage 0
  if(bufDirty[activeBuf]){ // SD did not clear buffer, too fast!
    die a horrible Death!
    shut off interrupt,
    display error meassage!
    }
  Wire.requestFrom(sensorAddress,4);
  for(uint8_t i=0;i<4;i++){
    bufs[activeBuf,activeOfs++]=Wire.read();  
    }
 if(activeOfs==512){
   bufDirty[activeBuf]=true;
   activeOfs = 0;
   activeBuf= (activeBuf+1)%2;
   }
  stage=0;
  }
}

void setup(){
// initialize timer to produce 1ms interrupt
// assign timerISR() as service function
}
 
void loop(){
uint8_t b = (activeBuf+1)%2; // inactive buffer
if(bufdirty[b]){

 // write bufs[b] to SDCard

  bufDirty[b]=false;
  }
}



There is a lot of holes in this code, but it is a start.

Chuck.

only4zubair

Thanks Chuck. I haven't used timers so I will have to read up on the documentation and examples to see how its set up. I should have clarified that the sample intervals do not have to be evenly spaced together, slight fluctuations are acceptable.


jack wp

#6
Sep 23, 2015, 10:17 pm Last Edit: Sep 23, 2015, 10:39 pm by jack wp
It is likely that the Wifi could be causing blocking delays.

I may have missed this info above, but:

1.You mentioned a sensor, then several sensors. How many do you expect?
2.Where/how are you reporting all these readings?
3. Would it be as good to take many readings, average them, and report the average?
4. So that leads to the question, can you store the readings in ram, rather than needing SD card?
5. How long is your I2C wire? What pullup resistors are on the sensors if any? What pullup resistors did you add.


Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy