Problem with the nRF24L01+ when trying to swap between Transmitter and Receiver

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

The setup that I am aiming for has a number of nodes, which will send the IMU data to a central base station. The communication is achieved using a bunch of nRF24L01+ modules.
So far I have been able to transmit and receive the data from one node to the base station. The problem starts when I want to swap the roles of the node and the base station so that I can transmit and receive the data bi-directionally.
Initially, the base station (configured as TX) sends an 8-byte data to the node (configured as RX). After checking the received data, the node (configured as TX) sends back the IMU data to the base station (configured as RX).

Somehow, after the node receives the data from the base station, it is never able to send the IMU data back to the base station. The TX is done with polling and the RX is done with interrupts.
Can anyone of you point me in the right direction? Thanks!

[P.S. Using Atmega32U4]

I am posting the source code of both the base station and node here:

 

Base Station code:

/*
 * Base_Station.c
 *
 * Created: 21-Nov-18 6:18:12 PM
 * Author : Frederic Philips
 */
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include <stdint.h>
#include <stdlib.h>
#define F_CPU 16000000UL	//16 MHz frequency
#define BAUD  57600
#include <util/setbaud.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#include "nrf.h"

#define MOSI		2
#define MISO		3
#define SCLK		1
#define CSN		0
#define CE		4

#define PAYLOAD_LEN	8

uint8_t BS_payload_TX[PAYLOAD_LEN] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
uint8_t BS_payload_RX[PAYLOAD_LEN];

//0 - TX; 1 - RX
volatile uint8_t mode = 0;

void nRF_TX_mode(void);
void nRF_RX_mode(void);
void Flush_tx(void);
void Flush_rx(void);
void reset(void);
void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len);
uint8_t nrf24_getStatus(void);
uint8_t nrf24_isSending(void);

/************************************************************************************
** AVR_Init function:
** - Start-up delay
** - Initializes the I/O peripherals
*************************************************************************************/
void AVR_Init(void)
{
        _delay_ms(750);		//Short pause after BNO055 Power-On Reset(Mandatory)
        DDRD |= _BV(1);		//Set TX as output
        DDRD &= ~(_BV(0));	//Set RX as input
}

/************************************************************************************
** USART Reference:
** - ATmega32U4 Datasheet - Rev. CORP072610(Pg.186)
** - AVR Microcontroller and Embedded Systems - Mazidi(Pg.395)
** - Embedded C Programming and the Atmel AVR - Barnett(Pg.132)
*************************************************************************************
** To initialize the UART, the following steps are to be followed:
** - Set the Baud rate(use <util/setbaud.h>, which depends on the macros F_CPU & BAUD)
** - Disable double speed(2x) mode
** - Set the no. of data bits(8/9 bits), stop bit(1/2) and parity bit(None/Odd/Even)
** - Set the USART mode(Synchronous/Asynchronous/Asynchronous 2x)
** - Enable Receiver & Transmitter(Set RXEN & TXEN bits in UCSRB register)
*************************************************************************************/
void UART_Init(void)
{
        DDRD |= _BV(1);		//Set TX as output
        DDRD &= ~(_BV(0));	//Set RX as input

        //Set the BAUD rate(Ref. ATmega32U4 Datasheet Pg.189, Table 18-1)
        //To hard-code the Baud rate, Ref. Tables 18-9 to 18-12 in Pgs. 210 - 213
        UBRR1 = ((F_CPU / (16UL * BAUD)) - 1);

        //Disables 2x speed
        UCSR1A &= ~(_BV(U2X1));

        //Enable 8-bit character size, one stop-bit, no parity & asynchronous mode
        UCSR1C |= _BV(UCSZ11) | _BV(UCSZ10);

        //Enable Transmitter & Receiver
        UCSR1B |= _BV(TXEN1) | _BV(RXEN1);
}

/************************************************************************************
** UART_Tx function:
** - Transmits the ADC data via the USB Serial
** - The data is received & displayed in a Hyperterminal
*************************************************************************************/
void UART_Tx(unsigned char data)
{
        loop_until_bit_is_set(UCSR1A, UDRE1);	//Wait until buffer is empty
        UDR1 = data;				//Send data
}

void Init_SPI()
{
        //Set the output pin(s) for SPI
        DDRB |= _BV(CE);	//CE
        DDRB |= _BV(CSN);	//CSN
        DDRB |= _BV(MOSI);  	//MOSI
        DDRB |= _BV(SCLK);  	//SCLK

        //Set the input pin(s) for SPI
        DDRB &= ~_BV(MISO); 	//MISO

        SPCR |= ((1 << SPE) | (1 << MSTR) | (1 << SPR0));	//Enable SPI as master
        SPCR &= (~_BV(SPI2X) & ~_BV(SPR1)); 		   	//Set clock rate but not too important

        PORTB |= _BV(CSN);	//CSN high
        PORTB &= ~_BV(CE);	//CE low
}

unsigned char spi_tranceiver(unsigned char data)
{
        // Load data into the buffer
        SPDR = data;

        //Wait until transmission complete
        while(!(SPSR & (1 << SPIF)));   

        //Return received data
        return(SPDR);
}

unsigned char Read_Byte(unsigned char reg)
{
        _delay_us(10);
        PORTB &= ~_BV(CSN);	//CSN low
        _delay_us(10);
        spi_tranceiver(R_REGISTER + reg);
        _delay_us(10);
        reg = spi_tranceiver(NOP);
        _delay_us(10);
        PORTB |= _BV(CSN);	//CSN high
        return reg;
}

void Write_byte(unsigned char reg, unsigned char data)
{
        _delay_us(10);
        PORTB &= ~_BV(CSN);	//CSN low
        _delay_us(10);
        spi_tranceiver(W_REGISTER + reg);
        _delay_us(10);
        spi_tranceiver(data);
        _delay_us(10);
        PORTB |= _BV(CSN);	//CSN high
}

