chipKIT® Development Platform

Inspired by Arduino™

bmp180, wire lib problem.

Created Mon, 23 Nov 2015 23:37:28 +0000 by gromgsxr


gromgsxr

Mon, 23 Nov 2015 23:37:28 +0000

im trying to use a bmp180 barometric pressure sensor with a uno32, iv been trying to use https://github.com/sparkfun/BMP180_Breakout lib and it all compiles and loads up fine but never actually finds the sensor, if i use the same code on an arduino uno it works fine. i think it may be something to do with the wire library on the chipkit side, if i use this code it appears to crash or freeze up and not finish running either. im currently using mpide-0150-windows-20150820, i have also tried it in arduino ide 1.6.5 with the chipkit-core-windows.16778039.v1.0.0-27 and it still does not work any suggestions??????

#include <Wire.h>
 
 
void setup()
{
  Wire.begin();
 
  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}
 
 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknow error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(5000);           // wait 5 seconds for next scan
}

majenko

Mon, 23 Nov 2015 23:56:48 +0000

I don't think the chipKIT Wire library supports any timeouts - which means that endTransmission() will never finish if there is nothing there.


pito

Tue, 24 Nov 2015 08:05:09 +0000

I am using this which works fine (not with chipkit however):

..	
    unsigned i, ff = 0;

	printf("I2C dev found, addr(r/w): ");

	for (i=0; i<255; i=i+2){
		I2CStart();
		if (I2CSend(i) == 0){
			printf("%02X(%02X/%02X)  ", i>>1, i+1, i);
			++ff;
		}
		I2CStop();
	}

	if (ff == 0) printf("None\n");
	else printf("\n");
..

You do not need timeouts when scanning. It does respond immediately or it does not.

I2C dev found, addr(r/w): 1E(3D/3C)  53(A7/A6)  57(AF/AE)  68(D1/D0)  69(D3/D2)  77(EF/EE)

gromgsxr

Tue, 24 Nov 2015 10:22:39 +0000

ok so the time out in the i2c scanner is causing it to hang, i have used lcd i2c lib on my uno32 and that works fine and functions as it should so i know that the uno32 hardware is working, but the main issue is with the bmp180, the example gets stuck before the main loop as its unable to find the sensor so it sticks on the while(1), the sensor is mounted to a proto shield and i can put it in my arduino uno and the exact same code works fine so i know the sensor wiring is correct, i have tried adding pull up resistors and there was no change. any ideas what in the libary may be causing the issue? or even an alternative way of checking to see if the uno32 can find the sensor on the i2c bus.

#include <SFE_BMP180.h>
#include <Wire.h>

// You will need to create an SFE_BMP180 object, here called "pressure":

SFE_BMP180 pressure;

#define ALTITUDE 1655.0 // Altitude of SparkFun's HQ in Boulder, CO. in meters

void setup()
{
  Serial.begin(9600);
  Serial.println("REBOOT");

  // Initialize the sensor (it is important to get calibration values stored on the device).

  if (pressure.begin())
    Serial.println("BMP180 init success");
  else
  {
    // Oops, something went wrong, this is usually a connection problem,
    // see the comments at the top of this sketch for the proper connections.

    Serial.println("BMP180 init fail\n\n");
    while(1); // Pause forever.
  }
}

