Teensy 4.0 + nrf24l01

Status
Not open for further replies.
Hi all,

I am working on a quadruped robot with a Teensy 4.0 onboard with a NRF24L01. I want to control this robot with a remote. This remote uses an Arduino Mega in combination with the NRF24L01.

Everything is working on the robot (IVK, input of joysticks, walking sequence), so now I want to operate it remotely. Therefore I first want to do a simple test: Make contact by sending a simple message between the Arduino Mega and the Teensy 4.0.

I have made the following code for the transmitter (Arduino Mega):

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(7, 8); // CE, CSN
const byte address[6] = "00001";

void setup() {
radio.begin();
radio.openWritingPipe(address);
radio.setPALevel(RF24_PA_HIGH);
radio.stopListening();
}

void loop() {
const char text[] = "Test";
radio.write(&text, sizeof(text));
delay(1000);
}

For the receiver (Teensy), I used this code:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(9, 10); // CE, CSN
const byte address[6] = "00001";

void setup() {
Serial.begin(9600);
radio.begin();
radio.openReadingPipe(0, address);
radio.setPALevel(RF24_PA_HIGH);
radio.startListening();
}

void loop() {
if (radio.available()) {
char text[32] = "";
radio.read(&text, sizeof(text));
Serial.println(text);
}

Now the problem is that the Teensy does not receive anything. I also tested the receiver code on an Arduino Uno and then the code does work and the message is received. So I think it has something to do with teensy and the SPI. This is also my first time working with a Teensy. I tried numerous things (like this solution //SPI.beginTransaction(SPISettings(400000000, MSBFIRST, SPI_MODE0));, setting the pins, trying other example codes....) from all other forum posts, but nothing works.

Can someone help me with this problem? Thanks already.

(I could not upload my pictures so therefore this photo link for the wiring: https://photos.app.goo.gl/wVS7FT6FZuFbQL9w8 )
 
Hi all,

I am working on a quadruped robot with a Teensy 4.0 onboard with a NRF24L01. I want to control this robot with a remote. This remote uses an Arduino Mega in combination with the NRF24L01.

Everything is working on the robot (IVK, input of joysticks, walking sequence), so now I want to operate it remotely. Therefore I first want to do a simple test: Make contact by sending a simple message between the Arduino Mega and the Teensy 4.0.

I have made the following code for the transmitter (Arduino Mega):

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(7, 8); // CE, CSN
const byte address[6] = "00001";

void setup() {
radio.begin();
radio.openWritingPipe(address);
radio.setPALevel(RF24_PA_HIGH);
radio.stopListening();
}

void loop() {
const char text[] = "Test";
radio.write(&text, sizeof(text));
delay(1000);
}

For the receiver (Teensy), I used this code:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(9, 10); // CE, CSN
const byte address[6] = "00001";

void setup() {
Serial.begin(9600);
radio.begin();
radio.openReadingPipe(0, address);
radio.setPALevel(RF24_PA_HIGH);
radio.startListening();
}

void loop() {
if (radio.available()) {
char text[32] = "";
radio.read(&text, sizeof(text));
Serial.println(text);
}

Now the problem is that the Teensy does not receive anything. I also tested the receiver code on an Arduino Uno and then the code does work and the message is received. So I think it has something to do with teensy and the SPI. This is also my first time working with a Teensy. I tried numerous things (like this solution //SPI.beginTransaction(SPISettings(400000000, MSBFIRST, SPI_MODE0));, setting the pins, trying other example codes....) from all other forum posts, but nothing works.

Can someone help me with this problem? Thanks already.

(I could not upload my pictures so therefore this photo link for the wiring: https://photos.app.goo.gl/wVS7FT6FZuFbQL9w8 )


Several things to check :

  • Dynamic payload is activated : radio.enableDynamicPayloads();
  • Not sure about this but I think the payload size, sizeof() has to be the same at both ends;
  • nRF24 maximum SPI speed is 4 MHz or less;
  • you're transmitting/receiving on the same channel AND at the same data rate;
  • if using RF24_PA_HIGH or RF24_PA_MAX, I would add a 100nF capacitor across the power supply to the nRF24 as close as possible to the transceiver chip
 
Several things to check :

  • Dynamic payload is activated : radio.enableDynamicPayloads();
  • Not sure about this but I think the payload size, sizeof() has to be the same at both ends;
  • nRF24 maximum SPI speed is 4 MHz or less;
  • you're transmitting/receiving on the same channel AND at the same data rate;
  • if using RF24_PA_HIGH or RF24_PA_MAX, I would add a 100nF capacitor across the power supply to the nRF24 as close as possible to the transceiver chip

Hi Gavin,

Thank you for your reply. I have tried al your things but nothing works...... I also tried different combinations of your suggestions.

This is the new Transmitter code:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(7, 8); // CE, CSN
const byte address[6] = "00001";
void setup() {
radio.begin();
radio.setDataRate( RF24_250KBPS );
radio.openWritingPipe(address);
radio.setPALevel(RF24_PA_MIN);
radio.stopListening();
}
void loop() {
const char text[] = "Test";
radio.write(&text, sizeof(text));
delay(1000);
}

This is the new Receiver code:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(9, 10); // CE, CSN
const byte address[6] = "00001";
void setup() {
SPI.begin();
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));

SPI.setSCK(13);

Serial.begin(9600);

radio.begin();
radio.setDataRate( RF24_250KBPS );
radio.enableDynamicPayloads();
radio.openReadingPipe(0, address);
radio.setPALevel(RF24_PA_MIN);
radio.startListening();
}
void loop() {
if (radio.available()) {
char text[32] = "";
radio.read(&text, sizeof(text));
Serial.println(text);
}
}

But it still won't work. I also tried a different code from this tutorial https://forum.arduino.cc/index.php?topic=421081. I tried it also with your suggestions....

At last, I checked that it could be a soldering mistake, so now the wires are directly connected to the Teensy, but that also did not help.

The old code does work on an Arduino Uno. So I think that it has something to do with Clock speed of the processor or bussses from the Teensy? Or Maybe that it is 32 bit?
 
I'm setting up a Teensy 4.0 with nRF24L01+. I'll try your code and see what happens and get back to you later today.

Hi Gavin,

Thank you so much for your help. I really appreciate it that you want to recreate my problem. I also saw your problem and I want to help you with that. Only I do not have the knowledge to help you....... But if you ever need help with problems with mechanical design or cad programs, than you can always send me a message.

Thank you!
 
Got the T4 and radio to work together, but it wasn't easy and I don't really know why your code does not work as is. Maybe subtle timing issues, since the Teensy is much faster than Arduino. I assumed your sending code works, but didn't test that. I used a ready-made setup as a transmitter.

Code:
#include <SPI.h>
#include <RF24.h>


RF24 radio(9, 10); // CE, CSN
const byte address[6] = "00001";

void setup() {
  Serial.begin(115200);
  while (!Serial);
  radio.begin();
  radio.setDataRate( RF24_250KBPS );
  radio.setChannel( 90 );
  radio.openReadingPipe(0, address);
  radio.printDetails();
  radio.setPALevel(RF24_PA_MIN);
  radio.startListening();
  Serial.println( "Ready" );
}
void loop() {
  if (radio.available()) {
  char text[32] = "";
  radio.read(&text, sizeof(text));
  Serial.print( "[" );
  Serial.print( int(text[2]) );
  Serial.println( "]" );
  }
}

Notice that I removed the enableDynamicPayloads(). That didn't work!

Maybe you know this already, but the first character in your address string becomes the least significant byte of the address. Since the LSB for each pipe has to be different, if you use more than one pipe, the first character of your address string should be different, as in "1node", "2node", etc. Also, when uploading new code to the Teensy, the RF24 doesn't reset and will keep old settings which makes debugging more difficult.

Anyway, if you can, try this version and let me know how it goes.
 
Got the T4 and radio to work together, but it wasn't easy and I don't really know why your code does not work as is. Maybe subtle timing issues, since the Teensy is much faster than Arduino. I assumed your sending code works, but didn't test that. I used a ready-made setup as a transmitter.

Code:
#include <SPI.h>
#include <RF24.h>


RF24 radio(9, 10); // CE, CSN
const byte address[6] = "00001";

void setup() {
  Serial.begin(115200);
  while (!Serial);
  radio.begin();
  radio.setDataRate( RF24_250KBPS );
  radio.setChannel( 90 );
  radio.openReadingPipe(0, address);
  radio.printDetails();
  radio.setPALevel(RF24_PA_MIN);
  radio.startListening();
  Serial.println( "Ready" );
}
void loop() {
  if (radio.available()) {
  char text[32] = "";
  radio.read(&text, sizeof(text));
  Serial.print( "[" );
  Serial.print( int(text[2]) );
  Serial.println( "]" );
  }
}

Notice that I removed the enableDynamicPayloads(). That didn't work!

Maybe you know this already, but the first character in your address string becomes the least significant byte of the address. Since the LSB for each pipe has to be different, if you use more than one pipe, the first character of your address string should be different, as in "1node", "2node", etc. Also, when uploading new code to the Teensy, the RF24 doesn't reset and will keep old settings which makes debugging more difficult.

Anyway, if you can, try this version and let me know how it goes.

Hi Gavin,

First: thank you for your help. I really appreciate it. So I am trying to get it to work this whole morning, but several hours later, still no result.

I used your code for the receiver (Teensy) and my old code for the transmitter (Arduino Mega). That did not work. So to make sure my transmitter works, I tried both old codes with an Arduino Uno instead of a Teensy and it did work. So now I am sure again that my transmitter is working, but you added some lines of code to the receiver for channel selection and data rate, so I also added those to the transmitter code and tried differenct combinations:

Code:
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(7, 8); // CE, CSN
const byte address[6] = "00001";

void setup() {
radio.begin();
radio.setDataRate( RF24_250KBPS ); //added this line of code to make datarate the same
radio.setChannel( 90 ); //added this line of code to set the channel the same
radio.openWritingPipe(address);
radio.setPALevel(RF24_PA_MIN);
radio.stopListening();
}

void loop() {
const char text[32] = "Test"; //added 32 between the brackets to make it the same with the receiver code
radio.write(&text, sizeof(text));
delay(1000);
}

But after those lines were added, I still could not make contact with the Teensy, but here is the status report of the Teensy:

SPI Speedz = 10 Mhz
STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1 = 0x3130303030 0xc2c2c2c2c2
RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR = 0xe7e7e7e7e7
RX_PW_P0-6 = 0x20 0x00 0x00 0x00 0x00 0x00
EN_AA = 0x3f
EN_RXADDR = 0x03
RF_CH = 0x5a
RF_SETUP = 0x21
CONFIG = 0x0e
DYNPD/FEATURE = 0x00 0x00
Data Rate = 250KBPS
Model = nRF24L01+
CRC Length = 16 bits
PA Power = PA_MIN

(I am sorry, I could not get the status report of the transmitter even with adding this line: radio.printDetails(); and serial begin)

Now the conclusion:

-The transmitter is working because it can send data to an arduino Uno.
-I think the wiring is correct because it can get a status report from the Teensy and the NRF24L01. But to be completely sure, here are the pins:

CE = 9
CSN = 10
SCK = 13
MOSI = 11
MISO = 12

-Both NRF24L01 modules are working because without the Teensy, they can send data to each other.
-The teensy is working because my normal code for the robot does work on the teensy.
-Your code is working on the teensy, so the only thing I can think of now, is that there is something wrong with the transmitter code: (something to do with the channel? Or maybe you also used an teensy as transmitter? So maybe to be sure: is it possible that you can send me your transmitter code to be sure?

About that tip of yours for the address string. So far that I can understand it, it is only relevant when you want to receive and transmit on the same NRF24L01 module? Because than it certainly something that I am going to check when I want to implement it on my project.

Again thank you for your help.
 
Hi again,

Thanks for posting all the info. I'm glad to help. Your message caught my eye because I'm working on a (kind of) robot myself. It's a very simple wheeled robot and I'm still working on motor control. But I should eventually install a transceiver for remote sensing and control so this is useful to me too.

The emitter in my tests was an Arduino that I use as a remote controlled volume. So I haven't tested the nRF24 and T4 in transmit mode. I should be able to try this later tonight. So not much use posting the code.

Ok, now to see if we're on the same wavelength.

This is how my Teensy and nRF24 are connected (just like yours, I think):

Teensy 4.0 Pin nRF24L01+ Pin
----------- ---------------
Ground 1. Gnd
3.3v (next to pin 23) 2. Vcc
CE = 9 3. CE
CSN = 10 4. CSN
SCK = 13 5. SCK
MOSI = 11 6. MOSI
MISO = 12 7. MISO
no connection 8. IRQ

This looks obvious but the way the pins are located on the transceiver is a bit tricky, right?

I'm using the RF24 v1.3.6 library from TMRh20. I tried updating to v1.3.7 but the code wouldn't even compile so I returned to 1.3.6. So maybe, check if you're using the same?

My status report looks like this :

STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1 = 0xe7e7e7e7e7 0xc2c2c2c2c2
RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR = 0xe7e7e7e7e7
RX_PW_P0-6 = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA = 0x3f
EN_RXADDR = 0x03
RF_CH = 0x5a
RF_SETUP = 0x23
CONFIG = 0x0e
DYNPD/FEATURE = 0x00 0x00
Data Rate = 250KBPS
Model = nRF24L01+
CRC Length = 16 bits
PA Power = PA_LOW

Pretty much the same as yours, except the pipe address is different and the "SPI Speed 10MHz" line does not appear in mine. The RF_SETUP is 0x23 instead of 0x21. Let me look at the manual... This is because of the different output power levels. So that looks ok.

By the way, I misread the nRF24L01+ datasheet. The max SPI speed is 10MHz, not 4MHz. I was also wrong when I said that the receive buffer has to be the same length as the sending buffer. It can be longer (but maybe not shorter?). Live and learn!

About the pipe adresses : they are used to transmit/receive from several radios over the same physical channel. The chip uses the pipe address to automatically send received messages to the right pipe. If you setup a radio network, the devices can talk to each other over the same channel. With two radios, like your setup, you don't have to worry too much about that.

I'll get to work on a Teensy to Teensy radio link and send you the code, maybe later tonight if I have time.

Have a good day.
 
Teensy 4.0 connections to nRF24L01+ transceiver

Oops, the connection table came out wrong, let me retry.

Teensy 4.0 PinnRF24L01+ Pin
Ground1. Gnd
3.3v (next to pin 23)2. Vcc
CE = 93. CE
CSN = 104. CSN
SCK = 135. SCK
MOSI = 116. MOSI
MISO = 127. MISO
no connection8. IRQ
 
Hi again,

Thanks for posting all the info. I'm glad to help. Your message caught my eye because I'm working on a (kind of) robot myself. It's a very simple wheeled robot and I'm still working on motor control. But I should eventually install a transceiver for remote sensing and control so this is useful to me too.

The emitter in my tests was an Arduino that I use as a remote controlled volume. So I haven't tested the nRF24 and T4 in transmit mode. I should be able to try this later tonight. So not much use posting the code.

Ok, now to see if we're on the same wavelength.

This is how my Teensy and nRF24 are connected (just like yours, I think):

Teensy 4.0 Pin nRF24L01+ Pin
----------- ---------------
Ground 1. Gnd
3.3v (next to pin 23) 2. Vcc
CE = 9 3. CE
CSN = 10 4. CSN
SCK = 13 5. SCK
MOSI = 11 6. MOSI
MISO = 12 7. MISO
no connection 8. IRQ

This looks obvious but the way the pins are located on the transceiver is a bit tricky, right?

I'm using the RF24 v1.3.6 library from TMRh20. I tried updating to v1.3.7 but the code wouldn't even compile so I returned to 1.3.6. So maybe, check if you're using the same?

My status report looks like this :

STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1 = 0xe7e7e7e7e7 0xc2c2c2c2c2
RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR = 0xe7e7e7e7e7
RX_PW_P0-6 = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA = 0x3f
EN_RXADDR = 0x03
RF_CH = 0x5a
RF_SETUP = 0x23
CONFIG = 0x0e
DYNPD/FEATURE = 0x00 0x00
Data Rate = 250KBPS
Model = nRF24L01+
CRC Length = 16 bits
PA Power = PA_LOW

Pretty much the same as yours, except the pipe address is different and the "SPI Speed 10MHz" line does not appear in mine. The RF_SETUP is 0x23 instead of 0x21. Let me look at the manual... This is because of the different output power levels. So that looks ok.

By the way, I misread the nRF24L01+ datasheet. The max SPI speed is 10MHz, not 4MHz. I was also wrong when I said that the receive buffer has to be the same length as the sending buffer. It can be longer (but maybe not shorter?). Live and learn!

About the pipe adresses : they are used to transmit/receive from several radios over the same physical channel. The chip uses the pipe address to automatically send received messages to the right pipe. If you setup a radio network, the devices can talk to each other over the same channel. With two radios, like your setup, you don't have to worry too much about that.

I'll get to work on a Teensy to Teensy radio link and send you the code, maybe later tonight if I have time.

Have a good day.

Hi Gavin,

Thanks you for your reply. First I wanted to say that I think that my problem originates because I want to sent data between an Arduino Mega and a Teensy. You said that you are going to look at Teensy to Teensy radio link (don't understand me wrong, it is also a great that you want to take a look at that, but I think that maybe the problem is that it is Arduino and Teensy combination). So maybe you can try the communication between arduino and Teensy? (Only if you have time)

I checked all the pins and we have connected them at the same ports. The only thing that is different is that I use an extra board that converts the 5 volts to 3.3 volts but I do not think that that can be the problem.

I checked and I am using the same library version as you.

Our status report indeed looks the same, so maybe that can be an indication that problem is related to the transmitter side of things?

Just as all previous days (almost two weeks now), I am going to work at the problem today (and al future days untill it is resolved :) ) so if I find anything, I will let you know.

Thank you for your help, advice and explination.

Have a good day.
 
Hi,

Great news, I have a new lead. I thought maybe it useful to try an other method of communation between teensy and the NRF24L01 by using irq (because maybe it has something to do with the polling speed of Teensy?). Together with de example code pingpair irq simple, contact was made between teensy and arduino. Only problem that this is one way and for me the wrong way. Because I want to send the data from the remote (arduino mega) to the receiver (Teensy).

Capture.jpg

Code for Teensy (used pin 1 for irq):

Code:
/*
 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.
 
 Created Dec 2014 - TMRh20
 */

/**
 * Example of using interrupts
 *
 * This is a very simple example of using two devices to communicate using interrupts.
 * With multiple devices, each device would need to have a separate reading pipe
 */

#include <SPI.h>
#include "RF24.h"
#include <printf.h>

// Hardware configuration
// Set up nRF24L01 radio on SPI bus plus pins 7 & 8
RF24 radio(9,10);
                                        
// Use the same address for both devices
uint8_t address[] = { "radio" };

// Simple messages to represent a 'ping' and 'pong'
uint8_t ping = 111;
uint8_t pong = 222;

volatile uint32_t round_trip_timer = 0;


/********************** Setup *********************/

void setup(){

  Serial.begin(115200);
  while (!Serial);
  Serial.println(F("Simple pingpair example"));
  Serial.println(F("Send a 'T' via Serial to transmit a single 'ping' "));
  //printf_begin(); You must uncomment this if you wish to use printDetails()
  
  // Setup and configure rf radio
  radio.begin();

  // Use dynamic payloads to improve response time
  radio.enableDynamicPayloads();
  radio.openWritingPipe(address);             // communicate back and forth.  One listens on it, the other talks to it.
  radio.openReadingPipe(1,address); 
  radio.startListening();
  
  //radio.printDetails();                             // Dump the configuration of the rf unit for debugging

  attachInterrupt(0, check_radio, LOW);             // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver
}



/********************** Main Loop *********************/
void loop() {

  if(Serial.available()){
    switch(toupper(Serial.read())){
      case 'T': 
                // Only allow 1 transmission per 45ms to prevent overlapping IRQ/reads/writes
                // Default retries = 5,15 = ~20ms per transmission max
                while(micros() - round_trip_timer < 45000){
                  //delay between writes 
                }
                Serial.print(F("Sending Ping"));
                radio.stopListening();                
                round_trip_timer = micros();
                radio.startWrite( &ping, sizeof(uint8_t),0 );
                break;    
    }
  }  
}

/********************** Interrupt *********************/

void check_radio(void)                                // Receiver role: Does nothing!  All the work is in IRQ
{
  
  bool tx,fail,rx;
  radio.whatHappened(tx,fail,rx);                     // What happened?

 
  // If data is available, handle it accordingly
  if ( rx ){
    
    if(radio.getDynamicPayloadSize() < 1){
      // Corrupt payload has been flushed
      return; 
    }
    // Read in the data
    uint8_t received;
    radio.read(&received,sizeof(received));

    // If this is a ping, send back a pong
    if(received == ping){
      radio.stopListening();
      // Normal delay will not work here, so cycle through some no-operations (16nops @16mhz = 1us delay)
      for(uint32_t i=0; i<130;i++){
         __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
      }
      radio.startWrite(&pong,sizeof(pong),0);
      Serial.print("pong");
    }else    
    // If this is a pong, get the current micros()
    if(received == pong){
      round_trip_timer = micros() - round_trip_timer;
      Serial.print(F("Received Pong, Round Trip Time: "));
      Serial.println(round_trip_timer);
    }
  }

  // Start listening if transmission is complete
  if( tx || fail ){
     radio.startListening(); 
     Serial.println(tx ? F(":OK") : F(":Fail"));
  }  
}

Code for Arduino Mega (used pin 2 for irq)

Code:
/*
 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.
 
 Created Dec 2014 - TMRh20
 */

/**
 * Example of using interrupts
 *
 * This is a very simple example of using two devices to communicate using interrupts.
 * With multiple devices, each device would need to have a separate reading pipe
 */

#include <SPI.h>
#include "RF24.h"
#include <printf.h>

// Hardware configuration
// Set up nRF24L01 radio on SPI bus plus pins 7 & 8
RF24 radio(7,8);
                                        
// Use the same address for both devices
uint8_t address[] = { "radio" };

// Simple messages to represent a 'ping' and 'pong'
uint8_t ping = 111;
uint8_t pong = 222;

volatile uint32_t round_trip_timer = 0;


/********************** Setup *********************/

void setup(){

  Serial.begin(115200);
  Serial.println(F("Simple pingpair example"));
  Serial.println(F("Send a 'T' via Serial to transmit a single 'ping' "));
  //printf_begin(); You must uncomment this if you wish to use printDetails()
  
  // Setup and configure rf radio
  radio.begin();

  // Use dynamic payloads to improve response time
  radio.enableDynamicPayloads();
  radio.openWritingPipe(address);             // communicate back and forth.  One listens on it, the other talks to it.
  radio.openReadingPipe(1,address); 
  radio.startListening();
  
  //radio.printDetails();                             // Dump the configuration of the rf unit for debugging

  attachInterrupt(0, check_radio, LOW);             // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver
}



/********************** Main Loop *********************/
void loop() {

  if(Serial.available()){
    switch(toupper(Serial.read())){
      case 'T': 
                // Only allow 1 transmission per 45ms to prevent overlapping IRQ/reads/writes
                // Default retries = 5,15 = ~20ms per transmission max
                while(micros() - round_trip_timer < 45000){
                  //delay between writes 
                }
                Serial.print(F("Sending Ping"));
                radio.stopListening();                
                round_trip_timer = micros();
                radio.startWrite( &ping, sizeof(uint8_t),0 );
                break;    
    }
  }  
}

/********************** Interrupt *********************/

void check_radio(void)                                // Receiver role: Does nothing!  All the work is in IRQ
{
  
  bool tx,fail,rx;
  radio.whatHappened(tx,fail,rx);                     // What happened?

 
  // If data is available, handle it accordingly
  if ( rx ){
    
    if(radio.getDynamicPayloadSize() < 1){
      // Corrupt payload has been flushed
      return; 
    }
    // Read in the data
    uint8_t received;
    radio.read(&received,sizeof(received));

    // If this is a ping, send back a pong
    if(received == ping){
      radio.stopListening();
      // Normal delay will not work here, so cycle through some no-operations (16nops @16mhz = 1us delay)
      for(uint32_t i=0; i<130;i++){
         __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
      }
      radio.startWrite(&pong,sizeof(pong),0);
      Serial.print("pong");
    }else    
    // If this is a pong, get the current micros()
    if(received == pong){
      round_trip_timer = micros() - round_trip_timer;
      Serial.print(F("Received Pong, Round Trip Time: "));
      Serial.println(round_trip_timer);
    }
  }

  // Start listening if transmission is complete
  if( tx || fail ){
     radio.startListening(); 
     Serial.println(tx ? F(":OK") : F(":Fail"));
  }  
}

Unfortunetly, I do not have time any more today so I will continue working tomorrow. But maybe this can also give you a lead to finally make the system work? I hope that one of us can come to the answer and I am looking forward to it.

Have a great day,
 
Hi Wittecactus,

Well, some measure of success at last! The code that works for me is transmitting from Arduino to Teensy 4.0. The same radio on each side means they transmit/receive the same signals as long as they get the same settings (data rate, channel, etc).

Again I suspect subtle timing issues. In the library code, there are several calls to delay() and comments to the effect that some calls to the library won't work without these delays. Since the Teensy is so much faster, that could be the problem. Using the code with IRQ complicates the issue IMHO. Especially since it's using NOPs to slow down the Interrupt Request Routine!

My instinct would be to add some delay(10) after each call to a radio setting and see if that helps. The nRF24 seems to take a little while to "digest" its commands. Also I have had issues with nRF24 not hearing each other because they were both in send or receive mode at exactly the same time! Just like my mom starts to talk right when I'm trying to tell her something.:)

But if it works with the IRQ example, why not exchange the programs between the Arduino and Teensy and see if that works?

Good day.
 
Hi Gavin,

I have tried several things this weeks but nothing works. I tried different codes and I have added the delays, but it does not work. I watched video's but they are all using communication between to identical arduino's and they do not have the same problems. I read in your reply that IRQ can complicates things further more so I will go back to using the normal SPI ports. Is it still possible that you can share your Arduino sending code? Than I will know for sure what went wrong with that and that the problem is maybe not code related but something else (And hopefully finally continue with the project......).

Thank you for helping me this whole thread! :)

Have a great day,
 
I have been following some of this thread, and thought I would throw out a few independent and semi things, just in case something might help.

In many cases like this, posting pictures of your actual wiring and setup might help. It might show things like, maybe bad solder joints (or no solder joints at all). Or maybe missing ground wire...

I am not sure if I have any of these radios sitting around and not sure if I ever tried that library... What I would have probably tried is the Radiohead library.

So if it were me, I would probably try out the RadioHead library with their Simple Client and Servo example sketches to see if that could get your two radios to talk. You may or may not want to stick with that library, but it would at least give you a good indication that the radios are working.
 
The reason I didn't post my code is that it contains so much other stuff that you'll have a hard time sorting through the part that deals with the nRF24 itself. Also, the comments are in french (my first language, I'm from Montreal) and it needs an ATmega328P that runs at 8MHz! I would second KurtE's advice about using simple examples (although I haven't heard of the Radiohead library and will have to look into that).

Here's the code I used for the tests...

Code:
/*
  Contrôle de volume par radio, partie émetteur.

  Envoie par radio l'état d'un bouton MUTE et la valeur de
  deux potentiomètres pour contrôler le volume dans le récepteur.
  
  L'émetteur est conçu pour fonctionner avec 2 piles AA ou AAA.
  Les piles alimentent le transceiver nRF24L01+ (ITead)
  et un ATmega328 avec une horloge de 8 MHz réduite à 4 MHz.

  Le mouvement des potentiomètres est détecté par un comparateur TLC3704.

  Changements majeurs depuis la version 2.x :

    - les potentiomètres sont remplacés par des encodeurs rotatifs
    - le TLC3704 n'est plus utilisé
    - le processeur est réveillé par les interruptions des encodeurs
    - utilisation des librairies Encoder, Bounce2 et elapsedMillis
    - changement de DEBUG en constante au lieu de define
    
  Librairie RF24 par James Coliz, Jr. <maniacbug@ymail.com>

*/

#include <SPI.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>
#define ENCODER_USE_INTERRUPTS
#include <Encoder.h>
#include <Bounce2.h>
#include <elapsedMillis.h>
#include "payload.h"

const bool DEBUG = false;

// broches Arduino assignées aux 4 boutons
const byte LEFT_BUTTON_PIN = A0;    // bouton gauche
const byte RIGHT_BUTTON_PIN = A1;   // bouton droit
const byte LEFT_ENC_BUTTON_PIN = A2;  // bouton de l'encodeur de gauche
const byte RIGHT_ENC_BUTTON_PIN = A3; // bouton de l'encodeur de droite

// led rouge pour afficher les erreurs de transmission
const byte LED_TEMOIN = 8;

// deux encodeurs avec interruptions sur les broches Arduino 2 et 3
Encoder enc0( 2, 4 );
Encoder enc1( 3, 5 );
int newEnc0;
int newEnc1;

// créer 4 objets pour les 4 boutons
Bounce left_button = Bounce();
Bounce right_button = Bounce();
Bounce left_enc_button = Bounce();
Bounce right_enc_button = Bounce();
int leftButtonState;
int rightButtonState;
int leftEncButtonState;
int rightEncButtonState;

// drapeau global pour tous les boutons
volatile bool buttonChanged = false;

// temporisation de mise en sommeil
elapsedMillis since_last_active;  // temps écoulé depuis la dernière 
                                  // action sur un bouton ou encodeur
unsigned int sleepDelay = 10000 / 2;   // délai de mise en sommeil 
                                  // Note : à 4 MHz, 10 secondes = 10 000 millisecondes / 2
elapsedMillis sinceLED; // temps écoulé depuis que la DEL témoin est allumée

// les données à transmettre
payload data; 

// transceiver connecté au bus SPI plus les broches 9 & 10
RF24 radio( 9, 10 );

// deux chemins pour communiquer avec deux récepteurs
const uint64_t pipe0 = 0xE8E8F0F0E1LL;  // récepteur A
const uint64_t pipe1 = 0xE8E8F0F0C1LL;  // récepteur B

// les commandes possibles
typedef enum { mute_down = 1, mute_up, pot0_change, pot1_change, pot_all_change } command_e;

// valeurs courantes des encodeurs
int pot0_value = 0;
int pot1_value = 0;
bool pot0_changed = false;
bool pot1_changed = false;
bool ok; // true si la dernière transmission a été reçue (auto acknowledge)

// mettre en sommeil
void do_sleep( void )
{
  // empêcher interruptions qui pourraient désactiver
  // les interruptions et nous empêcher de se réveiller
  cli();

  // désactiver les modules inutilisés en mode sommeil
  power_spi_disable();
  power_usart0_disable();
  power_timer0_disable();
  power_timer1_disable();
  power_timer2_disable();

  // désactiver tous les modules
//  power_all_disable();
  
  // choix du mode de sommeil
  set_sleep_mode( SLEEP_MODE_PWR_DOWN );
  sleep_enable();

  // réactiver interruptions
  sei();
  
  sleep_cpu();    // exécution s'arrête ici

  // une interruption d'un encodeur ou d'un bouton va nous réveiller
  sleep_disable(); // exécution se poursuit ici

  // réactiver les modules nécessaires
  power_spi_enable();
  if ( DEBUG )
    power_usart0_enable();
  power_timer0_enable();
  power_timer1_enable();
  power_timer2_enable();
}

// routine d'interruption 
// appelée lorsqu'un des 4 boutons change d'état
ISR( PCINT1_vect ) {
  buttonChanged = true;
}


/*****************************************************************
 * 
 * 
 *              SETUP
 * 
 * 
 *****************************************************************/
void setup( void ) {
  // diminuer la vitesse d'horloge
  // réduit la consommation et permet de fonctionner jusqu'à un 
  // minimum de 1,8 volts
  noInterrupts();
  clock_prescale_set( clock_div_2 ); // diviser par deux : 8 -> 4MHz

  // désactiver ADC
  ADCSRA &= ~bit( ADEN );

  // désactiver Brown-Out Detector
  MCUCR = bit( BODS ) | bit( BODSE );
  MCUCR = bit( BODS );

  // désactiver les entrées numériques inutilisées
  DIDR1 = bit( AIN1D ) | bit( AIN0D ); // comparateur analogique
  DIDR0 = bit( ADC5D ) | bit( ADC4D ); // entrées ADC

  // désactiver ACME (Analog Comparator Multiplexer Enable)
  ADCSRB = 0;

  // désactiver les modules inutilisés
  power_adc_disable();
  power_twi_disable();
  interrupts ();
 
  // désactiver le Watch Dog Timer
  wdt_disable();

  // ouvrir radio
  // canal 76 par défaut
  // taux de transfert 1 MBPS par défaut
  radio.begin();

  // régler puissance d'émission
  //radio.setPALevel( RF24_PA_MIN ); // -18dBm
  //radio.setPALevel( RF24_PA_LOW ); // -12dBm
  radio.setPALevel( RF24_PA_HIGH ); // -6dBm
  //radio.setPALevel( RF24_PA_MAX ); // 0dBm

  // changer le taux de transfert au besoin
  radio.setDataRate( RF24_250KBPS ); // pour portée maximum
  //radio.setDataRate( RF24_1MBPS );
  //radio.setDataRate( RF24_2MBPS );

  // changer de canal (fréquence d'émission-réception) au besoin
  // channel = 0 à 125 correspond à 2,400GHz à 2,500GHz
  // note : si DataRate est réglé à 2MBPS la largeur de bande
  // est de 2 MHz et on doit alors sauter un canal sur deux
  // pour éviter les chevauchements
  radio.setChannel( 90 );

  // désactiver auto-acknowledge
  // radio.setAutoAck( false );

  // fixer taille du payload
  // radio.setPayloadSize( sizeof( payload ) );

  // délai de 6 ms entre les retransmissions
  // retransmettre 15 fois maximum
  radio.setRetries( 6, 15 );
    
  // préparer broches d'entrée pour les boutons
  pinMode( LEFT_BUTTON_PIN, INPUT_PULLUP );
  pinMode( RIGHT_BUTTON_PIN, INPUT_PULLUP );
  pinMode( LEFT_ENC_BUTTON_PIN, INPUT_PULLUP );
  pinMode( RIGHT_ENC_BUTTON_PIN, INPUT_PULLUP );

  // préparer broches d'entrée pour les encodeurs
  pinMode( 2, INPUT_PULLUP );
  pinMode( 3, INPUT_PULLUP );
  pinMode( 4, INPUT_PULLUP );
  pinMode( 5, INPUT_PULLUP );

  // créer une instance pour chaque bouton
  left_button.attach( LEFT_BUTTON_PIN );
  left_button.interval( 10 ); // intervalle en ms
  right_button.attach( RIGHT_BUTTON_PIN );
  right_button.interval( 10 );
  left_enc_button.attach( LEFT_ENC_BUTTON_PIN );
  left_enc_button.interval( 10 );
  right_enc_button.attach( RIGHT_ENC_BUTTON_PIN );
  right_enc_button.interval( 10 );


  // interruption par appui sur un bouton
  // pour sortir du mode sommeil et répondre rapidement à 
  // l'appui d'un bouton
  // activer broches A0 à A3 pour pin change interrupts
  // bank 1 Port C pins 0, 1, 2 et 3
  bitSet( PCICR, PCIE1 ); // enable pin change interrupt bank 1
  bitSet( PCMSK1, PCINT8 );
  bitSet( PCMSK1, PCINT9 );
  bitSet( PCMSK1, PCINT10 );
  bitSet( PCMSK1, PCINT11 );


  // témoin rouge indique défaut de transmission
  pinMode( LED_TEMOIN, OUTPUT );
  digitalWrite( LED_TEMOIN, LOW );

  if ( DEBUG ) {
    Serial.begin( 115200 );   // régler à 115200/2 = 57600 dans la console
    Serial.println( "Prêt" );
  }  
}

/*****************************************************************
 * 
 * 
 *              LOOP
 * 
 * 
 *****************************************************************/
void loop( void )
{
  // transmissions reçues jusqu'à preuve du contraire!
  ok = true;
  if ( sinceLED > 200 ) {
    digitalWrite( LED_TEMOIN, LOW );  // éteindre témoin d'erreur de transmission
    sinceLED = 0;
  }
  
  // voir s'il est temps d'aller en mode veille
  if ( since_last_active > sleepDelay ) {
    // éteindre la radio
     radio.powerDown();

    // mettre en mode sommeil
    // un appui sur un bouton ou la rotation d'un encodeur 
    // va nous réveiller
    if ( DEBUG ) {
      Serial.println( "******************************** mise en sommeil" );
      delay( 50 );
    }
    digitalWrite( LED_TEMOIN, LOW );  // éteindre témoin d'erreur de transmission
    sinceLED = 0;
    do_sleep();
    // exécution continue ici après réveil
    // rallumer la radio
    radio.powerUp();
    since_last_active = 0;
    if ( DEBUG ) {
      Serial.println( "******************************** réveil" );
    }
  }

  left_button.update();
  // si le bouton gauche a changé d'état
  if ( left_button.fell() ) {
    // bouton est enfoncé, envoyer une commande mute_down
    data.id = 1;
    data.command = mute_down;
    data.timestamp = millis();
    // ouvrir radio en mode transmission
    radio.openWritingPipe( pipe0 );
    ok &= radio.write( &data, sizeof( payload) ); // récepteur A
    if ( DEBUG ) {
      Serial.println( "Bouton gauche enfoncé" );
    }
    since_last_active = 0;
  } else if ( left_button.rose() ) {
    // bouton est relâché, envoyer une commande mute_up
    data.id = 1;
    data.command = mute_up;
    data.timestamp = millis();
    // ouvrir radio en mode transmission
    radio.openWritingPipe( pipe0 );
    ok &= radio.write( &data, sizeof( payload) ); // récepteur A
    if ( DEBUG ) {
      Serial.println( "Bouton gauche relâché" );
    }
    since_last_active = 0;
  }

  right_button.update();
  if ( right_button.fell() ) {
    // bouton est enfoncé, envoyer une commande mute_down
    data.id = 1;
    data.command = mute_down;
    data.timestamp = millis();
    // ouvrir radio en mode transmission
    radio.openWritingPipe( pipe1 );
    ok &= radio.write( &data, sizeof( payload) ); // récepteur B
    if ( DEBUG ) {
      Serial.println( "Bouton droit enfoncé" );
    }
    since_last_active = 0;
  } else if ( right_button.rose() ) {
    // bouton est relâché, envoyer une commande mute_up
    data.id = 1;
    data.command = mute_up;
    data.timestamp = millis();
    // ouvrir radio en mode transmission
    radio.openWritingPipe( pipe1 );
    ok &= radio.write( &data, sizeof( payload) ); // récepteur B
    if ( DEBUG ) {
      Serial.println( "Bouton droit relâché" );
    }
    since_last_active = 0;
  }

  left_enc_button.update();
  // si le bouton de l'encodeur gauche est enfoncé
  if ( left_enc_button.fell() ) {
    // à compléter
    since_last_active = 0;
  } else if ( left_enc_button.rose() ) {
    // à compléter
    since_last_active = 0;
  }

  right_enc_button.update();
  // si le bouton de l'encodeur droit est enfoncé
  if ( right_enc_button.fell() ) {
    // à compléter
    since_last_active = 0;
  } else if ( right_enc_button.rose() ) {
    // à compléter
    since_last_active = 0;
  }

  // lire position des encodeurs
  newEnc0 = 12 * enc0.read();
  enc0.write( 0 );
  newEnc1 = 12 * enc1.read();
  enc1.write( 0 );

  pot0_changed = false;
  pot1_changed = false;

  // si la position de l'encodeur gauche a changé
  if ( newEnc0 != 0 ) {
    // voir si on est déjà aux limites (0 ou 1023)
    if ( pot0_value == 0 && newEnc0 <= 0 ||
         pot0_value == 1023 && newEnc0 >= 0 ) {
      // rien à changer
    } else {
      pot0_value += newEnc0;
      if ( pot0_value < 0 ) pot0_value = 0;
      if ( pot0_value > 1023 ) pot0_value = 1023;
      pot0_changed = true;
    }
    since_last_active = 0;
  }

  // si la position de l'encodeur droit a changé
  if ( newEnc1 != 0 ) {
    // voir si on est déjà aux limites (0 ou 1023)
    if ( pot1_value == 0 && newEnc1 <= 0 ||
         pot1_value == 1023 && newEnc1 >= 0 ) {
      // rien à changer
    } else {
      pot1_value += newEnc1;
      if ( pot1_value < 0 ) pot1_value = 0;
      if ( pot1_value > 1023 ) pot1_value = 1023;
      pot1_changed = true;
    }
    since_last_active = 0;
  }

  if ( DEBUG ) {
    if ( pot0_changed ) {
      Serial.print( "pot0_value : " );
      Serial.print( pot0_value );
    }
    if ( pot1_changed ) {
      Serial.print( "  pot1_value : " );
      Serial.print( pot1_value );
    }
    if ( pot0_changed || pot1_changed ) {
      Serial.println();
    }
  }  

  // si la position des deux pots a changé
  if ( pot0_changed && pot1_changed ) {
    // envoyer commande pot_all_change 
    if ( DEBUG ) {
      Serial.print( "transmission pot_all_change.." );
    }  
    data.id = 1;
    data.command = pot_all_change;
    data.pot0 = pot0_value;
    data.pot1 = pot1_value;
    data.timestamp = millis();
    // ouvrir radio en mode transmission
    radio.openWritingPipe( pipe0 );
    ok &= radio.write( &data, sizeof( payload ) );
    radio.openWritingPipe( pipe1 );
    ok &= radio.write( &data, sizeof( payload ) );
    if ( DEBUG ) {
      Serial.println( ok );
    }  
  } else if ( pot0_changed ) {
    // envoyer commande pot0_change 
    if ( DEBUG ) {
      Serial.print( "transmission pot0_change.." );
    }  
    data.id = 1;
    data.command = pot0_change;
    data.pot0 = pot0_value;
    data.pot1 = pot1_value;
    data.timestamp = millis();
    // ouvrir radio en mode transmission
    radio.openWritingPipe( pipe0 );
    ok &= radio.write( &data, sizeof( payload ) );  // récepteur A
    radio.openWritingPipe( pipe1 );
    ok &= radio.write( &data, sizeof( payload ) );  // récepteur B
    if ( DEBUG ) {
      Serial.println( ok );
    }  
  } else if ( pot1_changed ) {
    // envoyer commande pot1_change 
    if ( DEBUG ) {
      Serial.print( "transmission pot1_change.." );
    }  
    data.id = 1;
    data.command = pot1_change;
    data.pot0 = pot0_value;
    data.pot1 = pot1_value;
    data.timestamp = millis();
    // ouvrir radio en mode transmission
    radio.openWritingPipe( pipe0 );
    ok &= radio.write( &data, sizeof( payload ) );  // récepteur A
    radio.openWritingPipe( pipe1 );
    ok &= radio.write( &data, sizeof( payload ) );  // récepteur B
    if ( DEBUG ) {
      Serial.println( ok );
    }  
  }
  if ( !ok ) {
    digitalWrite( LED_TEMOIN, HIGH );  // allumer témoin d'erreur de transmission
    sinceLED = 0;
  }
}

You also need a header file that describes the payload...

Code:
/*
  Les données à transmettre/recevoir pour
  le contrôle de volume.
*/

typedef struct {
  int id; // identificateur de l'appareil
  int command; // commande à transmettre/recevoir
  int pot0; // potentiomètre gauche (0 - 1023)
  int pot1; // potentiomètre droit (0 - 1023)
  unsigned long timestamp;
} payload;
 
Wow! This Radiohead library is really an industrial grade tool. Maybe too powerful and complex for my needs, at this time. But it's nice to have in one's toolbox. Thanks Kurt.
 
I have been following some of this thread, and thought I would throw out a few independent and semi things, just in case something might help.

In many cases like this, posting pictures of your actual wiring and setup might help. It might show things like, maybe bad solder joints (or no solder joints at all). Or maybe missing ground wire...

I am not sure if I have any of these radios sitting around and not sure if I ever tried that library... What I would have probably tried is the Radiohead library.

So if it were me, I would probably try out the RadioHead library with their Simple Client and Servo example sketches to see if that could get your two radios to talk. You may or may not want to stick with that library, but it would at least give you a good indication that the radios are working.

Hi KurtE and Gavin,

Thank you for joining this thread KurtE and for your suggestions :). This radiohead library is indeed really extensive and most of the things are way beyond my knowledge. I watched a great explanation video and I tried the nrf client and the nrf server examples that are included in the library. This was easy to get it working between the Arduino Mega and the Arduino Uno (this gives the indication to me that the radio modules are working). Now it comes.... I can not get it working beween the Arduino Mega and the Teensy. I think that the reason is the same as Gavin says: That it are maybe subtle timing issues?

In the examples I also found and example for the Teensy, but this example is for a different radio module (RF69). But I tried adding some lines of code to get it working for the Teensy and added the suggestion of the SPI speed from Gavin.

This leads to the following (not working) code:

Code:
// nrf24_server.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple messageing server
// with the RH_NRF24 class. RH_NRF24 class does not provide for addressing or
// reliability, so you should only use RH_NRF24  if you do not need the higher
// level messaging abilities.
// It is designed to work with the other example nrf24_client
// Tested on Uno with Sparkfun NRF25L01 module
// Tested on Anarduino Mini (http://www.anarduino.com/mini/) with RFM73 module
// Tested on Arduino Mega with Sparkfun WRL-00691 NRF25L01 module

#include <SPI.h>
#include <RH_NRF24.h>

// Singleton instance of the radio driver
RH_NRF24 nrf24(9,10);
// RH_NRF24 nrf24(8, 7); // use this to be electrically compatible with Mirf
// RH_NRF24 nrf24(8, 10);// For Leonardo, need explicit SS pin
// RH_NRF24 nrf24(8, 7); // For RFM73 on Anarduino Mini

void setup() 
{
   Serial.begin(115200);
  delay(3000);
  while (!Serial) { delay(1); } //added these lines from the Teensy Example

   Serial.println("Teensy NRF24L01 Test!");
  Serial.println();

  SPI.begin(); //added SPI settings
  SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));

  
  if (!nrf24.init())
    Serial.println("init failed");
  // Defaults after init are 2.402 GHz (channel 2), 2Mbps, 0dBm
  if (!nrf24.setChannel(1))
    Serial.println("setChannel failed");
  if (!nrf24.setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm))
    Serial.println("setRF failed");    
}

void loop()
{
  if (nrf24.available())
  {
    // Should be a message for us now   
    uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    if (nrf24.recv(buf, &len))
    {
//      NRF24::printBuffer("request: ", buf, len);
      Serial.print("got request: ");
      Serial.println((char*)buf);
      
      // Send a reply
      uint8_t data[] = "And hello back to you";
      nrf24.send(data, sizeof(data));
      nrf24.waitPacketSent();
      Serial.println("Sent a reply");
    }
    else
    {
      Serial.println("recv failed");
    }
  }
}

I have connected to Nrf24l01 to the Teensy in the same way as in the previous library:

CE = 9
CSN = 10
SCK = 13
MOSI = 11
MISO = 12


My plan for now is to take a step back and go back to things that are more in my knowledge area: the plan is to add an extra Arduino Nano that is connected with the Teensy with serial. The Nano will be the receiver and will give the data trough serial to the Teensy. It is not the real solution but I hope that it will work. So I will let you guys know in a few days that it will work with this method.

(For KurtE: I included some pictures in my first post in the google photo link, if you need more specific photos that can help, let me know! (And I have also checked solder joints and the ground wire:)))

(For Gavin: I now understand why you did not include the code, but still thank you for that, I will go trough the code once I have time and search for differences for the transmitter)

Thank you both for your help and have a nice day,
 
Sorry again I am not an expert in this stuff, just have played with some of the radios...
May have to see if I have any of these sitting around

But I am pretty sure that with the Radiohead library you don't need to muck with the SPI... That is the beginTransaction at the start won't do anything.

That is if you look at their init code:
Code:
bool RH_NRF24::init()
{
[COLOR="#FF0000"]    // Teensy with nRF24 is unreliable at 8MHz:
    // so is Arduino with RF73
 [/COLOR]   _spi.setFrequency(RHGenericSPI::Frequency1MHz);
    if (!RHNRFSPIDriver::init())
	return false;

    // Initialise the slave select pin
    pinMode(_chipEnablePin, OUTPUT);
    digitalWrite(_chipEnablePin, LOW);
  
    // Clear interrupts
    spiWriteRegister(RH_NRF24_REG_07_STATUS, RH_NRF24_RX_DR | RH_NRF24_TX_DS | RH_NRF24_MAX_RT);
    // Enable dynamic payload length on all pipes
    spiWriteRegister(RH_NRF24_REG_1C_DYNPD, RH_NRF24_DPL_ALL);
    // Enable dynamic payload length, disable payload-with-ack, enable noack
    spiWriteRegister(RH_NRF24_REG_1D_FEATURE, RH_NRF24_EN_DPL | RH_NRF24_EN_DYN_ACK);
    // Test if there is actually a device connected and responding
    // CAUTION: RFM73 and version 2.0 silicon may require ACTIVATE
    if (spiReadRegister(RH_NRF24_REG_1D_FEATURE) != (RH_NRF24_EN_DPL | RH_NRF24_EN_DYN_ACK))
    { 
	spiWrite(RH_NRF24_COMMAND_ACTIVATE, 0x73);
        // Enable dynamic payload length, disable payload-with-ack, enable noack
        spiWriteRegister(RH_NRF24_REG_1D_FEATURE, RH_NRF24_EN_DPL | RH_NRF24_EN_DYN_ACK);
        if (spiReadRegister(RH_NRF24_REG_1D_FEATURE) != (RH_NRF24_EN_DPL | RH_NRF24_EN_DYN_ACK))
            return false;
    }

    // Make sure we are powered down
    setModeIdle();

    // Flush FIFOs
    flushTx();
    flushRx();

    setChannel(2); // The default, in case it was set by another app without powering down
    setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm);

    return true;
}
You will see that they set it them-self. Also interesting comment at start...
 
