No response from nrf24l01 usingatmega16.

Hi guys,

These nordic wireless chips seem to be fairly popular but I have been battling to get them talking for two days and am out of ideas.

I don’t have access to a scope until tomorrow to check the signals but I have checked the spi setup via a loopback setup and it seems to be fine. The code i’m using is essentially the http://www.tinkerer.eu/AVRLib/nRF24L01 code but I’m having no luck. I only ever get back 0xFF as the status from the device.

Main:

void main()
{

// Initialize AVR for use with mirf
mirf_init();

// Configure mirf
mirf_config();

// Test communication
mirf_CSN_lo;
status_test = spi_fast_shift(NOP);
mirf_CSN_hi;  

}

Mirf.c

// Pin definitions for chip select and chip enabled of the MiRF module


#define CSND		DDB0
#define CED         DDB1

#define DD_MISO     DDB6
#define DD_MOSI     DDB5
#define DD_SS       DDB4
#define DD_SCK      DDB7


// Defines for setting the MiRF registers for transmitting or receiving mode
#define TX_POWERUP mirf_config_register(CONFIG, mirf_CONFIG | ( (1<<PWR_UP) | (0<<PRIM_RX) ) )
#define RX_POWERUP mirf_config_register(CONFIG, mirf_CONFIG | ( (1<<PWR_UP) | (1<<PRIM_RX) ) )



// Flag which denotes transmitting mode
volatile uint8_t PTX;

void mirf_init() 
// Initializes pins ans interrupt to communicate with the MiRF module
// Should be called in the early initializing phase at startup.
{
    // Define CSN and CE as Output and set them to default
    DDRB |= ((1<<CSND)|(1<<CED));

	mirf_CE_lo;
    mirf_CSN_hi;	
	
	_delay_ms(5000);

	DDRB |= ((1<<CSND)|(1<<CED)|(1<<DD_MOSI)|(1<<DD_SS)|(1<<DD_SCK));
	//	PORTB |= (1<<PB6); //TRY PULLUP RESISTOR ON MISO
		
	//SPI SETUP
    SPCR = ((1<<SPE)|               // SPI Enable
            (0<<SPIE)|              // SPI Interupt Enable
            (0<<DORD)|              // Data Order (0:MSB first / 1:LSB first)
            (1<<MSTR)|              // Master/Slave select   
            (0<<SPR1)|(0<<SPR0)|    // SPI Clock Rate
            (0<<CPOL)|              // Clock Polarity (0:SCK low / 1:SCK hi when idle)
            (0<<CPHA));             // Clock Phase (0:leading / 1:trailing edge sampling)

	// SPSR = (1<<SPI2X);              // Double Clock Rate
}


void mirf_config() 
// Sets the important registers in the MiRF module and powers the module
// in receiving mode
{
    // Set RF channel
    mirf_config_register(RF_CH,mirf_CH);

    // Set length of incoming payload 
    mirf_config_register(RX_PW_P0, mirf_PAYLOAD);

    // Start receiver 
    PTX = 0;        // Start in receiving mode
    RX_POWERUP;     // Power up in receiving mode
    mirf_CE_hi;     // Listening for pakets
}

void mirf_set_RADDR(uint8_t * adr) 
// Sets the receiving address
{
    mirf_CE_lo;
    mirf_write_register(RX_ADDR_P0,adr,5);
    mirf_CE_hi;
}

void mirf_set_TADDR(uint8_t * adr)
// Sets the transmitting address
{
    mirf_write_register(TX_ADDR, adr,5);
}


extern uint8_t mirf_data_ready() 
// Checks if data is available for reading
{
    if (PTX) return 0;
    uint8_t status;
    // Read MiRF status 
    mirf_CSN_lo;                                // Pull down chip select
    status = spi_fast_shift(NOP);               // Read status register
    mirf_CSN_hi;                                // Pull up chip select
    return status & (1<<RX_DR);
}

extern void mirf_get_data(uint8_t * data) 
// Reads mirf_PAYLOAD bytes into data array
{
    mirf_CSN_lo;                               // Pull down chip select
    spi_fast_shift( R_RX_PAYLOAD );            // Send cmd to read rx payload
    spi_transfer_sync(data,data,mirf_PAYLOAD); // Read payload
    mirf_CSN_hi;                               // Pull up chip select
    mirf_config_register(STATUS,(1<<RX_DR));   // Reset status register
}