void loop()
{
  char status;
  double T,P,p0,a;

  // Loop here getting pressure readings every 10 seconds.

  // If you want sea-level-compensated pressure, as used in weather reports,
  // you will need to know the altitude at which your measurements are taken.
  // We're using a constant called ALTITUDE in this sketch:
  
  Serial.println();
  Serial.print("provided altitude: ");
  Serial.print(ALTITUDE,0);
  Serial.print(" meters, ");
  Serial.print(ALTITUDE*3.28084,0);
  Serial.println(" feet");
  
  // If you want to measure altitude, and not pressure, you will instead need
  // to provide a known baseline pressure. This is shown at the end of the sketch.

  // You must first get a temperature measurement to perform a pressure reading.
  
  // Start a temperature measurement:
  // If request is successful, the number of ms to wait is returned.
  // If request is unsuccessful, 0 is returned.

  status = pressure.startTemperature();
  if (status != 0)
  {
    // Wait for the measurement to complete:
    delay(status);

    // Retrieve the completed temperature measurement:
    // Note that the measurement is stored in the variable T.
    // Function returns 1 if successful, 0 if failure.

    status = pressure.getTemperature(T);
    if (status != 0)
    {
      // Print out the measurement:
      Serial.print("temperature: ");
      Serial.print(T,2);
      Serial.print(" deg C, ");
      Serial.print((9.0/5.0)*T+32.0,2);
      Serial.println(" deg F");
      
      // Start a pressure measurement:
      // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
      // If request is successful, the number of ms to wait is returned.
      // If request is unsuccessful, 0 is returned.

      status = pressure.startPressure(3);
      if (status != 0)
      {
        // Wait for the measurement to complete:
        delay(status);

        // Retrieve the completed pressure measurement:
        // Note that the measurement is stored in the variable P.
        // Note also that the function requires the previous temperature measurement (T).
        // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
        // Function returns 1 if successful, 0 if failure.

        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          // Print out the measurement:
          Serial.print("absolute pressure: ");
          Serial.print(P,2);
          Serial.print(" mb, ");
          Serial.print(P*0.0295333727,2);
          Serial.println(" inHg");

          // The pressure sensor returns abolute pressure, which varies with altitude.
          // To remove the effects of altitude, use the sealevel function and your current altitude.
          // This number is commonly used in weather reports.
          // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m.
          // Result: p0 = sea-level compensated pressure in mb

          p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO)
          Serial.print("relative (sea-level) pressure: ");
          Serial.print(p0,2);
          Serial.print(" mb, ");
          Serial.print(p0*0.0295333727,2);
          Serial.println(" inHg");

          // On the other hand, if you want to determine your altitude from the pressure reading,
          // use the altitude function along with a baseline pressure (sea-level or other).
          // Parameters: P = absolute pressure in mb, p0 = baseline pressure in mb.
          // Result: a = altitude in m.

          a = pressure.altitude(P,p0);
          Serial.print("computed altitude: ");
          Serial.print(a,0);
          Serial.print(" meters, ");
          Serial.print(a*3.28084,0);
          Serial.println(" feet");
        }
        else Serial.println("error retrieving pressure measurement\n");
      }
      else Serial.println("error starting pressure measurement\n");
    }
    else Serial.println("error retrieving temperature measurement\n");
  }
  else Serial.println("error starting temperature measurement\n");

  delay(5000);  // Pause for 5 seconds.
}

majenko

Tue, 24 Nov 2015 11:07:11 +0000

Why do you need to search for the sensor? The address is fixed - once you know it (which you can scan for using the Arduino, or just look it up in the device datasheet) you just provide that address to your program instead of going through the rigmarole of scanning the entire bus.

If you're interested, the bit that locks up is in TwoWire::endTransmission() and there are two locations where it could potentially stall:

uint8_t TwoWire::endTransmission(uint8_t fStopBit)
{
    uint8_t retStatus = 0;
    DTWI::I2C_STATUS i2cStatus;

    // if not my bus, then the beginMaster failed and we either had
    // a collision or the slave acked, in either case report a NACK from the slave
    if(!di2c.getStatus().fMyBus)
    {
        return(2);
    }

    // wait for the transmit buffer is empty
    while(di2c.getStatus().fWrite && di2c.transmitting() != 0);  // <<=== Could go on forever

    // Get the current status
    i2cStatus = di2c.getStatus();

    // what happened to the bus, we use to have it?
    // other error
    if(!i2cStatus.fMyBus)
    {
        return(4);
    }

    // we have the bus, but not writing
    // the otherside NACKed our Write
    else if(!i2cStatus.fWrite)
    {
            retStatus = 3;
    }

    // put a stop bit out if we are not going to attempt a repeated start
    if(fStopBit)
    {
        while(!di2c.stopMaster());   // <<=== Could go on forever
    }

    return(retStatus);
}

gromgsxr

Tue, 24 Nov 2015 11:24:10 +0000