void Init_nrf(void)
{
        //Enable auto-acknowledgment for data pipe 0
        Write_byte(EN_AA, 0x01);

        //Enable data pipe 0
        Write_byte(EN_RXADDR, 0x01);

        //Set address width to 5 bytes
        Write_byte(SETUP_AW, 0x03);

        //Set channel frequency to 2.505GHz
        Write_byte(RF_CH, 0x69);

        //Set data rate to 2Mbps and 0dB gain
        Write_byte(RF_SETUP, 0x0E);

        //Enable W_TX_PAYLOAD_NOACK command
//	Write_byte(FEATURE, 0x01);

        //Set the 5-bytes receiver address as 0x01 0x02 0x03 0x04 0x05
        _delay_us(10);
        PORTB &= ~_BV(CSN);	//CSN low
        _delay_us(10);
        //Setup p0 pipe address for receiving
        spi_tranceiver(W_REGISTER + RX_ADDR_P0);
        _delay_us(10);
        spi_tranceiver(0x11);
        _delay_us(10);
        spi_tranceiver(0x12);
        _delay_us(10);
        spi_tranceiver(0x13);
        _delay_us(10);
        spi_tranceiver(0x14);
        _delay_us(10);
        spi_tranceiver(0x15);
        _delay_us(10);
        PORTB |= _BV(CSN);	//CSN high

        //Set the 5-bytes transmitter address as 0x01 0x02 0x03 0x04 0x05
        _delay_us(10);
        PORTB &= ~_BV(CSN);	//CSN low
        _delay_us(10);
        //Setup the transmitter address
        spi_tranceiver(W_REGISTER + TX_ADDR);
        _delay_us(10);
        spi_tranceiver(0xAA);
        _delay_us(10);
        spi_tranceiver(0xBB);
        _delay_us(10);
        spi_tranceiver(0xCC);
        _delay_us(10);
        spi_tranceiver(0xDD);
        _delay_us(10);
        spi_tranceiver(0xEE);
        _delay_us(10);
        PORTB |= _BV(CSN);	//CSN high

        //Set the payload width as 8-bytes
        Write_byte(RX_PW_P0, 0x08);

        //Set the retransmission delay to 750us with 15 retries
        Write_byte(SETUP_RETR, 0x2F);

        //Boot the nrf as TX and mask the maximum retransmission interrupt(disable)
        //Enable CRC and set the length to 2-bytes
        nRF_TX_mode();

        _delay_ms(10);		//10ms delay after power-up
}

void nRF_TX_mode(void)
{
        Flush_tx();							 //Flush TX FIFO
        Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status
        PORTB &= ~_BV(CE);						 //CE low - Standby-I
        //Power-up and set as TX
        Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP) | (0 << PRIM_RX));
        //Mask TX_DR and MAX_RT interrupts
        Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT));
        _delay_us(150);
}

void nRF_RX_mode(void)
{
        Flush_rx();							 //Flush RX FIFO
        Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status
        PORTB &= ~_BV(CE); 						 //CE low
        //Power-up as set as RX
        Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP) | (1 << PRIM_RX));
        //Mask TX_DR and MAX_RT interrupts
        Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT));
        PORTB |= _BV(CE);  						 //CE high
        _delay_us(150);
}

void Flush_tx(void)
{
        _delay_us(10);
        PORTB &= ~_BV(CSN);	//CSN low
        _delay_us(10);
        spi_tranceiver(FLUSH_TX);
        _delay_us(10);
        PORTB |= _BV(CSN);	//CSN high
        _delay_us(10);
}

void Flush_rx(void)
{
        _delay_us(10);
        PORTB &= ~_BV(CSN);
        _delay_us(10);
        spi_tranceiver(FLUSH_RX);
        _delay_us(10);
        PORTB |= _BV(CSN);
        _delay_us(10);
}

void Payload_TX(uint8_t* data, uint8_t len)
{
        uint8_t i;

        for(i = 0; i < len; i++)
        {
                spi_tranceiver(BS_payload_TX[i]);
        }
}

void transmit_data(unsigned char *tdata)
{
        Flush_tx();
        PORTB &= ~_BV(CSN); //CSN low
        _delay_us(10);
        //Transmit payload with ACK enabled
        spi_tranceiver(W_TX_PAYLOAD);
        _delay_us(10);
        Payload_TX(BS_payload_TX, PAYLOAD_LEN);
        _delay_us(10);
        PORTB |= _BV(CSN);  //CSN high
        _delay_us(10);      //Need at least 10us before sending
        PORTB |= _BV(CE);   //CE high
        _delay_us(10);      //Hold CE high for at least 10us and not longer than 4ms
        PORTB &= ~_BV(CE);  //CE low
}

uint8_t nrf24_getStatus()
{
        uint8_t rv;
        PORTB &= ~_BV(CSN); //CSN low
        rv = spi_tranceiver(NOP);
        PORTB |= _BV(CSN);  //CSN high
        return rv;
}

uint8_t nrf24_isSending()
{
        uint8_t status;

        /* read the current status */
        status = nrf24_getStatus();

        /* if sending successful (TX_DS) or max retries exceeded (MAX_RT). */
        if((status & ((1 << TX_DS)  | (1 << MAX_RT))))
        {
                return 0; /* false */
        }

        return 1; /* true */
}

void Init_INT6(void)
{
        EICRB &= ~(1 << ISC60) | (1 << ISC61);	//INT6 active when low
        EIMSK |= (1 << INT6);			//Enable INT6
        sei();					//Enable global interrupts
}

ISR(INT6_vect)
{
        cli();					//Disable global interrupt

        PORTB &= ~_BV(CE); 			//Stop listening
        // Pull down chip select
        PORTB &= ~_BV(CSN); //CSN low
        _delay_us(10);
        // Send command to read RX payload
        spi_tranceiver(R_RX_PAYLOAD);
        _delay_us(10);
        // Read payload
        Payload_RX(BS_payload_RX, BS_payload_RX, PAYLOAD_LEN);
        _delay_us(10);
        // Pull up chip select
        PORTB |= _BV(CSN);  //CSN high
        _delay_us(10);
        // Reset status register
        Write_byte(STATUS, (1 << RX_DR));
        mode = 0;	    //Set as TX
}

/* send and receive multiple bytes over SPI */
void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len)
{
        uint8_t i;

        for(i = 0; i < len; i++)
        {
                data_in[i] = spi_tranceiver(data_out[i]);
                UART_Tx(data_in[i]);   //Send the received data to UART
        }
}

void reset(void)
{
        _delay_us(10);
        //Reset IRQ-flags in status register
                Write_byte(STATUS, 0x70);
        _delay_us(10);
}

int main(void)
{
        AVR_Init();
        Init_SPI();
        Init_nrf();
        UART_Init();
        Init_INT6();

        //0 - TX; 1 - RX
        int8_t mode = 0;

        //Disable Interrupt initially
        cli();

        //Endless Loop
        while(1)
        {
                if(mode == 0) //TX
                {
                        //Configure as Transmitter
                        nRF_TX_mode();

//			UART_Tx(0x55);   	//Send BP1 to UART

                        transmit_data(BS_payload_TX);
                        while(nrf24_isSending());
                        reset();

//			UART_Tx(0x66);   	//Send BP2 to UART

                        //Configure as Receiver
                        mode = 1;		//Set as RX
                        nRF_RX_mode();
                        PORTB |= _BV(CE);	//Start listening again
                        sei();		

//			UART_Tx(0x77);   	//Send BP3 to UART
                }

//		UART_Tx(0x88);   		//Send BP4 to UART
        }
}