void mirf_config_register(uint8_t reg, uint8_t value)
// Clocks only one byte into the given MiRF register
{
    mirf_CSN_lo;;
    spi_fast_shift(W_REGISTER | (REGISTER_MASK & reg));
    spi_fast_shift(value);
    mirf_CSN_hi;
}

void mirf_read_register(uint8_t reg, uint8_t * value, uint8_t len)
// Reads an array of bytes from the given start position in the MiRF registers.
{
    mirf_CSN_lo;
    spi_fast_shift(R_REGISTER | (REGISTER_MASK & reg));
    spi_transfer_sync(value,value,len);
    mirf_CSN_hi;
}

void mirf_write_register(uint8_t reg, uint8_t * value, uint8_t len) 
// Writes an array of bytes into inte the MiRF registers.
{
    mirf_CSN_lo;
    spi_fast_shift(W_REGISTER | (REGISTER_MASK & reg));
    spi_transmit_sync(value,len);
    mirf_CSN_hi;
}


void mirf_send(uint8_t * value, uint8_t len) 
// Sends a data package to the default address. Be sure to send the correct
// amount of bytes as configured as payload on the receiver.
{
   // while (PTX) {}                  // HANDLED MANUALLY Wait until last paket is send

    mirf_CE_lo;

    PTX = 1;                        // Set to transmitter mode
    TX_POWERUP;                     // Power up
    
    mirf_CSN_lo;                    // Pull down chip select
    spi_fast_shift( FLUSH_TX );     // Write cmd to flush tx fifo
    mirf_CSN_hi;                    // Pull up chip select
    
    mirf_CSN_lo;                    // Pull down chip select
    spi_fast_shift( W_TX_PAYLOAD ); // Write cmd to write payload
    spi_transmit_sync(value,len);   // Write payload
    mirf_CSN_hi;                    // Pull up chip select
    
    mirf_CE_hi;                     // Start transmission
}

SPI:

void spi_transfer_sync (uint8_t * dataout, uint8_t * datain, uint8_t len)
// Shift full array through target device
{
       uint8_t i;      
       for (i = 0; i < len; i++) {
             SPDR = dataout[i];
             while((SPSR & (1<<SPIF))==0);
             datain[i] = SPDR;
       }
}

void spi_transmit_sync (uint8_t * dataout, uint8_t len)
// Shift full array to target device without receiving any byte
{
       uint8_t i;      
       for (i = 0; i < len; i++) {
             SPDR = dataout[i];
             while((SPSR & (1<<SPIF))==0);
       }
}

uint8_t spi_fast_shift (uint8_t data)
// Clocks only one byte to target device and returns the received one
{
    SPDR = data;
    while(!(SPSR & (1<<SPIF)));
    return SPDR;
}

Anybody got any ideas of something I can try? I’ve been at it for two days and nothing left I can think of trying.

Here’s a simple C18 program that tests SPI between an PIC18F4520 and the nRF24L01. You should be able to adapt it for the AVR quite easily.

/*
** test.c
** SPI test program for PIC18F4520 and nRF24L01 or nRF24L01+
** Checks SPI comms between PIC and wireless chip
** 
** RA0	LED (output)
** RA1	PB (input)
*/

#include <p18f4520.h>
#include <spi.h>

//function prototypes
unsigned char spi_Send_Read(unsigned char);

// Defines
#define SPI_SCK		LATCbits.LATC3		// Clock pin, PORTC pin 3 
#define SPI_SO		LATCbits.LATC5		// Serial output pin, PORTC pin 5 
#define SPI_SI		PORTCbits.RC4		// Serial input pin, PORTC pin 4 
#define SPI_CSN		LATCbits.LATC2		// CSN output pin, PORTC pin 2
#define SPI_CE		LATCbits.LATC1		// CE output pin, PORTC pin 1
#define SPI_IRQ		PORTBbits.RB0		// IRQ input pin, PORTB pin 0
#define SPI_SCALE	4              		// postscaling of signal 
#define LED			LATAbits.LATA0
#define PB			PORTAbits.RA1