With the scanning i was just looking for a way to verify that the uno32 could find the sensor on the bus more than anything, the sensor address is 0x77. i don't actually need to use the i2c scanner.

the second lot of code is the example from the bmp180 lib thats what i need to use but it never gets past initializing the sensor.


majenko

Tue, 24 Nov 2015 11:50:12 +0000

Question... What position are JP6 and JP8 set to on your Uno32?

provided altitude: 1655 meters, 5430 feet
temperature: 115.78 deg C, 240.40 deg F
absolute pressure: -1359.67 mb, -40.16 inHg
relative (sea-level) pressure: -1660.61 mb, -49.04 inHg
computed altitude: 1655 meters, 5430 feet

True, that is complete gibberish output, but then I am communicating with a BMP087 not a BMP180... But that is your code verbatim. And yes, pullup resistors are required, not optional.


gromgsxr

Tue, 24 Nov 2015 12:30:05 +0000

the jumpers are on the left (closest to analogue pins). i have tried in both positions both with & without pull up resistors. if i use the adafruit bmp085 library it does work to some extent where it provides information but appears to be incorrect like your posted code


janbbeck

Tue, 26 Apr 2016 01:01:47 +0000

I am having the exact same problem (BMP180 hanging in endTransmission). This happens sporadically only. Sometimes it takes an hour, sometimes more, but the point is that if something goes wrong with reading the sensor (or the sensor itself breaks) the whole board hangs.

I am using UECIDE, but I don't think MPLAB will be any different. The best thing about the UECIDE is the ability of pulling in libraries for various sensors I use. However, since they mostly seem to use wire.h this is a big problem. I tried replacing the BMP180 with a different sensor (MPL115A2), but its the same thing - eventually endTransmission hangs. There may be a sporadic problem on the I2Cbus, and maybe I should hunt that down. But honestly the system should not hang because of a glitch on that bus. There should be a bad value or an error returned back. </rant>

Anyway, I am trying to find a good option to fix this, and I am left with the following questions: I have seem some suggestions that the DTWI library is better than the wire.h libray. At the same time, it seems to me that the chipkit wire.h library uses the DTWI.h library. Am I going to have the same problems if I port the BMP library to DTWI?

How about changing the two while loops you pointed out to for loops that will time out after some tries/fails?

Also, where is that file you mentioned located (for UECIDE under linux)?

Thanks for taking the time.

Why do you need to search for the sensor? The address is fixed - once you know it (which you can scan for using the Arduino, or just look it up in the device datasheet) you just provide that address to your program instead of going through the rigmarole of scanning the entire bus. If you're interested, the bit that locks up is in TwoWire::endTransmission() and there are two locations where it could potentially stall:

uint8_t TwoWire::endTransmission(uint8_t fStopBit)
{
uint8_t retStatus = 0;
DTWI::I2C_STATUS i2cStatus;
// if not my bus, then the beginMaster failed and we either had
// a collision or the slave acked, in either case report a NACK from the slave
if(!di2c.getStatus().fMyBus)
{
return(2);
}
// wait for the transmit buffer is empty
while(di2c.getStatus().fWrite &amp;&amp; di2c.transmitting() != 0);  // &lt;&lt;=== Could go on forever
// Get the current status
i2cStatus = di2c.getStatus();
// what happened to the bus, we use to have it?
// other error
if(!i2cStatus.fMyBus)
{
return(4);
}
// we have the bus, but not writing
// the otherside NACKed our Write
else if(!i2cStatus.fWrite)
{
retStatus = 3;
}
// put a stop bit out if we are not going to attempt a repeated start
if(fStopBit)
{
while(!di2c.stopMaster());   // &lt;&lt;=== Could go on forever
}
return(retStatus);
}

majenko

Tue, 26 Apr 2016 09:17:47 +0000

Wire uses DTWI, yes. However, the lack of timeouts is a function of Wire, not DTWI. It calls DTWI functions in a tight loop until the DTWI functions say they have succeeded.

So using DTWI is the way to go.


janbbeck

Tue, 26 Apr 2016 12:15:29 +0000

As always a helpful answer. Thank you Majenko. I will port the bmp180 library and report back.