Chip Select issue with nRF8001 (BLE) and nRF24l01+(Transceiver)

Ok, I’m having a hard time figuring out how to get my nRF8001 BLE module and nRF24l01+ transceiver working on the same Arduino Uno. I would like to have the BLE take over when a button/switch is ON and the transceiver take over when a different button/switch is ON (and the BLE button/switch is OFF). I’ve had some success, but it seems to be hit or miss. Therefore, I believe I’m not selecting the chips correctly. I have attempted to read about CS with multiple devices, but its over my head. I would really appreciate some help with the code below, so I can use both forms of communication. Any suggestions, edits, tutorials, explantations, etc. would be greatly appreciated! Below is my sketch and attached is horrible schematic drawling. If anyone knows a good free Arduino schematic maker, that would be awesome.

//*Arduino Uno Master (Receiver)*

//*********( THE START)***********
/*-----( Import needed libraries )-----*/
#include <SPI.h>   // Comes with Arduino IDE
#include "RF24.h"  //Transceiver Library
#include "Adafruit_BLE_UART.h" //Bluetooth Library
#include <OBD2UART.h> //OBD-II Adapter Library
/*-----( Declare Constants and Pin Numbers )-----*/
#define ADAFRUITBLE_REQ 10
#define ADAFRUITBLE_RDY 2
#define ADAFRUITBLE_RST 9

/*-----( Declare objects )-----*/
// (Create an instance of a radio, specifying the CE and CS pins. )
RF24 myRadio (7, 8); // "myRadio" is the identifier you will use in following methods
Adafruit_BLE_UART uart = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);
/*-----( Declare Variables )-----*/
byte addresses[][6] = {"1Node"}; // Create address for 1 pipe.
// Data that will be received from the transmitter
int msg[1];
int LED1 = 4;
float in, out;
COBD obd;
int RPMvalue;
int RPM_button = 5;
int RPM_value = 0;
int backup_button = 6;
int backup_value = 0;

/**************************************************************************/
/*!
    This function is called whenever select ACI events happen
*/
/**************************************************************************/
void aciCallback(aci_evt_opcode_t event)
{
  switch (event)
  {
    case ACI_EVT_DEVICE_STARTED:
      Serial.println(F("Advertising started"));
      break;
    case ACI_EVT_CONNECTED:
      Serial.println(F("Connected!"));
      break;
    case ACI_EVT_DISCONNECTED:
      Serial.println(F("Disconnected or advertising timed out"));
      break;
    default:
      break;
  }
}

void setup()   /****** SETUP: RUNS ONCE ******/
{
  // Use the serial Monitor (Symbol on far right). Set speed to 115200 (Bottom Right)
  Serial.begin(9600); 
  while (!Serial);
  delay(1000);
  Serial.println(F("LETS DO THIS"));

  //*******Transeiver********
  myRadio.begin();  // Start up the physical nRF24L01 Radio
  myRadio.setChannel(108);  // Above most Wifi Channels
  myRadio.setPALevel(RF24_PA_MIN);
  myRadio.openReadingPipe(1, addresses[0]); // Use the first entry in array 'addresses' (Only 1 right now)
  myRadio.startListening();

  //*******LED/Buzzer********
  pinMode(LED1, OUTPUT);
  pinMode(RPM_button, INPUT);
  pinMode(backup_button, INPUT);

  //*******Bluetooth*******
  uart.setACIcallback(aciCallback);
  uart.begin();

  //*******OBD-II Adapter********
  obd.begin();
  while (!obd.init());


}//--(end setup )---