Node code:

/*
 * Node_1.c
 *
 * Created: 21-Nov-18 6:21:39 PM
 * Author : Frederic Philips
 */
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include <stdint.h>
#include <stdlib.h>
#define F_CPU 16000000UL	//16 MHz frequency
#define BAUD  57600
#include <util/setbaud.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#include "Test_BNO055.h"
#include "i2cmaster.h"
#include "nrf.h"

#define MOSI		2
#define MISO		3
#define SCLK		1
#define CSN		0
#define CE		4

#define PAYLOAD_LEN	8

uint8_t N1_payload_TX[PAYLOAD_LEN];
uint8_t N1_payload_RX[PAYLOAD_LEN];

volatile uint8_t RX_Payload_cnt;

void nRF_TX_mode(void);
void nRF_RX_mode(void);
void Flush_tx(void);
void Flush_rx(void);
void reset(void);
void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len);
uint8_t nrf24_getStatus(void);
uint8_t nrf24_isSending(void);

/************************************************************************************
** AVR_Init function:
** - Start-up delay
** - Initializes the I/O peripherals
*************************************************************************************/
void AVR_Init(void)
{
	_delay_ms(750);		//Short pause after BNO055 Power-On Reset(Mandatory)
	DDRD |= _BV(1);		//Set TX as output
	DDRD &= ~(_BV(0));	//Set RX as input

	//Initialize TWI data
	TWI_data = 0;
}

/************************************************************************************
** USART Reference:
** - ATmega32U4 Datasheet - Rev. CORP072610(Pg.186)
** - AVR Microcontroller and Embedded Systems - Mazidi(Pg.395)
** - Embedded C Programming and the Atmel AVR - Barnett(Pg.132)
*************************************************************************************
** To initialize the UART, the following steps are to be followed:
** - Set the Baud rate(use <util/setbaud.h>, which depends on the macros F_CPU & BAUD)
** - Disable double speed(2x) mode
** - Set the no. of data bits(8/9 bits), stop bit(1/2) and parity bit(None/Odd/Even)
** - Set the USART mode(Synchronous/Asynchronous/Asynchronous 2x)
** - Enable Receiver & Transmitter(Set RXEN & TXEN bits in UCSRB register)
*************************************************************************************/
void UART_Init(void)
{
	DDRD |= _BV(1);		//Set TX as output
	DDRD &= ~(_BV(0));	//Set RX as input

	//Set the BAUD rate(Ref. ATmega32U4 Datasheet Pg.189, Table 18-1)
	//To hard-code the Baud rate, Ref. Tables 18-9 to 18-12 in Pgs. 210 - 213
	UBRR1 = ((F_CPU / (16UL * BAUD)) - 1);

	//Disables 2x speed
	UCSR1A &= ~(_BV(U2X1));

	//Enable 8-bit character size, one stop-bit, no parity & asynchronous mode
	UCSR1C |= _BV(UCSZ11) | _BV(UCSZ10);

	//Enable Transmitter & Receiver
	UCSR1B |= _BV(TXEN1) | _BV(RXEN1);
}

/************************************************************************************
** UART_Tx function:
** - Transmits the ADC data via the USB Serial
** - The data is received & displayed in a Hyperterminal
*************************************************************************************/
void UART_Tx(unsigned char data)
{
	loop_until_bit_is_set(UCSR1A, UDRE1);	//Wait until buffer is empty
	UDR1 = data;				//Send data
}

void BNO_Read_Quaternions(void)
{
	i2c_start_wait(BNO055_ADDRESS+I2C_WRITE);	//Set device address and read mode
	i2c_write(BNO055_QUATERNION_DATA_W_LSB_ADDR);	//Access LSB of Quaternion_W value
	i2c_rep_start(BNO055_ADDRESS+I2C_READ);		//Set device address and read mode
	N1_payload_TX[0] = i2c_readNak();
	UART_Tx(N1_payload_TX[0]);
	i2c_stop();

	i2c_start_wait(BNO055_ADDRESS+I2C_WRITE);	//Set device address and read mode
	i2c_write(BNO055_QUATERNION_DATA_W_MSB_ADDR);	//Access MSB of Quaternion_W value
	i2c_rep_start(BNO055_ADDRESS+I2C_READ);		//Set device address and read mode
	N1_payload_TX[1] = i2c_readNak();
	UART_Tx(N1_payload_TX[1]);
	i2c_stop();

	i2c_start_wait(BNO055_ADDRESS+I2C_WRITE);	//Set device address and read mode
	i2c_write(BNO055_QUATERNION_DATA_X_LSB_ADDR);	//Access LSB of Quaternion_X value
	i2c_rep_start(BNO055_ADDRESS+I2C_READ);		//Set device address and read mode
	N1_payload_TX[2] = i2c_readNak();
	UART_Tx(N1_payload_TX[2]);
	i2c_stop();

	i2c_start_wait(BNO055_ADDRESS+I2C_WRITE);	//Set device address and read mode
	i2c_write(BNO055_QUATERNION_DATA_X_MSB_ADDR);	//Access MSB of Quaternion_X value
	i2c_rep_start(BNO055_ADDRESS+I2C_READ);		//Set device address and read mode
	N1_payload_TX[3] = i2c_readNak();
	UART_Tx(N1_payload_TX[3]);
	i2c_stop();

	i2c_start_wait(BNO055_ADDRESS+I2C_WRITE);	//Set device address and read mode
	i2c_write(BNO055_QUATERNION_DATA_Y_LSB_ADDR);	//Access LSB of Quaternion_Y value
	i2c_rep_start(BNO055_ADDRESS+I2C_READ);		//Set device address and read mode
	N1_payload_TX[4] = i2c_readNak();
	UART_Tx(N1_payload_TX[4]);
	i2c_stop();

	i2c_start_wait(BNO055_ADDRESS+I2C_WRITE);	//Set device address and read mode
	i2c_write(BNO055_QUATERNION_DATA_Y_MSB_ADDR);	//Access MSB of Quaternion_Y value
	i2c_rep_start(BNO055_ADDRESS+I2C_READ);		//Set device address and read mode
	N1_payload_TX[5] = i2c_readNak();
	UART_Tx(N1_payload_TX[5]);
	i2c_stop();

	i2c_start_wait(BNO055_ADDRESS+I2C_WRITE);	//Set device address and read mode
	i2c_write(BNO055_QUATERNION_DATA_Z_LSB_ADDR);	//Access LSB of Quaternion_Z value
	i2c_rep_start(BNO055_ADDRESS+I2C_READ);		//Set device address and read mode
	N1_payload_TX[6] = i2c_readNak();
	UART_Tx(N1_payload_TX[6]);
	i2c_stop();

	i2c_start_wait(BNO055_ADDRESS+I2C_WRITE);	//Set device address and read mode
	i2c_write(BNO055_QUATERNION_DATA_Z_MSB_ADDR);	//Access MSB of Quaternion_Z value
	i2c_rep_start(BNO055_ADDRESS+I2C_READ);		//Set device address and read mode
	N1_payload_TX[7] = i2c_readNak();
	UART_Tx(N1_payload_TX[7]);
	i2c_stop();
}