// Macros
#define nop() _asm nop _endasm

void main(void)
{
	unsigned char status = 0;
	unsigned char data[5];
	int i;

	// run internal oscillator at 8 MHz
	OSCCON = OSCCON | 0x70;
	while (OSCCONbits.IOFS == 0)
		;

	OpenSPI(SPI_FOSC_16, MODE_00, SMPMID); //open SPI1
	PORTA = 0x00;
	ADCON1 = 0x0F;		// set up PORTA to be digital I/Os
	TRISA = 0x02;		// PORTA<7.2,0> outputs PORTA<1> input
	TRISCbits.TRISC3 = 0;	// SDO output
	TRISCbits.TRISC5 = 0;   // SCK output
	TRISCbits.TRISC2 = 0;	// CSN output
	TRISCbits.TRISC1 = 0;	// CE output
	SPI_CSN = 1;		// CSN high
	SPI_SCK = 0;		// SCK low
	SPI_CE	= 0;		// CE low
	nop();

	//write TX_ADDRESS register
	SPI_CSN = 0;			//CSN low
	spi_Send_Read(0x30);
	spi_Send_Read(0x11);
	spi_Send_Read(0x22);
	spi_Send_Read(0x33);
	spi_Send_Read(0x44);
	spi_Send_Read(0x55);
	SPI_CSN = 1;			//CSN high


	//read TX_ADDRESS register
	//Check that values are correct using the MPLAB debugger
	SPI_CSN = 0;			//CSN low
	status = spi_Send_Read(0x10);
	data[0] = spi_Send_Read(0x00);	// 0x11
	data[1] = spi_Send_Read(0x00);	// 0x22
	data[2] = spi_Send_Read(0x00);	// 0x33
	data[3] = spi_Send_Read(0x00);	// 0x44
	data[4] = spi_Send_Read(0x00);	// 0x55
	SPI_CSN = 1;			//CSN high

	// test PB and LED
	while(1)
	{
		if (!PB)
			LED = 1;
		else
			LED = 0;
	}
}


unsigned char spi_Send_Read(unsigned char byte)
{
	SSPBUF = byte;	
	while(!DataRdySPI())
		;	
	return SSPBUF;
}

Leon

I don’t see anything obvious wrong, but here are some things I found helpful in a similar situation:

  • Make sure SPI loopback is working reliably without the radio first. Tie MOSI to MISO and you should see every byte you send come back in SPDR.

  • Double check the SPI clock rate you are setting to make sure that given your F_CPU you aren’t sending faster than the nRF is able to receive.

  • It looks like CEN and SS are on different pins, and you’re using CEN as an SS. I had a problem once in which SS was a floating input and this caused every hardware SPI transaction to abort and clear the MSTR bit. I see you have made SS an output so this may not apply, but I am wondering if your issue is in this neighborhood. To check this issue, verify MSTR is still set after your SPI send is complete. If not, the transaction was aborted.

  • Poking around with an LED may help you see enough of what’s going on to make progress without the scope…

Good luck, let us know what you find.

Best,

-br

Cheers guys,

Loopback does seem to be working reliably so im thinking that takes care of the possible problem with the SS. I might try taking the SPI clock rate back this afternoon and will also get the scope on to it to see if there is anything glaringly wrong. Otherwise i’m done to trying a backup mirf board - longshot.

I remember having a similar problem. I think it was solved by reading the status register directly i.e:

mirf_read_register(STATUS,&byte,1);

Though I can’t remember exactly. Also another thing to try is adding a small delay after mirf_config. The data sheet shows it is in a ‘Transition State’ for 1.5 ms after PWR_UP.

It’s worth noting these chips play very nicely with Arduino:

http://www.arduino.cc/playground/Interf … e/Nrf24L01

It’s worth noting these chips play very nicely with Arduino:

http://www.arduino.cc/playground/Interf … e/Nrf24L01

on that note, check out this thread: http://www.arduino.cc/cgi-bin/yabb2/YaB … 1289089043

I am having problems, as can be seen. any and all help would be appreciated! if and when I get my code up and running, I will post it.

-mike