void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  //*******RF24 Transeiver********
  backup_value = digitalRead(backup_button);
  if (backup_value == HIGH) {
    Serial.print(F("RF ON"));
    if ( myRadio.available()) // Check for incoming data from transmitter
    {
      while (myRadio.available())  // While there is data ready
      {
        myRadio.read(msg, 1);
        Serial.println(msg[0]);
        if (msg[0] == 110)
        {
          for (in = 0; in < 6.283; in = in + 0.003) {
            out = sin(in) * 127.5 + 127.5;
            analogWrite(LED1, out);
          }
        }
        else if (msg[0] == 100)
        {
          for (in = 0; in < 6.283; in = in + 0.011) {
            out = sin(in) * 127.5 + 127.5;
            analogWrite(LED1, out);
          }
        }
        else if (msg[0] == 111)
        {
          for (in = 0; in < 6.283; in = in + 0.0009) {
            out = sin(in) * 127.5 + 127.5;
            analogWrite(LED1, out);
          }
        }
        else
        {
          digitalWrite(LED1, LOW);
        }
        delay(100);
      }
    }
    else
    {
      Serial.print(F("No radio available"));
    }
  }
  //*******OBD-II Adapter********
  RPM_value = digitalRead(RPM_button);
  if (RPM_value == HIGH)
  {
    uart.pollACI(); 
    if (obd.readPID(PID_RPM, RPMvalue))
    {
      String s = String(RPMvalue);
      uint8_t sendbuffer[20];
      s.getBytes(sendbuffer, 20);
      char sendbuffersize = min(20, s.length());
      uart.print("RPM = ");
      uart.write(sendbuffer, sendbuffersize);
    }
  }
} //End Loop

//*********( THE END )***********

I have tried several times to actually use an SPI bus for multiple devices. I've never succeeded. I don't know why. I can only surmise that perhaps the lines from an unselected device are supposed to go high impedance, but maybe they don't. I do know of one device I tried which would definitely dirty up the lines if it was reset. My rule of thumb now is, if I want two devices on SPI, I use two Nanos as handlers, establishing completely separate SPI busses. For $3.00, it saves a lot of grief.

@dbenedi2, you seem to be using pins 7 and 8 for CE and CSN on the nRF24 but it is not obvious what are the equivalent pins for the nRF8001 - that must be buried in the Adafruit library so some archaeology is required. Adafruit seem to have a passion for hiding stuff and making simple things complex.

When you find out what pin(s) are used to control the nRF8001 you will need to ensure that one device is properly "disconnected" when you want to communicate with the other. I am not familiar with the nRF8001 but the nRF24 will only respond to SPI signals when CSN is first brought LOW.

I strongly recommend studying the Nordic datasheets for the devices - though they are not page-turners!

@jrdoner I guess that Nordic will use the same SPI settings for all of its products (well, hopefully) but that is not true for other products. As far as I can see the SD Card library (for example) uses very different settings. If you are using two "incompatible" devices you will need to restore the appropriate settings before trying to communicate with either of them. Unfortunately the libraries don't seem to provide a function to do that. They each assume they will be the only SPI device. Please note that I have not had a chance to test this theory yet.

...R

Robin2:
@dbenedi2, you seem to be using pins 7 and 8 for CE and CSN on the nRF24 but it is not obvious what are the equivalent pins for the nRF8001 - that must be buried in the Adafruit library so some archaeology is required. Adafruit seem to have a passion for hiding stuff and making simple things complex.

When you find out what pin(s) are used to control the nRF8001 you will need to ensure that one device is properly "disconnected" when you want to communicate with the other. I am not familiar with the nRF8001 but the nRF24 will only respond to SPI signals when CSN is first brought LOW.

I strongly recommend studying the Nordic datasheets for the devices - though they are not page-turners!

@Robin2 Thanks for the good information! After some testing throughout the day yesterday, I realized I could make the code work correctly if I removed everything involved with the OBD2UART library. Therefore, I have been able to connect to BLE and the transceiver, but now lack the functionally I was gaining from the OBD2UART library. The OBD2UART library is used with an adapter I bought, which pulls data from my car (Freematics – Freematics OBD-II UART Adapter V2.1 (for Arduino)). With this, it is wired to D0 & D1 on my Uno (Tx,Rx), which I believe is the actual issue. How do these pins function? How would they mess up my BLE and transceiver communication? Whats the best way to fix this? Also, I attempted to use softwareSerial(A2,A3), but had no luck. Any suggestions, explanation, links, tutorials, guidance, etc. would be greatly appreciated.

dbenedi2:
it is wired to D0 & D1 on my Uno (Tx,Rx), which I believe is the actual issue. How do these pins function?

At this stage you need to make a pencil drawing showing all the connections for all the devices attached to your Uno and post a photo of the drawing. It is too difficult to understand all the stuff clearly with a verbal description.