void Init_SPI()
{
	//Set the output pin(s) for SPI
	DDRB |= _BV(CE);	//CE
	DDRB |= _BV(CSN);	//CSN
	DDRB |= _BV(MOSI);  	//MOSI
	DDRB |= _BV(SCLK);  	//SCLK

	//Set the input pin(s) for SPI
	DDRB &= ~_BV(MISO); 	//MISO

	SPCR |= ((1 << SPE) | (1 << MSTR) | (1 << SPR0));	//Enable SPI as master
	SPCR &= (~_BV(SPI2X) & ~_BV(SPR1)); 		   	//Set clock rate but not too important

	PORTB |= _BV(CSN);	//CSN high
	PORTB &= ~_BV(CE);	//CE low
	_delay_ms(10);		//10ms delay
}

unsigned char spi_tranceiver(unsigned char data)
{
	//Load data into the buffer
	SPDR = data;

	//Wait until transmission complete
	while(!(SPSR & (1 << SPIF)));

	//Return received data
	return(SPDR);
}

unsigned char Read_Byte(unsigned char reg)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(R_REGISTER + reg);
	_delay_us(10);
	reg = spi_tranceiver(NOP);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	return reg;
}

void Write_byte(unsigned char reg, unsigned char data)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(W_REGISTER + reg);
	_delay_us(10);
	spi_tranceiver(data);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
}

void Init_nrf(void)
{
	//Enable auto-acknowledgment for data pipe 0
	Write_byte(EN_AA, 0x01);

	//Enable data pipe 0
	Write_byte(EN_RXADDR, 0x01);

	//Set address width to 5 bytes
	Write_byte(SETUP_AW, 0x03);

	//Set channel frequency to 2.505GHz
	Write_byte(RF_CH, 0x69);

	//Set data rate to 2Mbps and 0dB gain
	Write_byte(RF_SETUP, 0x0E);

	//Enable W_TX_PAYLOAD_NOACK command
//	Write_byte(FEATURE, 0x01);

	//Set the 5-bytes receiver address as 0x01 0x02 0x03 0x04 0x05
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	//Setup p0 pipe address for receiving
	spi_tranceiver(W_REGISTER + RX_ADDR_P0);
	_delay_us(10);
	spi_tranceiver(0xAA);
	_delay_us(10);
	spi_tranceiver(0xBB);
	_delay_us(10);
	spi_tranceiver(0xCC);
	_delay_us(10);
	spi_tranceiver(0xDD);
	_delay_us(10);
	spi_tranceiver(0xEE);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high

	//Set the 5-bytes transmitter address as 0x01 0x02 0x03 0x04 0x05
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	//Setup the transmitter address
	spi_tranceiver(W_REGISTER + TX_ADDR);
	_delay_us(10);
	spi_tranceiver(0x11);
	_delay_us(10);
	spi_tranceiver(0x12);
	_delay_us(10);
	spi_tranceiver(0x13);
	_delay_us(10);
	spi_tranceiver(0x14);
	_delay_us(10);
	spi_tranceiver(0x15);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high

	//Set the payload width as 8-bytes
	Write_byte(RX_PW_P0, 0x08);

	//Set the retransmission delay to 750us with 15 retries
	Write_byte(SETUP_RETR, 0x2F);

	//Boot the nrf as RX and mask the maximum retransmission interrupt(disable)
	//Enable CRC and set the length to 2-bytes
	nRF_RX_mode();

	_delay_ms(10);		//10ms delay after power-up
}

void nRF_TX_mode(void)
{
	Flush_tx();							 //Flush TX FIFO
	Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status
	PORTB &= ~_BV(CE);						 //CE low - Standby-I
	//Power-up and set as TX
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP) | (0 << PRIM_RX));
	//Mask TX_DR and MAX_RT interrupts
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT));
	_delay_us(150);
}

void nRF_RX_mode(void)
{
	Flush_rx();							 //Flush RX FIFO
	Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status
	PORTB &= ~_BV(CE); 						 //CE low
	//Power-up as set as RX
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP) | (1 << PRIM_RX));
	//Mask TX_DR and MAX_RT interrupts
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT));
	PORTB |= _BV(CE);  						 //CE high
	_delay_us(150);
}

void Flush_tx(void)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(FLUSH_TX);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	_delay_us(10);
}

void Flush_rx(void)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(FLUSH_RX);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	_delay_us(10);
}

void Payload_TX(uint8_t* data, uint8_t len)
{
	uint8_t i;

	for(i = 0; i < len; i++)
	{
		spi_tranceiver(N1_payload_TX[i]);
	}
}

void transmit_data(unsigned char *tdata)
{
	Flush_tx();
	PORTB &= ~_BV(CSN); //CSN low
	_delay_us(10);
	//Transmit payload with ACK enabled
	spi_tranceiver(W_TX_PAYLOAD);
	_delay_us(10);
	Payload_TX(N1_payload_TX, PAYLOAD_LEN);
	_delay_us(10);
	PORTB |= _BV(CSN);  //CSN high
	_delay_us(10);      //Need at least 10us before sending
	PORTB |= _BV(CE);   //CE high
	_delay_us(10);      //Hold CE high for at least 10us and not longer than 4ms
	PORTB &= ~_BV(CE);  //CE low
}

uint8_t nrf24_getStatus()
{
	uint8_t rv;
	PORTB &= ~_BV(CSN); //CSN low
	rv = spi_tranceiver(NOP);
	PORTB |= _BV(CSN);  //CSN high
	return rv;
}

