nRF24L01+ with Atmega8515 problem

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

Hello,

I am writing the code for the transmitter and receiver side for the nRF24L01+ transceiver. I am using two Atmega8515 as my microprocessors, one at the transmit, one at the receive side.

I seem to have two problems:

1. Both the TX and RX side do not start automatically when I turn on the power, I need to toggle the reset pin on the Atmega8515 to jumpstart the program on the chip. This only happens when the In-system programmer (ISP) is disconnected from the Atmega microprocessor. I do not know how to solve this.

2. After many tries I managed to get the transmitter working and I am able to see the waveforms on the spectrum analyzer. You will notice that I have a while(1) loop in the code which I use to run the program indefinitely. However, in practice, the loop does NOT continue forever, instead the program runs for a couple iterations then stops. This happens both on TX and RX sides, and this is preventing me from having proper communication between my transmitter and receiver. Please help!

 

TX SIDE:

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>

/*Register address defines for nRF24L01+ */
#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define RX_ADDR_P0 0x0A
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define WRITE 0xA0
#define NOP 0xFF
#define FLUSH_TX 0xE1

/*PROTOTYPES*/
void SPI_Init(void);
int SPI_ReadWrite(int);
int SPI_WriteComand(int);
void CSNlow(void);
void CSNhigh(void);
void Transmit(void);

int main(void)
{
    int testval;

    SPI_Init();

    while(1)
    {
        CSNlow();
        testval=SPI_ReadWrite(FLUSH_TX);    //flush all from TX
        CSNhigh();
        CSNlow();
        testval=SPI_ReadWrite(WRITE);        //write 0xEB to TX FIFO
        testval=SPI_ReadWrite(0xEB);
        CSNhigh();
        _delay_ms(1);
        Transmit();
        _delay_ms(1);
    }
}

    

int SPI_WriteCommand(int val)
{
    val=val+0x20;                //add the write byte
    SPDR = val;                    // Start transmission
    while(!(SPSR & (1<<SPIF)));     // Wait for transmission complete
    _delay_us(10);
    return(SPDR);
}

int SPI_ReadWrite(int val)
{
    SPDR = val;                // Start transmission
    while(!(SPSR & (1<<SPIF)));    // Wait for transmission complete
    _delay_us(10);
    return(SPDR);
}

void SPI_Init(void)
{
//    int x;
// Set MOSI,SCK, CSN(DB3) and CE(DB2) output, all others input
    DDRB =(1<<DDB5)|(1<<DDB7)|(1<<DDB3)|(1<<DDB2);
    DDRA = 0xFF;

    PORTB=PORTB|0x08;        //CSN pin high

// Enable SPI, Master, set clock rate fck/16
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
    
    CSNlow();
    SPI_WriteCommand(EN_AA);        //auto-acknowledge
    SPI_WriteCommand(0x00);
    CSNhigh();

    CSNlow();
    SPI_WriteCommand(EN_RXADDR);    //data pipe 1
    SPI_WriteCommand(0x01);
    CSNhigh();

//    SPI_WriteCommand(RF_CH);
//    SPI_WriteCommand(0x05);

//    SPI_WriteCommand(RX_ADDR_P0);
//    for(x=0;x<5;x++)
//    {
//        SPI_WriteCommand(0xEB);
//    }
//
//    SPI_WriteCommand(TX_ADDR);
//    for(x=0;x<5;x++)
//    {
//        SPI_WriteCommand(0xEB);
//    }

    CSNlow();
    SPI_WriteCommand(RX_PW_P0);
    SPI_WriteCommand(0x01);
    CSNhigh();

    CSNlow();
    SPI_WriteCommand(CONFIG);    //Transmit mode
    SPI_WriteCommand(0x76);
    CSNhigh();
    _delay_ms(2);
    
}

void CSNlow(void)
{
    _delay_us(10);
    PORTB=PORTB&0xF7; //CSN low
    _delay_us(10);
}

void CSNhigh(void)
{
    _delay_us(10);
    PORTB=PORTB|0x08; //CSN high
    _delay_us(10);
}

 

 

RX SIDE:

 

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>

/*Register address defines for nRF24L01+ */
#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define RX_ADDR_P0 0x0A
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define WRITE 0xA0
#define READ 0x61
#define NOP 0xFF

/*PROTOTYPES*/
void SPI_Init(void);
int SPI_ReadWrite(int);
int SPI_WriteReg(int);
void DisplayInit(void);
void Command(int);
void Data(int);
void CSNlow(void);
void CSNhigh(void);

int main(void)
{
    int status;
    int data;
    DDRA = 0xFF;    //Port A as output    
    DDRE = 0xFB;    //PE0, PE1 input/PE2 output (TEMP)
    DisplayInit();
    SPI_Init();

    while(1)
    {
        PORTB=PORTB|0x04;        //CE high
        _delay_ms(100);
        PORTB=PORTB&0xFB;        //CE low
        _delay_us(10);    
        CSNlow();
        status=SPI_ReadWrite(STATUS);        //read status register
        status=SPI_ReadWrite(NOP);        //dummy byte
        CSNhigh();        
        status=status&0xBF;
        if(status==0x40)
        {

            CSNlow();
            data=SPI_ReadWrite(READ);    //read RX FIFO
            data=SPI_ReadWrite(NOP);         //dummy byte
            CSNhigh();
            Data(data);                //send received byte to the display
            CSNlow();
            status=SPI_ReadWrite(STATUS);
            status=SPI_ReadWrite(0x70);        //reset the interrupts
            CSNhigh();
        }
    }
}    

