BMP180 and nRF2401 Fail

I am trying to build a project with a BMP180 and a nRF2401 radio and am having issues with hangs when both of these libs are in the same sketch.

You can try this at home yourself. Just open, build and upload an example from either lib and you will find things work just fine. Then add an example from the other lib example folder, build and upload and you will see that the sketch will hang. I have tried this with many different libs for each device in different combinations and all demonstrate the same issue.

I have traced it into Wire.cpp in all cases. In most cases it usually hangs at the endTransmission call from the lib into Wire. I have see this also with the nRF2401 and the DHT22 sensor lib. I have several sensors and in all cases the issue is the same.

Each device runs fine on its own but when these two devices are combined, the sketch hangs in Wire.

I have limited debugging resources and could use some help on this.

Thanks,

Tim

Each device runs fine on its own but when these two devices are combined, the sketch hangs in Wire.

When the two sketches are combined THE WAY YOU ARE DOING IT, something goes wrong. Don't expect is to guess how you combined the sketches, what pins you are using, etc. Post YOUR code!

It doesn't matter how you combine them, it doesn't work. Take one, either one, add libs from other sketch, add other configs and minimal code from other and it hangs. Comment out one or two lines of definition and it works again. While I have tried many different libs from different makers, it is wired like this: Getting Started with nRF24L01+ on Arduino | maniacbug

The code has changed from one lib to another and in different combos all with the same result. The following is simply a combination of two example sketches from two different libs.

/*
 Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 */

/**
 * Example for Getting Started with nRF24L01+ radios. 
 *
 * This is an example of how to use the RF24 class.  Write this sketch to two 
 * different nodes.  Put one of the nodes into 'transmit' mode by connecting 
 * with the serial monitor and sending a 'T'.  The ping node sends the current 
 * time to the pong node, which responds by sending the value back.  The ping 
 * node can then see how long the whole cycle took.
 */

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
//
// Hardware configuration
//
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 

RF24 radio(9,10);

//
// Topology
//

// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

//
// Role management
//
// Set up role.  This sketch uses the same software for all the nodes
// in this system.  Doing so greatly simplifies testing.  
//

// The various roles supported by this sketch
typedef enum { role_ping_out = 1, role_pong_back } role_e;

// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};

// The role of the current running sketch
role_e role = role_ping_out;

void displaySensorDetails(void)
{
  sensor_t sensor;
  bmp.getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" hPa");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" hPa");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" hPa");  
  Serial.println("------------------------------------");
  Serial.println("");
  delay(500);
}


void setup(void)
{
  //
  // Print preamble
  //

  Serial.begin(9600);
  printf_begin();
  printf("\n\rRF24/examples/GettingStarted/\n\r");
  printf("ROLE: %s\n\r",role_friendly_name[role]);
  printf("*** PRESS 'R' to begin Listening to the other node\n\r");

  //
  // Setup and configure rf radio
  //

  radio.begin();

  // optionally, increase the delay between retries & # of retries
  radio.setRetries(15,15);

  // optionally, reduce the payload size.  seems to
  // improve reliability
  //radio.setPayloadSize(8);

  //
  // Open pipes to other nodes for communication
  //

  // This simple sketch opens two pipes for these two nodes to communicate
  // back and forth.
  // Open 'our' pipe for writing
  // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)

  //if ( role == role_ping_out )
  {
    //radio.openWritingPipe(pipes[0]);
    radio.openReadingPipe(1,pipes[1]);
  }
  //else
  {
    //radio.openWritingPipe(pipes[1]);
    //radio.openReadingPipe(1,pipes[0]);
  }

  //
  // Start listening
  //

  radio.startListening();

  //
  // Dump the configuration of the rf unit for debugging
  //

  radio.printDetails();

// Start up the BMP sensor
  Serial.println("Pressure Sensor Test"); Serial.println("");
  
// Initialise the sensor 
  if(!bmp.begin())
  {
// There was a problem detecting the BMP085 ... check your connections
    Serial.print("Ooops, no BMP085 detected ... Check your wiring or I2C ADDR!");
    while(1);
  }  
  
//  Display some basic information on this sensor
  displaySensorDetails();

 
}