uint8_t nrf24_isSending()
{
	uint8_t status;

	/* read the current status */
	status = nrf24_getStatus();

	/* if sending successful (TX_DS) or max retries exceeded (MAX_RT). */
	if((status & ((1 << TX_DS)  | (1 << MAX_RT))))
	{
		return 0; /* false */
	}

	return 1; /* true */
}

void Init_INT6(void)
{
	EICRB &= ~(1 << ISC60) | (1 << ISC61);	//INT6 active when low
	EIMSK |= (1 << INT6);			//Enable INT6
	sei();					//Enable global interrupts
}

ISR(INT6_vect)
{
	cli();					//Disable global interrupt

	PORTB &= ~_BV(CE); 			//Stop listening
	// Pull down chip select
	PORTB &= ~_BV(CSN); //CSN low
	_delay_us(10);
	// Send command to read RX payload
	spi_tranceiver(R_RX_PAYLOAD);
	_delay_us(10);
	// Read payload
	Payload_RX(N1_payload_RX, N1_payload_RX, PAYLOAD_LEN);
	_delay_us(10);
	// Pull up chip select
	PORTB |= _BV(CSN);  //CSN high
	_delay_us(10);
	// Reset status register
	Write_byte(STATUS, (1 << RX_DR));
}

/* send and receive multiple bytes over SPI */
void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len)
{
	uint8_t i;

	for(i=0; i<len; i++)
	{
		data_in[i] = spi_tranceiver(data_out[i]);
		UART_Tx(data_in[i]);		   //Send the received data to UART
		if (data_in[i] == 0xAA)
		{
			RX_Payload_cnt++;
			UART_Tx(RX_Payload_cnt);   //Send RX_Payload count to UART
		}
	}
}

void reset(void)
{
	_delay_us(10);
	//Reset IRQ-flags in status register
	Write_byte(STATUS, 0x70);
	_delay_us(10);
}

/************************************************************************************
** Main function:
** - Contains an endless loop
** - Sets the BNO055 in NDOF mode and fetches the quaternion data
*************************************************************************************/
int main(void)
{
	AVR_Init();
	i2c_init();

	Init_SPI();
	Init_nrf();
	UART_Init();
	Init_INT6();

	i2c_start_wait(BNO055_ADDRESS+I2C_WRITE);	//Set device address and read mode
	i2c_write(BNO055_OPR_MODE_ADDR);
	i2c_write(OPERATION_MODE_NDOF);			//Set operation mode to NDOF
	i2c_stop();
	_delay_ms(10);

	//Initialize the received payload count
	RX_Payload_cnt = 0;

	Flush_rx();
	reset();
	PORTB |= _BV(CE);			//Start listening

	//Endless Loop
	while(1)
	{
		if (RX_Payload_cnt == PAYLOAD_LEN)
		{
			UART_Tx(0x55);   	//Send BP1 to UART

			RX_Payload_cnt = 0;

			//Configure as Transmitter
			nRF_TX_mode();

			UART_Tx(0x66);   	//Send BP2 to UART

			//Read the Quaternions data from the BNO055
			BNO_Read_Quaternions();

			UART_Tx(0x77);   	//Send BP3 to UART

			//Transmit Quaternion payload
			transmit_data(N1_payload_TX);
			while(nrf24_isSending());
			reset();

			UART_Tx(0x88);   	//Send BP4 to UART

			//Configure as Receiver
			nRF_RX_mode();
			Flush_rx();
			reset();
			PORTB |= _BV(CE);	//Start listening again
			sei();

			UART_Tx(0x99);   	//Send BP5 to UART
		}

//		UART_Tx(0x00);   //Send BP5 to UART
	}
}

 

This topic has a solution.

Regards,
Frederic Philips

Last Edited: Sun. Dec 23, 2018 - 07:06 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Frederic,

 

I think this question would be answered best if you seeked help in nordic devzone, because it seems to me as its a mesh problem.

 

Regards,

Moe

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have some limited experience with the nRF24L01+. I used it once several years ago.

I never liked their idea of data pipes, which are either to complicated to bother with, or too limited to actually do something usefull.

 

There are also some hardware issues with the Chinese variants.

First, reliability and range often improve by soldering more decoupling caps directly on the PCB.

Second, there is at least one clone of the nRF24L01+ which is about 99.99% compatible but has some weird issues and does not always work.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

Sorry for the late reply. I was able to solve the issue finally.

While setting the nRF to TX mode, I was doing this:

Write_byte(CONFIG, Read_Byte(CONFIG) | (0 << PRIM_RX));

Instead of this:
 

Write_byte(CONFIG, Read_Byte(CONFIG) & ~(1 << PRIM_RX));

So the nRF was never set to the TX mode and stayed indefinitely in the RX mode.

 

If anyone is interested, here is the final working code:
[Note: The Node initializes as RX and waits for the Base Station to initiate the communicaiton]

 

Node:

/*
 * Node_1.c
 *
 * Created: 21-Nov-18 6:21:39 PM
 * Author : Frederic Philips
 */ 
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include <stdint.h>
#include <stdlib.h>
#define F_CPU 16000000UL	//16 MHz frequency
#include <util/delay.h>
#include <avr/interrupt.h>

#include "nrf.h"

#define MOSI		2
#define MISO		3
#define SCLK		1
#define CSN		0
#define CE		4

#define PAYLOAD_LEN	8

uint8_t N1_payload_TX[PAYLOAD_LEN] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
uint8_t N1_payload_RX[PAYLOAD_LEN];

volatile uint8_t RX_Payload_cnt;

void nRF_TX_mode(void);
void nRF_RX_mode(void);
void Flush_tx(void);
void Flush_rx(void);
void reset(void);
void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len);
uint8_t nrf24_getStatus(void);
uint8_t nrf24_isSending(void);

/************************************************************************************
** AVR_Init function:
** - Start-up delay
** - Initializes the I/O peripherals
*************************************************************************************/
void AVR_Init(void)
{
	_delay_ms(750);		//Short pause after BNO055 Power-On Reset(Mandatory)
}

void Init_SPI()
{
	//Set the output pin(s) for SPI
	DDRB |= _BV(CE);	//CE
	DDRB |= _BV(CSN);	//CSN
	DDRB |= _BV(MOSI);  	//MOSI
	DDRB |= _BV(SCLK);  	//SCLK

	//Set the input pin(s) for SPI
	DDRB &= ~_BV(MISO); 	//MISO

	
	SPCR |= ((1 << SPE) | (1 << MSTR) | (1 << SPR0));	//Enable SPI as master
	SPCR &= (~_BV(SPI2X) & ~_BV(SPR1)); 		   	//Set clock rate but not too important
	
	PORTB |= _BV(CSN);	//CSN high
	PORTB &= ~_BV(CE);	//CE low
	_delay_ms(10);		//10ms delay
}