Jumping in here with a late comment. In the Radiohead library that is included with Teensyduino there is a comment in several of the radio libraries:
// Add by Adrien van den Bossche <vandenbo@univ-tlse2.fr> for Teensy
// ARM M4 requires the below. else pin interrupt doesn't work properly.
// On all other platforms, its innocuous, belt and braces

I ran into this issue with initial testing with the RF69 and included examples for the RF69 in the Teensy folder for the Radiohead examples. So make sure when you initialize the radio you are giving it both a chip select pin (CS) and the chip IRQ (IRQ), i.e.
Code:
RH_NRF24 nrf24(CS, IRQ);
which I think you are doing now.

As @KurtE stated "you don't need to much with SPI as long as you using the SPI pins which you are.
 
Actually I think the parameters for this one are the Chip Enable pin, Slave select pin and which SPI module to use.

Code:
    /// Constructor. You can have multiple instances, but each instance must have its own
    /// chip enable and slave select pin. 
    /// After constructing, you must call init() to initialise the interface
    /// and the radio module
    /// \param[in] chipEnablePin the Arduino pin to use to enable the chip for transmit/receive
    /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the NRF24 before
    /// accessing it. Defaults to the normal SS pin for your Arduino (D10 for Diecimila, Uno etc, D53 for Mega, 
    /// D10 for Maple)
    /// \param[in] spi Pointer to the SPI interface object to use. 
    ///                Defaults to the standard Arduino hardware SPI interface
    RH_NRF24(uint8_t chipEnablePin = 8, uint8_t slaveSelectPin = SS, RHGenericSPI& spi = hardware_spi);