///////////////////////////////////////////////////////////////////////
// Main Loop
///////////////////////////////////////////////////////////////////////
void loop(void)
{
  /* Get a new BMP sensor event */ 
  Serial.println("Top of loop!!!");
  printf("Creating event for BMP\n");
  sensors_event_t event;
  printf("Going to getEvent\n");
  bmp.getEvent(&event);
  /* Display the results (barometric pressure is measure in hPa) */
  if (event.pressure)
  {
    /* Display atmospheric pressue in hPa */
    Serial.print("Pressure:    ");
    Serial.print(event.pressure);
    Serial.println(" hPa");
    
// First we get the current temperature from the BMP085 
    float temperature;
    bmp.getTemperature(&temperature);
    Serial.print("Temperature: ");
    Serial.print(temperature);
    Serial.println(" C");

//   Then convert the atmospheric pressure, and SLP to altitude
//   Update this next line with the current SLP for better results
    float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
    Serial.print("Altitude:    "); 
    Serial.print(bmp.pressureToAltitude(seaLevelPressure,
                                        event.pressure)); 
    Serial.println(" m");
    Serial.println("");
  }
  else
  {
    Serial.println("Sensor error");
  }

  //
  // Ping out role.  Repeatedly send the current time
  //

  if (role == role_ping_out)
  {
    // First, stop listening so we can talk.
    radio.stopListening();

    // Take the time, and send it.  This will block until complete
    unsigned long time = millis();
    printf("Now sending %lu...",time);
    bool ok = radio.write( &time, sizeof(unsigned long) );
    
    if (ok)
      printf("ok...");
    else
      printf("failed.\n\r");

    // Now, continue listening
    radio.startListening();

    // Wait here until we get a response, or timeout (250ms)
    unsigned long started_waiting_at = millis();
    bool timeout = false;
    while ( ! radio.available() && ! timeout )
      if (millis() - started_waiting_at > 200 )
        timeout = true;

    // Describe the results
    if ( timeout )
    {
      printf("Failed, response timed out.\n\r");
    }
    else
    {
      // Grab the response, compare, and send to debugging spew
      unsigned long got_time;
      radio.read( &got_time, sizeof(unsigned long) );

      // Spew it
      printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
    }

    // Try again 1s later
    delay(1000);
  }

  //
  // Pong back role.  Receive each packet, dump it out, and send it back
  //

  if ( role == role_pong_back )
  {
    // if there is data ready
    if ( radio.available() )
    {
      // Dump the payloads until we've gotten everything
      unsigned long got_time;
      bool done = false;
      while (!done)
      {
        // Fetch the payload, and see if this was the last one.
        done = radio.read( &got_time, sizeof(unsigned long) );

        // Spew it
        printf("Got payload %lu...",got_time);

   // Delay just a little bit to let the other unit
   // make the transition to receiver
   delay(20);
      }

      // First, stop listening so we can talk
      radio.stopListening();

      // Send the final one back.
      radio.write( &got_time, sizeof(unsigned long) );
      printf("Sent response.\n\r");

      // Now, resume listening so we catch the next packets.
      radio.startListening();
    }
  }

  //
  // Change roles
  //

  if ( Serial.available() )
  {
    char c = toupper(Serial.read());
    if ( c == 'T' && role == role_pong_back )
    {
      printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");

      // Become the primary transmitter (ping out)
      role = role_ping_out;
      radio.openWritingPipe(pipes[0]);
      radio.openReadingPipe(1,pipes[1]);
    }
    else if ( c == 'R' && role == role_ping_out )
    {
      printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
      
      // Become the primary receiver (pong back)
      role = role_pong_back;
      radio.openWritingPipe(pipes[1]);
      radio.openReadingPipe(1,pipes[0]);
    }
  }
}

What error message do you get ?

No error messages. The sketch just hangs. I have followed debug into wire.cpp where it hangs on the endTransmission. Comment out radio.begin and maybe something else related to radio and it works fine or comment out the bmp.begin and the radio works but with both active the sketch hangs in Wire.cpp. You can try this and it will hang for you too. I have tried this on my MBP, my zBook and my iMac, all with same results. I have used Arduino IDE 1.6.4 and 1.6.5 and VisualStudio with Microwhatever-its-called. All with the same result. I think I have used every single RF24 lib out there and three different BMP180 libs.

I have about given up on it but the idea of using something else at 10 times the cost isn't too appealing to me though I have ordered two Particle Photons but I won't see them until next month and they are still 5 times more expensive than the nRF2401 board.