unsigned char spi_tranceiver(unsigned char data)
{
	//Load data into the buffer
	SPDR = data;
	
	//Wait until transmission complete
	while(!(SPSR & (1 << SPIF)));

	//Return received data
	return(SPDR);
}

unsigned char Read_Byte(unsigned char reg)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(R_REGISTER + reg);
	_delay_us(10);
	reg = spi_tranceiver(NOP);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	return reg;
}

void Write_byte(unsigned char reg, unsigned char data)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(W_REGISTER + reg);
	_delay_us(10);
	spi_tranceiver(data);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
}

void Init_nrf(void)
{	
	//Enable auto-acknowledgment for data pipe 0
	Write_byte(EN_AA, 0x01);
	
	//Enable data pipe 0
	Write_byte(EN_RXADDR, 0x01);

	//Set address width to 5 bytes
	Write_byte(SETUP_AW, 0x03);
	
	//Set channel frequency to 2.505GHz
	Write_byte(RF_CH, 0x69);
	
	//Set data rate to 2Mbps and 0dB gain
	Write_byte(RF_SETUP, 0x0E);
	
	//Enable W_TX_PAYLOAD_NOACK command
//	Write_byte(FEATURE, 0x01);
	
	//Set the 5-bytes receiver address as 0x01 0x02 0x03 0x04 0x05
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	//Setup p0 pipe address for receiving
	spi_tranceiver(W_REGISTER + RX_ADDR_P0);
	_delay_us(10);
	spi_tranceiver(0xAA);
	_delay_us(10);
	spi_tranceiver(0xBB);
	_delay_us(10);
	spi_tranceiver(0xCC);
	_delay_us(10);
	spi_tranceiver(0xDD);
	_delay_us(10);
	spi_tranceiver(0xEE);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	
	//Set the 5-bytes transmitter address as 0x01 0x02 0x03 0x04 0x05
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	//Setup the transmitter address
	spi_tranceiver(W_REGISTER + TX_ADDR);
	_delay_us(10);
	spi_tranceiver(0x11);
	_delay_us(10);
	spi_tranceiver(0x12);
	_delay_us(10);
	spi_tranceiver(0x13);
	_delay_us(10);
	spi_tranceiver(0x14);
	_delay_us(10);
	spi_tranceiver(0x15);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	
	//Set the payload width as 8-bytes
	Write_byte(RX_PW_P0, 0x08);
	
	//Set the retransmission delay to 750us with 15 retries
	Write_byte(SETUP_RETR, 0x2F);
	
	//Boot the nrf as RX and mask the maximum retransmission interrupt(disable)
	//Enable CRC and set the length to 2-bytes
	nRF_RX_mode();
	
	_delay_ms(10);		//10ms delay after power-up
}

void nRF_TX_mode(void)
{
	PORTB &= ~_BV(CE);						 //CE low - Standby-I
	//Power-up and set as TX
	Write_byte(CONFIG, Read_Byte(CONFIG) & ~(1 << PRIM_RX));
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP));
	Flush_tx();							 //Flush TX FIFO
	Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status
	//Mask TX_DR and MAX_RT interrupts
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT));
	_delay_us(150);
}

void nRF_RX_mode(void)
{
	PORTB &= ~_BV(CE); 						 //CE low - Standby-I
	//Power-up as set as RX
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP) | (1 << PRIM_RX));
	Flush_rx();							 //Flush RX FIFO
	Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status
	//Mask TX_DR and MAX_RT interrupts
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT));
	PORTB |= _BV(CE);  						 //CE high
	_delay_us(150);
}

void Flush_tx(void)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(FLUSH_TX);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	_delay_us(10);
}

void Flush_rx(void)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(FLUSH_RX);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	_delay_us(10);
}

void Payload_TX(uint8_t* data, uint8_t len)
{
	uint8_t i;
	
	for(i = 0; i < len; i++)
	{
		spi_tranceiver(N1_payload_TX[i]);
	}
}

void transmit_data(unsigned char *tdata)
{
	Flush_tx();
	PORTB &= ~_BV(CSN); //CSN low
	_delay_us(10);
	//Transmit payload with ACK enabled
	spi_tranceiver(W_TX_PAYLOAD);
	_delay_us(10);
	Payload_TX(N1_payload_TX, PAYLOAD_LEN);
	_delay_us(10);
	PORTB |= _BV(CSN);  //CSN high
	_delay_us(10);      //Need at least 10us before sending
	PORTB |= _BV(CE);   //CE high
	_delay_us(10);      //Hold CE high for at least 10us and not longer than 4ms
	PORTB &= ~_BV(CE);  //CE low
}

uint8_t nrf24_getStatus()
{
	uint8_t rv;
	PORTB &= ~_BV(CSN); //CSN low
	rv = spi_tranceiver(NOP);
	PORTB |= _BV(CSN);  //CSN high
	return rv;
}

uint8_t nrf24_isSending()
{
	uint8_t status;

	/* read the current status */
	status = nrf24_getStatus();
	
	/* if sending successful (TX_DS) or max retries exceeded (MAX_RT). */
	if((status & ((1 << TX_DS)  | (1 << MAX_RT))))
	{
		return 0; /* false */
	}

	return 1; /* true */
}

void Init_INT6(void)
{
	EICRB &= ~(1 << ISC60) | (1 << ISC61);	//INT6 active when low
	EIMSK |= (1 << INT6);			//Enable INT6
	sei();					//Enable global interrupts
}

ISR(INT6_vect)
{
	cli();					//Disable global interrupt
	
	PORTB &= ~_BV(CE); 			//Stop listening
	// Pull down chip select 
	PORTB &= ~_BV(CSN); //CSN low
	_delay_us(10);
	// Send command to read RX payload 
	spi_tranceiver(R_RX_PAYLOAD);
	_delay_us(10);
	// Read payload 
	Payload_RX(N1_payload_RX, N1_payload_RX, PAYLOAD_LEN);
	_delay_us(10);
	// Pull up chip select
	PORTB |= _BV(CSN);  //CSN high
	_delay_us(10);
	// Reset status register 
	Write_byte(STATUS, (1 << RX_DR));
}

/* send and receive multiple bytes over SPI */
void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len)
{
	uint8_t i;

	for(i=0; i<len; i++)
	{
		data_in[i] = spi_tranceiver(data_out[i]);
		if (data_in[i] == 0xAA)
		{
			RX_Payload_cnt++;
		}
	}
}