But also in that header file is the comments:
Code:
/// The electrical connection between the nRF24L01 and the Arduino require 3.3V, the 3 x SPI pins (SCK, SDI, SDO), 
/// a Chip Enable pin and a Slave Select pin.
/// If you are using the Sparkfun WRL-00691 module, it has a voltage regulator on board and 
/// can be should with 5V VCC if possible.
/// The examples below assume the Sparkfun WRL-00691 module
///
/// Connect the nRF24L01 to most Arduino's like this (Caution, Arduino Mega has different pins for SPI, 
/// see below). Use these same connections f[COLOR="#FF0000"]or Teensy 3.1 (use 3.3V not 5V Vcc).[/COLOR]
/// \code
///                 Arduino      Sparkfun WRL-00691
///                 5V-----------VCC   (3.3V to 7V in)
///             pin D8-----------CE    (chip enable in)
///          SS pin D10----------CSN   (chip select in)
///         SCK pin D13----------SCK   (SPI clock in)
///        MOSI pin D11----------SDI   (SPI Data in)
///        MISO pin D12----------SDO   (SPI data out)
///                              IRQ   (Interrupt output, not connected)
///                 GND----------GND   (ground in)
/// \endcode
/

Note: I have not seen anything talking about if these boards have some form of PULL up resistors on the MISO pin

