I have a tilt sensing application which will run as a datalogger for more than a year, so low current draw is important. I have no problems setting the registers for things like the ee_w bit, bandwidth, range, etc. but for the life of me I can not seem to get this sensor to go into it's low current sleep mode.
datasheet: http://www.spezial.cz/pdf/BST-BMA180-DS000-03.pdf
I am disabling the only obvious conflict I could find by setting the dis_wake_up to 1 (which if set to zero, prevents the sensor from going to sleep "manually")
with:
i2c_writeRegBits(BMA180_ADDRESS,BMA180_CMD_CTRL_REG0,1, ctrl_reg0_dis_wake_up_MASK);
but the sensor itself (a Geeetec board) never seems to draw much less than 1mA. Which is its maximum current draw, if not higher.
All the references I could find out there seem to be for applications that don't go to sleep (like IMU's), so I just thought I would post here in case someone else has run into this. This is the most convoluted sensor I have come across so far...
P.S. All my unused input pins are not left floating.
There is always the option to switch the power supply of the BMA180 with a transistor.
Yes, if I have to. But it seems like overkill when the sensor only consumes 0.5 uA in sleep mode. I would really like to do it in software instead of adding more components.
Finally got it working....
//first check if the sensor is in sleep mode by looking at the content of bit1 in CTRL_reg0
//if so wake up the sensor by setting the sleep bit (bit1 of reg0) to "0"
//you do not need to set the ee_w bit to do this
//but the dis_wake_up bit must be "1" to disable the auto-sleeping function first (I do this in the initialization)
bytebuffer1 = i2c_readRegByte(BMA180_ADDRESS, BMA180_CMD_CTRL_REG0);
bytebuffer2=bytebuffer1;
bytebuffer1 &= B00000010; //knock out the other bits
if(bytebuffer1){ // if "true" then the bit was "1"
bytebuffer2 &=~ (1<<1); // forces 1st bit of bytebuffer2 to be 0. all other bits left alone
bytebuffer1 = i2c_writeRegByte(BMA180_ADDRESS, BMA180_CMD_CTRL_REG0, bytebuffer2);
delay(10);// now give the sensor some time to wake up
}
... now take readings....
and then to put it to sleep again:
// put the BMA180 sensor to sleep again by setting the sleep = bit 1 of reg0, to "1"
bytebuffer1 = i2c_readRegByte(BMA180_ADDRESS, BMA180_CMD_CTRL_REG0);
bytebuffer1 |= (1<<1); // forces first bit of bytebuffer1 to be 1. all other bits left alone.
bytebuffer2 = i2c_writeRegByte(BMA180_ADDRESS, BMA180_CMD_CTRL_REG0, bytebuffer1);
Because this thing sleeps below 1uA, I can let the sensor run in its very power hungry low noise mode when I need to take a reading. Thanks to CosineKitty's bitmath tutorial at http://playground.arduino.cc/Code/BitMath which showed me how to toggle just the sleep bit.
And just for completeness, here are those functions:
// based on BMA180-Datalogger/bma180.ino at master · makerbot/BMA180-Datalogger · GitHub
byte i2c_readRegByte(int dev_address, byte reg_address) //MUST be integer for the i2c address
{
byte temp;
Wire.beginTransmission(dev_address); //set destination target
Wire.write(reg_address);
Wire.endTransmission();
Wire.beginTransmission(dev_address); //get data from device
Wire.requestFrom(dev_address, 1);
while(Wire.available())
{
temp = Wire.read();
}
return temp;
}
byte i2c_writeRegByte(int dev_address, byte reg_address, byte data)
{
byte result;
Wire.beginTransmission(dev_address);
Wire.write(reg_address);
Wire.write(data);
result = Wire.endTransmission();
//should I do some error checking??
if(result > 0)
{
#ifdef ECHO_TO_SERIAL //only call halt on error if in debug mode
Serial.print(F("FAIL in I2C reg write! Result code is "));
Serial.println(result);
error();
#endif
}
LowPower.powerDown(SLEEP_15Ms, ADC_OFF, BOD_OFF); // optional ... most of my sensors need settling time after a register change.
return result;
}