Thanks for any ideas or help you might be able to lend to this curiosity.

Tim

It could be, you are running out of ram.

My suggestion would be to remove or temporarily remove a lot of that printed stuff. Or move all those text strings into the flash memory.

This supposed I2C transmission problem, does it occur when you access the BMP device from the function call displaySensorDetails( ) or from bmp.getEvent( ) ?

removing the prints doesn't work. The build shows:

Sketch uses 14,344 bytes (44%) of program storage space. Maximum is 32,256 bytes.
Global variables use 1,257 bytes (61%) of dynamic memory, leaving 791 bytes for local variables.

Yes, depending upon which is first, it will hang at writeBytes when wire called from bmp classes.

Tim

If you exclude the radio part, does your communication with the BMP device actually work ?

Yes and if the BMP is disabled the radio works. You can try it yourself and see it not work, like I said at the very top. It is repeatable and easy to setup.

Global variables use 1,257 bytes (61%) of dynamic memory, leaving 791 bytes for local variables.

There is more to this than meets the eye.

I've just had a look at that Adafruit unified sensor crap. Those structs they have defined are extravagantly profligate with memory. It's really a quite unsuitable library to be using with a 2k ram arduino. And you are declaring instances of those structs as local variables in your code. I am convinced that you have a memory problem.

The BMP devices uses I2C and the nrf uses SPI, so there isn't a direct communication conflict. Thousands of arduino users have managed to use I2C and SPI separately.

Your sketch wouldn't compile for me. This line, in particular, doesn't appear to match the method in Adafruit_BMP085_U.h:

    Serial.print(bmp.pressureToAltitude(seaLevelPressure,
                                        event.pressure));

But after fixing that line it compiled and ran on my stock Uno, correctly reporting the pressure/temperature.

I don't have a radio, only a BMP180. So I wonder what it is about the radio, an SPI connected device that doesn't use interrupts, that could hang the I2C bus. Could it be that you have an electrical problem of some sort?

I have used many different BMP180 libs and a zillion different nRF2401 libs, none work together. They each work independently but not together.

I abandoned the Adafruit libs a few weeks ago, just FYI. None of them work.

Tim

So, you have three computers, and several different compilers, and you get the same outcome.

And the 2 parts of the application work, separately.

And you combine them, and it doesn't work.

And the reason for this is, your combined program exceeds the very limited RAM resource of the arduino you are using.

Your code is Kardasianesque in its profligacy with RAM. You are using a ridiculous sensor interface library which is equally extravagant with pointlessly wasting memory. Maybe it is useful on an STM32 device with 256k of RAM, but not on your 2k Arduino.

I don't have a 2K Arduino right now, so even if I could be bothered assembling all the bits and pieces to make it work, I can't test your problem.

I have used many different BMP180 libs and a zillion different nRF2401 libs, none work together. They each work independently but not together.

And the reason for this. Insufficient memory on the Arduino. Simple.

I abandoned the Adafruit libs a few weeks ago, just FYI. None of them work.

So why did you post the sketch which is using them, then ?

None of them work.

So how have thousands of people managed to get their gadgets to work, then ? Except you !

Even that ridiculous one your posted, works, IF YOU RUN IT ON A DEVICE WITH ENOUGH RAM !

Geez, you are kind of a dick aren't you.

removing the prints doesn't work.

Have you actually tried that ?

it will hang at writeBytes when wire called from bmp classes.

How do you actually know this ?

I have traced it into Wire.cpp in all cases. In most cases it usually hangs at the endTransmission call from the lib into Wire. I have see this also with the nRF2401 and the DHT22 sensor lib. I have several sensors and in all cases the issue is the same.

Really ? You had a problem with Wire.cpp using the DHT22 sensor ? What you you trying to use Wire for, when the DHT22 sensor doesn't use it, and the nRF2401 doesn't use it ?

How about posting the code which didn't work for you there.

The sketch I compiled for an Uno with 2K RAM had over 700 bytes free. So it's probably not a RAM issue, although it's impossible to be certain since we don't actually have a compilable version of your code.

We don't know what your hardware setup is either.

Good luck.

The sketch I compiled for an Uno with 2K RAM had over 700 bytes free.

That's 1.3k of global variables. It doesn't include local variables. Did you look to see how big some of those local variables are ?