Pins 0 and 1 would normally be reserved for uploading programs and communicating with the Serial Monitor for debugging messages. Is it possible to use SoftwareSerial with your OB2 device?

However, having said that, I don’t see why the use of Pins 0 and 1 would affect SPI stuff.

As well as posting your drawing you should also post the latest version of your program.
And when posting code please use the code button </>so your code looks like thisand is easy to copy to a text editor

…R

The UNO's hardware RX and TX don't interfere with other pins. From the code in the opening post, the BLE is connected to the same pins as the OBD. And that indeed interferes.

When you attempted to use SoftwareSerial, what did you connect to the SoftwareSerial pins? The BLE or the OBD? It looks like the latter is hardcoded to use the hardware serial port; maybe you can move the BLE to the software serial port.

Robin2:
At this stage you need to make a pencil drawing showing all the connections for all the devices attached to your Uno and post a photo of the drawing. It is too difficult to understand all the stuff clearly with a verbal description.

Pins 0 and 1 would normally be reserved for uploading programs and communicating with the Serial Monitor for debugging messages. Is it possible to use SoftwareSerial with your OB2 device?

However, having said that, I don’t see why the use of Pins 0 and 1 would affect SPI stuff.

I have attempted to use the OBD-II adapter with SoftwareSerial with no luck. I used pins A2 & A3 during this attempt. I may have not wrote the code correctly for it, but I agree that the configuration of the OBD shouldn’t effect my BLE or transceiver. I’m still very new to microcontrollers, so maybe I’m just overlooking something obvious.

Below is my code, which is wrote for wiring configuration shown in the attached picture. That means the OBD adapter is connected to the pins D0 & D1 (Rx,Tx) and BLE is connected to pins 10(REQ ), 2 (RDY), and 9 (RST), while the transceiver is connected to 7 (CE) and 8 (CSN).

//*Arduino Uno Master (Receiver)*

//*********( THE START)***********
/*-----( Import needed libraries )-----*/
#include <SPI.h>   // Comes with Arduino IDE
#include "RF24.h"  //Transceiver Library
#include "Adafruit_BLE_UART.h" //Bluetooth Library
#include <OBD2UART.h> //OBD-II Adapter Library
/*-----( Declare Constants and Pin Numbers )-----*/
#define ADAFRUITBLE_REQ 10
#define ADAFRUITBLE_RDY 2
#define ADAFRUITBLE_RST 9
/*-----( Declare objects )-----*/
// (Create an instance of a radio, specifying the CE and CS pins. )
RF24 myRadio (7, 8); // "myRadio" is the identifier you will use in following methods
Adafruit_BLE_UART uart = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);
/*-----( Declare Variables )-----*/
byte addresses[][6] = {"1Node"}; // Create address for 1 pipe.
// Data that will be received from the transmitter
int msg[1];
int LED1 = 4;
float in, out;
COBD obd;
int RPMvalue;
int RPM_button = 5;
int RPM_value = 0;
int backup_button = 6;
int backup_value = 0;

/**************************************************************************/
/*!
    This function is called whenever select ACI events happen
*/
/**************************************************************************/
void aciCallback(aci_evt_opcode_t event)
{
  switch (event)
  {
    case ACI_EVT_DEVICE_STARTED:
      Serial.println(F("Advertising started"));
      break;
    case ACI_EVT_CONNECTED:
      Serial.println(F("Connected!"));
      break;
    case ACI_EVT_DISCONNECTED:
      Serial.println(F("Disconnected or advertising timed out"));
      break;
    default:
      break;
  }
}

void setup()   /****** SETUP: RUNS ONCE ******/
{
  // Use the serial Monitor (Symbol on far right). Set speed to 115200 (Bottom Right)
  Serial.begin(9600);
  // while (!Serial);
  delay(1000);
  Serial.println(F("LETS DO THIS"));

  //*******Transeiver********
  myRadio.begin();  // Start up the physical nRF24L01 Radio
  myRadio.setChannel(108);  // Above most Wifi Channels
  myRadio.setPALevel(RF24_PA_MAX);
  myRadio.openReadingPipe(1, addresses[0]); // Use the first entry in array 'addresses' (Only 1 right now)
  myRadio.startListening(); // myRadio.startListening();

  //*******LED/Buzzer********
  pinMode(LED1, OUTPUT);
  pinMode(RPM_button, INPUT);
  pinMode(backup_button, INPUT);

  //*******Bluetooth*******
  uart.setACIcallback(aciCallback);
  uart.begin();

  //*******OBD-II Adapter********
  obd.begin();
  while (!obd.init());
}//--(end setup )---