So if it were me, I would probably hook up Logic Analyzer to all of the signals here and see if anything is happening.

However my impression is that it was at least working some on T4? Or did the Init fail?
 
@KurtE
For the one makerfocus board that i was able to find the spec shows:

The on chip voltage regulator accepts supply voltages from 1.9 to 3.6V.
but the SPI pins are 5v tolerant supposedly.
 
Sorry again I am not an expert in this stuff, just have played with some of the radios...
May have to see if I have any of these sitting around

But I am pretty sure that with the Radiohead library you don't need to muck with the SPI... That is the beginTransaction at the start won't do anything.

That is if you look at their init code:
Code:
bool RH_NRF24::init()
{
[COLOR="#FF0000"]    // Teensy with nRF24 is unreliable at 8MHz:
    // so is Arduino with RF73
 [/COLOR]   _spi.setFrequency(RHGenericSPI::Frequency1MHz);
    if (!RHNRFSPIDriver::init())
	return false;

    // Initialise the slave select pin
    pinMode(_chipEnablePin, OUTPUT);
    digitalWrite(_chipEnablePin, LOW);
  
    // Clear interrupts
    spiWriteRegister(RH_NRF24_REG_07_STATUS, RH_NRF24_RX_DR | RH_NRF24_TX_DS | RH_NRF24_MAX_RT);
    // Enable dynamic payload length on all pipes
    spiWriteRegister(RH_NRF24_REG_1C_DYNPD, RH_NRF24_DPL_ALL);
    // Enable dynamic payload length, disable payload-with-ack, enable noack
    spiWriteRegister(RH_NRF24_REG_1D_FEATURE, RH_NRF24_EN_DPL | RH_NRF24_EN_DYN_ACK);
    // Test if there is actually a device connected and responding
    // CAUTION: RFM73 and version 2.0 silicon may require ACTIVATE
    if (spiReadRegister(RH_NRF24_REG_1D_FEATURE) != (RH_NRF24_EN_DPL | RH_NRF24_EN_DYN_ACK))
    { 
	spiWrite(RH_NRF24_COMMAND_ACTIVATE, 0x73);
        // Enable dynamic payload length, disable payload-with-ack, enable noack
        spiWriteRegister(RH_NRF24_REG_1D_FEATURE, RH_NRF24_EN_DPL | RH_NRF24_EN_DYN_ACK);
        if (spiReadRegister(RH_NRF24_REG_1D_FEATURE) != (RH_NRF24_EN_DPL | RH_NRF24_EN_DYN_ACK))
            return false;
    }

    // Make sure we are powered down
    setModeIdle();

    // Flush FIFOs
    flushTx();
    flushRx();

    setChannel(2); // The default, in case it was set by another app without powering down
    setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm);

    return true;
}
You will see that they set it them-self. Also interesting comment at start...