void reset(void)
{
	_delay_us(10);
	//Reset IRQ-flags in status register
	Write_byte(STATUS, 0x70);
	_delay_us(10);
}

/************************************************************************************
** Main function:
** - Contains an endless loop
** - Sets the BNO055 in NDOF mode and fetches the quaternion data
*************************************************************************************/
int main(void)
{
	AVR_Init();	
	Init_SPI();
	Init_nrf();
	UART_Init();
	Init_INT6();
	
	//Initialize the received payload count
	RX_Payload_cnt = 0;
	
	Flush_rx();
	reset();
	PORTB |= _BV(CE);			//Start listening

	//Endless Loop
	while(1)
	{	
		if (RX_Payload_cnt == PAYLOAD_LEN)
		{
			
			RX_Payload_cnt = 0;
			
			//Configure as Transmitter
			nRF_TX_mode();			
		
			transmit_data(N1_payload_TX);
			while(nrf24_isSending());
			reset();
				
			//Configure as Receiver
			nRF_RX_mode();
			Flush_rx();
			PORTB |= _BV(CE);	//Start listening again
			sei();
		}
	}
}

Base Station:

/*
 * Base_Station.c
 *
 * Created: 21-Nov-18 6:18:12 PM
 * Author : Frederic Philips
 */ 
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include <stdint.h>
#include <stdlib.h>
#define F_CPU 16000000UL	//16 MHz frequency
#define BAUD  57600
#include <util/setbaud.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#include "nrf.h"

#define MOSI		2
#define MISO		3
#define SCLK		1
#define CSN		0
#define CE		4

#define PAYLOAD_LEN	8

uint8_t BS_payload_TX[PAYLOAD_LEN] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
uint8_t BS_payload_RX[PAYLOAD_LEN];

//0 - TX; 1 - RX
volatile uint8_t mode;

void nRF_TX_mode(void);
void nRF_RX_mode(void);
void Flush_tx(void);
void Flush_rx(void);
void reset(void);
void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len);
uint8_t nrf24_getStatus(void);
uint8_t nrf24_isSending(void);

/************************************************************************************
** AVR_Init function:
** - Start-up delay
** - Initializes the I/O peripherals
*************************************************************************************/
void AVR_Init(void)
{
	_delay_ms(750);		//Short pause after BNO055 Power-On Reset(Mandatory)
	DDRD |= _BV(1);		//Set TX as output
	DDRD &= ~(_BV(0));	//Set RX as input
}

/************************************************************************************
** USART Reference:
** - ATmega32U4 Datasheet - Rev. CORP072610(Pg.186)
** - AVR Microcontroller and Embedded Systems - Mazidi(Pg.395)
** - Embedded C Programming and the Atmel AVR - Barnett(Pg.132)
*************************************************************************************
** To initialize the UART, the following steps are to be followed:
** - Set the Baud rate(use <util/setbaud.h>, which depends on the macros F_CPU & BAUD)
** - Disable double speed(2x) mode
** - Set the no. of data bits(8/9 bits), stop bit(1/2) and parity bit(None/Odd/Even)
** - Set the USART mode(Synchronous/Asynchronous/Asynchronous 2x)
** - Enable Receiver & Transmitter(Set RXEN & TXEN bits in UCSRB register)
*************************************************************************************/
void UART_Init(void)
{
	DDRD |= _BV(1);		//Set TX as output
	DDRD &= ~(_BV(0));	//Set RX as input

	//Set the BAUD rate(Ref. ATmega32U4 Datasheet Pg.189, Table 18-1)
	//To hard-code the Baud rate, Ref. Tables 18-9 to 18-12 in Pgs. 210 - 213
	UBRR1 = ((F_CPU / (16UL * BAUD)) - 1);
	
	//Disables 2x speed
	UCSR1A &= ~(_BV(U2X1));
	
	//Enable 8-bit character size, one stop-bit, no parity & asynchronous mode
	UCSR1C |= _BV(UCSZ11) | _BV(UCSZ10);
	
	//Enable Transmitter & Receiver
	UCSR1B |= _BV(TXEN1) | _BV(RXEN1);
}

/************************************************************************************
** UART_Tx function:
** - Transmits the ADC data via the USB Serial
** - The data is received & displayed in a Hyperterminal
*************************************************************************************/
void UART_Tx(unsigned char data)
{
	loop_until_bit_is_set(UCSR1A, UDRE1);	//Wait until buffer is empty
	UDR1 = data;				//Send data	
}

void Init_SPI()
{
	//Set the output pin(s) for SPI
	DDRB |= _BV(CE);	//CE
	DDRB |= _BV(CSN);	//CSN
	DDRB |= _BV(MOSI);  	//MOSI
	DDRB |= _BV(SCLK);  	//SCLK

	//Set the input pin(s) for SPI
	DDRB &= ~_BV(MISO); 	//MISO

	
	SPCR |= ((1 << SPE) | (1 << MSTR) | (1 << SPR0));	//Enable SPI as master
	SPCR &= (~_BV(SPI2X) & ~_BV(SPR1)); 		   	//Set clock rate but not too important
	
	PORTB |= _BV(CSN);	//CSN high
	PORTB &= ~_BV(CE);	//CE low
}

unsigned char spi_tranceiver(unsigned char data)
{
	// Load data into the buffer
	SPDR = data;
	
	//Wait until transmission complete
	while(!(SPSR & (1 << SPIF)));   

	//Return received data
	return(SPDR);
}

unsigned char Read_Byte(unsigned char reg)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(R_REGISTER + reg);
	_delay_us(10);
	reg = spi_tranceiver(NOP);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	return reg;
}

void Write_byte(unsigned char reg, unsigned char data)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(W_REGISTER + reg);
	_delay_us(10);
	spi_tranceiver(data);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
}

