I have been banging my head for far too long with this problem, and I am now thoroughly stumped. I am simply trying to get communication to happen between two nRF24 modules. The modules are seemingly configured properly but just refuse to communicate with eachother.
At first, I was working with an ATmega328P directly (The bulk of its code shown below):
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include "nrf24l01.h"
#include "spi.h"
#include "uart.h"
#define F_CPU 8000000 // For the _delay_ms() function
void rf_init ( void ); // Initialize the nRF24L01 module.
uint8_t *tx_transfer ( uint8_t *data_frame, uint8_t number_of_payload_bytes );
uint8_t *rx_transfer ( uint8_t *data_frame, uint8_t number_of_payload_bytes );
//uint8_t *received_data;
void main ( void )
{
spi_init();
uart_init();
rf_init();
DDRC &=~ (1 << DDC5); // Set the test "button" pin as an input.
DDRC |= (1 << DDC4); // Set the test "light" pin as an output.
/* Set up the receiver */
// Enter RX mode by setting PWR_UP = 1, PRIM_RX = 1, and CE = high.
rx_transfer( (uint8_t []){ (W_REGISTER | RX_PW_P0), 1 }, 1);
rx_transfer( (uint8_t []){ (W_REGISTER | CONFIG), ((1 << PWR_UP) | (1 << PRIM_RX)) }, 1 );
PORTD |= (1 << PORTD7);
_delay_ms(1); // Wait for the setup to finish.
/* Set up the transmitter */
/* Go into "standby-2" mode. In this mode the transmitter will wait for tx data and transmit it when it receives the data. */
// Enter TX mode by setting PRIM_RX = 0, PWR_UP = 1, and bringing CE high.
tx_transfer( (uint8_t []){ (W_REGISTER | CONFIG), ((1 << PWR_UP) | (0 << PRIM_RX)) }, 1 );
tx_transfer( (uint8_t []){ (W_REGISTER | RF_SETUP), ((0 << RF_PWR_LOW) | (0 << RF_PWR_HIGH)) }, 1 ); // For initial testing purposes, go into low power mode.
PORTD |= (1 << PORTD5);
_delay_ms(1);
while ( 1 )
{
if ( PINC & (1 << PINC5) )
{
tx_transfer( (uint8_t []){ (W_TX_PAYLOAD), 0b00000001 }, 1 );
_delay_ms(1);
uint8_t *received_data = rx_transfer( (uint8_t []){ (R_RX_PAYLOAD) }, 1);
if (received_data[2] == 0b00000001)
{
PORTC ^= (1 << PORTC4);
}
while ( PINC & (1 << PINC5) );
}
}
}
void rf_init( void )
{
DDRD |= (1 << DDD5); // TX Chip Enable (CE)
//PORTD |= (1 << PORTD5); // Enable the transmitter (and receiver) (See Table 1 [2]) by default *Don't enable by default*
DDRD |= (1 << DDD7); // RX Chip Enable (CE)
//PORTD |= (1 << PORTD7); // Enable the receiver (and transmitter) (See Table 1 [2]) by default *Don't enable by default
_delay_ms(100); // Give the module time to boot up (See Figure 3 [2])
}
uint8_t *tx_transfer( uint8_t *data_frame, uint8_t number_of_payload_bytes ) // number_of_bytes_to_transfer -> either bytes to send or bytes to receive.
{
uint8_t return_data_frame[2 + number_of_payload_bytes]; // Create an array to store the data received by the module.
// Position 0 is for the amount of data in the data frame, position 1 is for the status register, and the rest is for the transferred data.
return_data_frame[0] = number_of_payload_bytes + 1; // Ensures that there is always a data spot for the status register.
PORTD &=~ (1 << PORTD6); // Bring the TX slave select line low to initiate the data transfer.
for ( uint8_t transfer_byte = 0; transfer_byte < (number_of_payload_bytes + 1); transfer_byte++ ) // Always make sure that you transfer at least one byte for the status register/command word.
{
return_data_frame[1 + transfer_byte] = spi_transfer(data_frame[transfer_byte]); // Data must be placed after the first position in the array, as the first position is used to store the number of bytes in the array.
}
PORTD |= (1 << PORTD6); // Bring the TX slave select line high to complete the data transfer.
return return_data_frame;
}
uint8_t *rx_transfer( uint8_t *data_frame, uint8_t number_of_payload_bytes ) // number_of_bytes_to_transfer -> either bytes to send or bytes to receive.
{
uint8_t return_data_frame[2 + number_of_payload_bytes]; // Create an array to store the data received by the module.
// Position 0 is for the amount of data in the data frame, position 1 is for the status register, and the rest is for the transferred data.
return_data_frame[0] = number_of_payload_bytes + 1; // Ensures that there is always a data spot for the status register.
PORTB &=~ (1 << PORTB0); // Bring the TX slave select line low to initiate the data transfer.
for ( uint8_t transfer_byte = 0; transfer_byte < (number_of_payload_bytes + 1); transfer_byte++ ) // Always make sure that you transfer at least one byte for the status register/command word.
{
return_data_frame[1 + transfer_byte] = spi_transfer(data_frame[transfer_byte]); // Data must be placed after the first position in the array, as the first position is used to store the number of bytes in the array.
}
PORTB |= (1 << PORTB0); // Bring the TX slave select line high to complete the data transfer.
return return_data_frame;
}
All its doing is trying to initiate communication between two nRF24 modules connected to the ATmega328P. I know that they are being configured, as I am able to see the SPI communication happening on my oscilloscope, and I can verify that the registers which I intended to modify are being modified. But of course, no communication was happening, so I made another post here (
https://www.eevblog.com/forum/projects/setting-up-the-nrf24l01-for-transmitting-and-receiving/msg3568493/#msg3568493) hoping to get confirmation that my method was correct, but I received little useful feedback for my issue.
Since I suspect my issue had to do with how I was configuring the modules, I decided to take another approach to test them using an arduino, as there is an RF24 library that will handle most of the manual configuration, which I was doing before, automatically. So, I connected the modules to an Arduino Uno in the same configuration as they were with the AVR and wrote the following sketch:
#include <SPI.h>
#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>
#define CHANNEL 100
RF24 reciever(7,8); //CE, CSN
RF24 transmitter(5,6);//CE, CSN
const byte address[6] = "00001";
void setup()
{
while (!Serial);
Serial.begin(9600);
reciever.begin();
reciever.openReadingPipe(0, address);
reciever.startListening();
reciever.setChannel(CHANNEL);
//reciever.setAutoAck(false);
transmitter.begin();
transmitter.openWritingPipe(address);
transmitter.stopListening();
transmitter.setPALevel(RF24_PA_MIN);
transmitter.setChannel(CHANNEL);
//transmitter.setAutoAck(false);
}
void loop()
{
const char text[] = "hello there";
transmitter.write(&text, sizeof(text));
delay(1);
if (reciever.available())
{
char text[32] = {0};
reciever.read(&text, sizeof(text));
Serial.println(CHANNEL);
Serial.println(text);
}
delay(1);
}
The idea with this was to constantly transmit a string of data, and I was hoping to see that data on the serial monitor, but of course nothing was showing up, And I verified that nothing was being received by checking the SPI data, and of course saw that the receive payload was empty.
I went down the list of trying as many things as I could: I changed timings, I changed channels, I added capacitors across the power and ground pins, I switched out nRF24 modules for others in case these were fried, all to no avail.
I have exhausted every troubleshooting point that I can think of, so I am well and truly stumped with this, and I would love some help.
Thank you.