Hi KurtE,

Thank you for your help. I am not an expert either, not in radio stuff and not in the Teensy so all help is appreciated. That init code is interesting indeed. For now I am sure that the problem is not related to the SPI speed. Later this week I will check the signal with the osciloscope.

Also if the SPI code from the previous code is removed it still will not work.

Thank you for this suggestion and I will take a closer look into the init code to maybe find the problem there.

Have a good day,

(Edit: I now see the new posts, I will reply to these posts later)
 
Last edited:
Jumping in here with a late comment. In the Radiohead library that is included with Teensyduino there is a comment in several of the radio libraries:


I ran into this issue with initial testing with the RF69 and included examples for the RF69 in the Teensy folder for the Radiohead examples. So make sure when you initialize the radio you are giving it both a chip select pin (CS) and the chip IRQ (IRQ), i.e.
Code:
RH_NRF24 nrf24(CS, IRQ);
which I think you are doing now.

As @KurtE stated "you don't need to much with SPI as long as you using the SPI pins which you are.


Hi mjs513,

Thank you for joining this thread and for helping us to find the solution :). Correct me if I am wrong, but the RF69 uses the interrupt pin and for the nrf24l01 it is optional to use the interrupt pin. The simple client server code does not use the interrupt function. So the code is:

Code:
 RH_NRF24 nrf24(CS, CSN);