void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  uart.pollACI();
  //*******RF24 Transeiver********
  backup_value = digitalRead(backup_button);
  if (backup_value == HIGH) {
    Serial.print(F("RF ON"));
    delay(1000);
    if ( myRadio.available()) // Check for incoming data from transmitter
    {
      while (myRadio.available(), backup_value == HIGH)  // While there is data ready
      {
        myRadio.read(msg, 1);
        Serial.println(msg[0]);
        if (msg[0] == 110)
        {
          for (in = 0; in < 6.283; in = in + 0.003) {
            out = sin(in) * 127.5 + 127.5;
            analogWrite(LED1, out);
          }
        }
        else if (msg[0] == 100)
        {
          for (in = 0; in < 6.283; in = in + 0.011) {
            out = sin(in) * 127.5 + 127.5;
            analogWrite(LED1, out);
          }
        }
        else if (msg[0] == 111)
        {
          for (in = 0; in < 6.283; in = in + 0.0009) {
            out = sin(in) * 127.5 + 127.5;
            analogWrite(LED1, out);
          }
        }
        else
        {
          digitalWrite(LED1, LOW);
        }
        delay(100);
      }
    }
    else
    {
      Serial.print(F("No radio available"));
    }
  }
  //*******OBD-II Adapter********
  RPM_value = digitalRead(RPM_button);
  if (RPM_value == HIGH)
  {
    //obd.begin();
    if (obd.readPID(PID_RPM, RPMvalue))
    {
      String s = String(RPMvalue);
      uint8_t sendbuffer[20];
      s.getBytes(sendbuffer, 20);
      char sendbuffersize = min(20, s.length());
      uart.print("RPM = ");
      uart.write(sendbuffer, sendbuffersize);
    }
  }
} //End Loop

//*********( THE END )***********

Attached is hand drawling of my current wiring schematic. I apologize in advance for the poor quality, but it at least gives an idea of my setup. I appreciate any further assistance!

sterretje:
The UNO's hardware RX and TX don't interfere with other pins. From the code in the opening post, the BLE is connected to the same pins as the OBD. And that indeed interferes.

How can you tell that the OBD and BLE are interfering? OBD is connected to RX and TX, while the BLE uses digital pins 2,9,10,11,12, & 13.

Thanks for the reply, any further assistance would be greatly appreciated!

Image from Reply #6 so we don’t have to download it. See this Image Guide

088b9f7dc585c20beb880b895c5d39c35f119a6d.jpg

…R

This is from the code in your opening post before I posted

void setup()   /****** SETUP: RUNS ONCE ******/
{
  // Use the serial Monitor (Symbol on far right). Set speed to 115200 (Bottom Right)
  Serial.begin(9600); [b][color=red]//BLE IS 9600[/color][/b]

My conclusion: your BLE uses the serial port

I suspect this (from OBDUART.h) is the problem

#define OBD_TIMEOUT_LONG 15000 /* ms */

From a quick examination it seems that the OBD library uses blocking code that is getting in the way of other stuff you want to do.

If I am correct the library author needs to spend a day on the naughty-step.

I guess you could amend the library to make it non-blocking but it might be as easy to write your own code to read the device. The (non-blocking) examples in Serial Input Basics could help get you started.

...R

Robin2:
I suspect this (from OBDUART.h) is the problem

#define OBD_TIMEOUT_LONG 15000 /* ms */

From a quick examination it seems that the OBD library uses blocking code that is getting in the way of other stuff you want to do.

If I am correct the library author needs to spend a day on the naughty-step.

I guess you could amend the library to make it non-blocking but it might be as easy to write your own code to read the device. The (non-blocking) examples in Serial Input Basics could help get you started.

...R

It might be easier to just use two arduinos and separate the communications. Thanks for the help, I'll let you know if I figure anything out.