int SPI_WriteReg(int val)
{
    val=val+0x20;                //add the write byte
    SPDR = val;                    /* Start transmission */
    while(!(SPSR & (1<<SPIF)));     /* Wait for transmission complete */
    _delay_us(10);
    return(val);
}

int SPI_ReadWrite(int val)
{
    SPDR = val;                /* Start transmission */
    while(!(SPSR & (1<<SPIF)));    /* Wait for transmission complete */
    _delay_us(10);
    return(val);
}

void SPI_Init(void)
{
//    int x;
/* Set MOSI,SCK, CSN(DB3) and CE(DB2) output, all others input */
    DDRB =(1<<DDB5)|(1<<DDB7)|(1<<DDB3)|(1<<DDB2);

    PORTB=PORTB|0x08;
/* Enable SPI, Master, set clock rate fck/16 */
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
    
    CSNlow();
    SPI_WriteReg(EN_AA);
    SPI_WriteReg(0x00);
    CSNhigh();

    CSNlow();
    SPI_WriteReg(EN_RXADDR);
    SPI_WriteReg(0x01);
    CSNhigh();

//    SPI_WriteReg(RF_CH);
//    SPI_WriteReg(0x05);

//    SPI_WriteReg(RX_ADDR_P0);
//    for(x=0;x<5;x++)
//    {
//        SPI_WriteReg(0xEB);
//    }

//    SPI_WriteReg(TX_ADDR);
//    for(x=0;x<5;x++)
//    {
//        SPI_WriteReg(0xEB);
//    }

    CSNlow();
    SPI_WriteReg(RX_PW_P0);
    SPI_WriteReg(0x01);
    CSNhigh();

    CSNlow();
    SPI_WriteReg(CONFIG);
    SPI_WriteReg(0x7F);            //RX mode
    CSNhigh();
    _delay_ms(2);

}

void DisplayInit(void)
{
    int dat=0;
    
    /*LCD INIT*/
    _delay_ms(20);
    
    dat=0x38;        //Function set: 8-bit/2-line
    Command(dat);
    dat=0x01;        //Clear Display
    Command(dat);
    dat=0x06;        //Entry mode set: Increment, no shift
    Command(dat);
    dat=0x0F;        //Display on, blinking cursor
    Command(dat);
}
    
void Command(int dat)
{
    int e=0;
    e=0x01;            //RS pin off, Enable ON
    PORTE=e;        
    PORTA=dat;
    e=0;            //RS off, Enable OFF (negative edge)
    PORTE=e;        
    _delay_ms(1);
}

void Data(int dat)
{    
    int e=0;
    e=0x03;            //RS pin on, Enable ON
    PORTE=e;
    PORTA=dat;
    e=0x02;            //RS pin ON, Enable OFF (negative edge trigger)
    PORTE=e;
    _delay_ms(1);
}

void CSNlow(void)
{
    _delay_us(10);
    PORTB=PORTB&0xF7; //CSN low
    _delay_us(10);
}

void CSNhigh(void)
{
    _delay_us(10);
    PORTB=PORTB|0x08; //CSN high
    _delay_us(10);
}

 

Last Edited: Fri. Oct 16, 2015 - 12:29 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've tried replacing the contents of the while(1) loop with a simple square wave output, and it work fine infinitely, but when I put the actual code that I want, it stop after a couple loops! I really don't know what's happening, can someone please help, this is really important to me!

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

UPDATE - I figured out that it was the SS pin floating, I now always keep it high and the infinite loop does fine. However, the transmitter and receiver will still not communicate. I checked the waveforms, the receiver just does not recognize anything so the RX FIFO is constantly low.

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

The obvious answer is to use the SS pin for CSN.    i.e. as God intended.

 

What are you doing with PORTE ?

 

Surely,  you have CE connected to a GPIO output

And IRQ connected to INT0 or INT1.    Or possibly just poll a GPIO input pin.

 

David.

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

I haven't read your program. Too ADD for that.

 

Are you sending the same data over and over? If your NRF24L01+ is really a SI24R1 fraudulently labeled NRF24L01+, the receiver will mistake identical packets transmitted for repeats of the same packet and discard them. To check for this, just count in one byte of the transmitted message so you're not sending the same message each time.

 

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

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

wow. there are several AVR and ARM drivers/libraries for that radio. And a common protocol stack with swappable code at the bottom for which radio to use.

http://www.airspayce.com/mikem/a...

 

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

Not to mention examples from the chip manufacturer themselves: http://www.nordicsemi.com/eng/Pr... - see the 'Downloads' tab...

 

Nordic's own Support & Community page: http://www.nordicsemi.com/eng/Su...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

The obvious answer is to use the SS pin for CSN.    i.e. as God intended.

You mean it is wrong to assign CSN to another GPIO output pin? Can you explain why is it wrong? I just put SS high perpetually right now.

 

david.prentice wrote:

What are you doing with PORTE ?

PORTE is used for controlling another device (An LCD display)

 

david.prentice wrote:

Surely,  you have CE connected to a GPIO output

And IRQ connected to INT0 or INT1.    Or possibly just poll a GPIO input pin.

CE is connected to GPIO output on PORTB (DB2), CSN is DB3.

I do not use interrupts, instead I poll the STATUS register to see if the internal RX received flag is set, then I read the data. The problem is, I do not get the data I am supposed to get at the receiver output. Once in a while the receiver outputs some weird trash value, and just keeps outputting that, but never the right data value.