So I think that, that piece of the code is correct. But still thank you for your suggestion because I now double checked it.

(If I said something wrong or if I did not understand you well, just say it because I am not a expert myself)

Thank you for your help and for your suggestion.

Have a great day,
 
Actually I think the parameters for this one are the Chip Enable pin, Slave select pin and which SPI module to use.

Code:
    /// Constructor. You can have multiple instances, but each instance must have its own
    /// chip enable and slave select pin. 
    /// After constructing, you must call init() to initialise the interface
    /// and the radio module
    /// \param[in] chipEnablePin the Arduino pin to use to enable the chip for transmit/receive
    /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the NRF24 before
    /// accessing it. Defaults to the normal SS pin for your Arduino (D10 for Diecimila, Uno etc, D53 for Mega, 
    /// D10 for Maple)
    /// \param[in] spi Pointer to the SPI interface object to use. 
    ///                Defaults to the standard Arduino hardware SPI interface
    RH_NRF24(uint8_t chipEnablePin = 8, uint8_t slaveSelectPin = SS, RHGenericSPI& spi = hardware_spi);

But also in that header file is the comments:
Code:
/// The electrical connection between the nRF24L01 and the Arduino require 3.3V, the 3 x SPI pins (SCK, SDI, SDO), 
/// a Chip Enable pin and a Slave Select pin.
/// If you are using the Sparkfun WRL-00691 module, it has a voltage regulator on board and 
/// can be should with 5V VCC if possible.
/// The examples below assume the Sparkfun WRL-00691 module
///
/// Connect the nRF24L01 to most Arduino's like this (Caution, Arduino Mega has different pins for SPI, 
/// see below). Use these same connections f[COLOR="#FF0000"]or Teensy 3.1 (use 3.3V not 5V Vcc).[/COLOR]
/// \code
///                 Arduino      Sparkfun WRL-00691
///                 5V-----------VCC   (3.3V to 7V in)
///             pin D8-----------CE    (chip enable in)
///          SS pin D10----------CSN   (chip select in)
///         SCK pin D13----------SCK   (SPI clock in)
///        MOSI pin D11----------SDI   (SPI Data in)
///        MISO pin D12----------SDO   (SPI data out)
///                              IRQ   (Interrupt output, not connected)
///                 GND----------GND   (ground in)
/// \endcode
/