void Init_nrf(void)
{
	//Enable auto-acknowledgment for data pipe 0
	Write_byte(EN_AA, 0x01);
	
	//Enable data pipe 0
	Write_byte(EN_RXADDR, 0x01);

	//Set address width to 5 bytes
	Write_byte(SETUP_AW, 0x03);
	
	//Set channel frequency to 2.505GHz
	Write_byte(RF_CH, 0x69);
	
	//Set data rate to 2Mbps and 0dB gain
	Write_byte(RF_SETUP, 0x0E);
	
	//Enable W_TX_PAYLOAD_NOACK command
//	Write_byte(FEATURE, 0x01);
	
	//Set the 5-bytes receiver address as 0x01 0x02 0x03 0x04 0x05
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	//Setup p0 pipe address for receiving
	spi_tranceiver(W_REGISTER + RX_ADDR_P0);
	_delay_us(10);
	spi_tranceiver(0x11);
	_delay_us(10);
	spi_tranceiver(0x12);
	_delay_us(10);
	spi_tranceiver(0x13);
	_delay_us(10);
	spi_tranceiver(0x14);
	_delay_us(10);
	spi_tranceiver(0x15);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	
	//Set the 5-bytes transmitter address as 0x01 0x02 0x03 0x04 0x05
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	//Setup the transmitter address
	spi_tranceiver(W_REGISTER + TX_ADDR);
	_delay_us(10);
	spi_tranceiver(0xAA);
	_delay_us(10);
	spi_tranceiver(0xBB);
	_delay_us(10);
	spi_tranceiver(0xCC);
	_delay_us(10);
	spi_tranceiver(0xDD);
	_delay_us(10);
	spi_tranceiver(0xEE);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	
	//Set the payload width as 8-bytes
	Write_byte(RX_PW_P0, 0x08);
	
	//Set the retransmission delay to 750us with 15 retries
	Write_byte(SETUP_RETR, 0x2F);
	
	//Boot the nrf as TX and mask the maximum retransmission interrupt(disable)
	//Enable CRC and set the length to 2-bytes
	nRF_TX_mode();
	
	_delay_ms(10);		//10ms delay after power-up
}

void nRF_TX_mode(void)
{
	PORTB &= ~_BV(CE);						 //CE low - Standby-I						 
	//Power-up and set as TX
	Write_byte(CONFIG, Read_Byte(CONFIG) & ~(1 << PRIM_RX));
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP));
//	_delay_ms(1);
	Flush_tx();							 //Flush TX FIFO
	Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status
	//Mask TX_DR and MAX_RT interrupts
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT));
	_delay_us(150);
}

void nRF_RX_mode(void)
{
	PORTB &= ~_BV(CE); 						 //CE low - Standby-I
	//Power-up as set as RX
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << PWR_UP) | (1 << PRIM_RX));
	Flush_rx();							 //Flush RX FIFO
	Write_byte(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); //Reset status
	//Mask TX_DR and MAX_RT interrupts
	Write_byte(CONFIG, Read_Byte(CONFIG) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT));
	PORTB |= _BV(CE);  						 //CE high
	_delay_us(150);
}

void Flush_tx(void)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);	//CSN low
	_delay_us(10);
	spi_tranceiver(FLUSH_TX);
	_delay_us(10);
	PORTB |= _BV(CSN);	//CSN high
	_delay_us(10);
}

void Flush_rx(void)
{
	_delay_us(10);
	PORTB &= ~_BV(CSN);
	_delay_us(10);
	spi_tranceiver(FLUSH_RX);
	_delay_us(10);
	PORTB |= _BV(CSN);
	_delay_us(10);
}

void Payload_TX(uint8_t* data, uint8_t len)
{
	uint8_t i;
	
	for(i = 0; i < len; i++)
	{
		spi_tranceiver(BS_payload_TX[i]);
	}
}

void transmit_data(unsigned char *tdata)
{
	Flush_tx();
	PORTB &= ~_BV(CSN); //CSN low
	_delay_us(10);
	//Transmit payload with ACK enabled
	spi_tranceiver(W_TX_PAYLOAD);
	_delay_us(10);
	Payload_TX(BS_payload_TX, PAYLOAD_LEN);
	_delay_us(10);
	PORTB |= _BV(CSN);  //CSN high
	_delay_us(10);      //Need at least 10us before sending
	PORTB |= _BV(CE);   //CE high
	_delay_us(10);      //Hold CE high for at least 10us and not longer than 4ms
	PORTB &= ~_BV(CE);  //CE low
}

uint8_t nrf24_getStatus()
{
	uint8_t rv;
	PORTB &= ~_BV(CSN); //CSN low
	rv = spi_tranceiver(NOP);
	PORTB |= _BV(CSN);  //CSN high
	return rv;
}

uint8_t nrf24_isSending()
{
	uint8_t status;

	/* read the current status */
	status = nrf24_getStatus();
	
	/* if sending successful (TX_DS) or max retries exceeded (MAX_RT). */
	if((status & ((1 << TX_DS)  | (1 << MAX_RT))))
	{
		return 0; /* false */
	}

	return 1; /* true */
}

void Init_INT6(void)
{
	EICRB &= ~(1 << ISC60) | (1 << ISC61);	//INT6 active when low
	EIMSK |= (1 << INT6);			//Enable INT6
	sei();					//Enable global interrupts
}

ISR(INT6_vect)
{
	cli();					//Disable global interrupt
	
	PORTB &= ~_BV(CE); 			//Stop listening
	// Pull down chip select 
	PORTB &= ~_BV(CSN); //CSN low
	_delay_us(10);
	// Send command to read RX payload 
	spi_tranceiver(R_RX_PAYLOAD);
	_delay_us(10);
	// Read payload 
	Payload_RX(BS_payload_RX, BS_payload_RX, PAYLOAD_LEN);
	_delay_us(10);
	// Pull up chip select
	PORTB |= _BV(CSN);  //CSN high
	_delay_us(10);
	// Reset status register 
	Write_byte(STATUS, (1 << RX_DR));
	mode = 0;	    //Set as TX
}

/* send and receive multiple bytes over SPI */
void Payload_RX(uint8_t *data_out, uint8_t *data_in, uint8_t len)
{
	uint8_t i;

	for(i = 0; i < len; i++)
	{
		data_in[i] = spi_tranceiver(data_out[i]);
		UART_Tx(data_in[i]);   //Send the received data to UART
	}
}

void reset(void)
{
	_delay_us(10);
	//Reset IRQ-flags in status register
    	Write_byte(STATUS, 0x70);   
	_delay_us(10);
}

int main(void)
{
	AVR_Init();
	Init_SPI();
	Init_nrf();
	UART_Init();
	Init_INT6();
	
	//0 - TX; 1 - RX
	mode = 0;
	
	//Disable Interrupt initially
	cli();

	//Endless Loop
	while(1)
	{
		if(mode == 0) //TX
		{
			//Configure as Transmitter
			nRF_TX_mode();
		
			transmit_data(BS_payload_TX);
			while(nrf24_isSending());
			reset();
		
			//Configure as Receiver
			mode = 1;		//Set as RX
			nRF_RX_mode();
			PORTB |= _BV(CE);	//Start listening again	
			sei();				
		}
	}
}

 

Regards,
Frederic Philips