Note: I have not seen anything talking about if these boards have some form of PULL up resistors on the MISO pin

So if it were me, I would probably hook up Logic Analyzer to all of the signals here and see if anything is happening.

However my impression is that it was at least working some on T4? Or did the Init fail?



Hi KurtE,

Thank you for your reply.

The Init did not fail so I think that it is working on the T4 but that it just will not receive any signal. I will hook up the osciloscope tonight and then I will give a report on that later.

Have a good day,
 
Hi all,

I have my results from the osciloscope.

Photos would not upload again so here is a new photo link: https://photos.app.goo.gl/Xp5qY6LFHuQ13atLA

All the signals looks really great to me, they do not look round so there is no need for a Pull up resistor.

There is only communication with CSN, not with CE and the signal as can be seen in the photo is constantly repeating itself (Is only different in the start up).

I looked into the datasheets to try to understand the signals better but I need some more time with that because it is all quite complex.

I also looked again at the code and for as far as I can see is that it will go trough the setup but then in the loop when it checks if a radio is available something goes wrong because it does not print anything into the serial (but there are no errors in the initialization). But the settings in setup are the same so what is going wrong?? :confused:

Maybe that you have some new suggestions after seeing the results from the scope.

Have a great day,
 
Status
Not open for further replies.
Back
Top