NRF24L01 and AVR - Does not transmit / Receive

Discussion about wireless devices

NRF24L01 and AVR - Does not transmit / Receive

Postby rrupad » Thu Sep 25, 2014 10:15 am

I have been trying to get these NRFs to work for quite a while now. I tried mirf, nrf24 Master (arduino), Davide Geroni's code (ported/modified to my setting) and could not get it to work. Then I came across a piece of code that is RAW - uses Hex notations of registers and their values - decreases readability - but it looked simpler than most of the code that I have seen. I read the tutorial of Brennen (succinctly written) and got to figure out the NRFs - Thanks a million, Brennen for your great work.

Scene:
I am trying to send 4 bytes of data from one AVR board (Atmega 8 - AT8) to another AVR board (Atmega328p - AT328). Both the boards are running at 16 MHz. AT8 board is the transmitter and AT328 is the receiver. The boards are wired to nRF on prototyping boards with jumpers and hookup wires.

The transmitter side register setting:
Code: Select all
--------------- Transmitter ----------------
Reg : 0x00    Val : 0x08 ---> Config register set to 0x08 (Enable CRC, No Power Up) ** Tried other recommended setting 0x38**
Reg : 0x01    Val : 0x00 ---> Auto ack register set to 0x00 (disable auto ack for all pipes)
Reg : 0x02    Val : 0x01 ---> Enable receive pipe reg set to 0x01 (Pipe 0 enabled)
Reg : 0x03    Val : 0x03 ---> Address width set to 0x03  - 5 bytes
Reg : 0x04    Val : 0x00 ---> Retries setup set to 0x00
Reg : 0x05    Val : 0x02 ---> RF Channel set to 2
Reg : 0x06    Val : 0x07 ---> RF power Setup, set to 0x07 (1 MBPS, Max Power)
Reg : 0x11    Val : 0x04---> Set TX Payload size, set to 4 bytes

Tramsmit address : JJJJJ ---> Transmit address set to 4A-4A-4A-4A-4A
Reg : 0x00    Val : 0x0A ---> Config register set to 0x0A (0000-1010 - To power up the chip) ** And consequently to the note with (**) above, to 0x3A**
--------------------------------------------------

Reg : 0x07    Val : 0x0f
Reg : 0x07    Val : 0x0e --->   [Space available in TX buffer]
TX - Status : 1110
Reg : 0x07    Val : 0x0e --->   [Space available in TX buffer]
TX - Status : 1110
Reg : 0x07    Val : 0x0f --->   [TX buffer-Full]
TX - Status : 1111
Reg : 0x07    Val : 0x0f
TX - Status : 1111
Reg : 0x07    Val : 0x0f
.
.
.
the status reads 1111 (f) continuously - TX_DS bit does not get set


I have read through the postings at DIY embedded but still does not seem to get a handle on how to set this up to make it work. In some of the postings, I saw a suggestion from Brennen that - Only when TX_DS bit gets set, it indicates that a transmission happened - we need to check the receive side. From the above output, TX-DS is not getting set - and I am unable to figure out why :( :( :(

The transmitter code
Code: Select all

/*
 * NRF24L_TX.c
 *
 * Created: 23-Sep-14 8:09:51 AM
 *  Author: Ravi Upadhyaya
 */


/*
 * NRF24L_RX.c
 *
 * Created: 22-Sep-14 5:37:45 PM
 *  Author: Ravi Upadhyaya
 */

#ifndef F_CPU
#define F_CPU      16000000L
#endif

#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>

#include "spi.h"
#include "nrf.h"
#include "serial.h"

#define USDELAY      50

void writeRegister(uint8_t ui8Reg, uint8_t ui8Val)
{
   CSN_LO;
   readWriteSPI(0x20+ui8Reg);
   readWriteSPI(ui8Val);
   CSN_HI;
}

uint8_t readRegister(uint8_t ui8Reg)
{
   uint8_t      ui8Val;
   char achBuffer[9];
   
   CSN_LO;
   readWriteSPI(ui8Reg);
   ui8Val = readWriteSPI(0xFF);
   CSN_HI;

   itoa(ui8Reg, achBuffer, 16);
   writeStringSerial("Reg : "); writeStringSerial(achBuffer);
   itoa(ui8Val, achBuffer, 16);
   writeStringSerial("    Val : "); writeStringSerial(achBuffer); writeStringSerial("\r\n");

   return ui8Val;
}


void configureTX()
{
   uint8_t i, data[5], ui8Val;

   CE_LO;
   
   writeRegister(0x00, 0x08);      // Write Config Register  (0x00), CRC Enabled, Power off, PTX enabled (0x38)
   readRegister(0x00);            // Read Config Register;

   // Shouldn't have to do this, but it wont TX of you don't
   writeRegister(0x01, 0x00);      // Write auto acknowledge RX register - disable auto ack on all channels
   readRegister(0x01);
   
   writeRegister(0x02, 0x01);      // Enable Receive pipe 0
   readRegister(0x02);

   writeRegister(0x03, 0x03);      // Write Addr width to a 5 byte address (0x03 = 5 bytes)
   readRegister(0x03);

   writeRegister(0x04, 0x00);      // Write retries register, disable auto retries
   readRegister(0x04);

   writeRegister(0x05, 0x02);      // Write RF Channel Red - set it to channel 2
   readRegister(0x05);
      
   writeRegister(0x06, 0x07);      // Write RF Data rate register - set it to 1 MBPS
   readRegister(0x06);
   
   writeRegister(0x11, 0x04);      // Write payload width register - set it to 4 bytes
   readRegister(0x11);

//==================================================================================   
   CSN_LO;
   readWriteSPI(0x30);            // Set transmitter address (0x10)
   for(i=0; i<5; i++)
      readWriteSPI(0x4A);         // Receiver Address : 0x4A4A4A4A4A
   CSN_HI;
   _delay_us(USDELAY);

   CSN_LO;
   readWriteSPI(0x10);
   for(i=0;i<5;i++)
      data[i] = readWriteSPI(0xff);
   CSN_HI;
   
   writeStringSerial("\r\nTramsmit address : ");
   for(i=0;i<5;i++)
      writeSerial(data[i]);      // Should print JJJJJ
   writeStringSerial("\r\n");
   _delay_us(USDELAY);
//==================================================================================

   writeRegister(0x00, 0x0A);      // Power up the chip and TX      (0x3A)
   readRegister(0x00);
   
   _delay_us(150);
}


int main(void)
{
   uint8_t ui8Status;
   char buffer[10];
   initSerial();
   writeStringSerial("--------------- Transmitter ----------------\r\n");
   initSPI();
   configureTX();
   writeStringSerial("--------------------------------------------------\r\n\r\n");

   writeRegister(0x07, 0x7E);   // Write status register, clear of all the interrupts
   readRegister(0x07);
      
   //the data sheet says that this is supposed to come up 0 after PWR, but that doesn't
   CSN_LO;
   readWriteSPI(0xE1);         // Clear TX_FIFO register
   CSN_HI;
   _delay_us(USDELAY);

    while(1)                  // Recieve data
    {      
      // 4 byte PAYLOAD
      CSN_LO;
      readWriteSPI(0xA0);         // Set TX Payload Register
      readWriteSPI(0x41);
      readWriteSPI(0x42);
      readWriteSPI(0x43);
      readWriteSPI(0x44);
      CSN_HI;
      _delay_us(USDELAY);
      // Pulse CE to start transmission
      CE_HI;
      _delay_us(15);
      CE_LO;

      _delay_us(USDELAY);
   
      ui8Status = readRegister(0x07);
      itoa(ui8Status, buffer, 2);
      writeStringSerial("TX - Status : "); writeStringSerial(buffer); writeStringSerial("\r\n");
      
      writeRegister(0x07, 0x7E);         // Reset the TX_DS interrupts
      
   _delay_us(150);
    }
}


Similarly the Reciver output (At328 Board)

Code: Select all
 ------- RECEIVER ----------------------------
Reg : 0x00     Val : 0x09 ---> Config register set to 0x08 (Enable CRC, No Power Up, PRX)
Reg : 0x01     Val : 0x00 ---> Auto ack register set to 0x00 (disable auto ack for all pipes)
Reg : 0x02     Val : 0x01 ---> Enable receive pipe reg set to 0x01 (Pipe 0 enabled)
Reg : 0x03     Val : 0x03 ---> Address width set to 0x03  - 5 bytes
Reg : 0x05     Val : 0x02 ---> RF Channel set to 2
Reg : 0x06     Val : 0x07 ---> RF power Setup, set to 0x07 (1 MBPS, Max Power)
Reg : 0x11     Val : 0x04 ---> Set RX Payload size, set to 4 bytes

Receiver address : JJJJJ ---> Receiver address set to 4A-4A-4A-4A-4A

Reg : 0x00     Val : 0x0b---> Config register set to 0x0A (0000-1011 - To power up the chip)
----------------------------------------------------------------
Reg : 0x07     Val : 0x0e ---> RX-FIFO Empty
RX - Status : 1110

Reg : 0x07     Val : 0x0e
RX - Status : 1110

Reg : 0x07     Val : 0x0e
RX - Status : 1110

Reg : 0x07     Val : 0x0e
RX - Status : 1110
.
.
.
Continues for ever...


The receiver code (runs on a AT328)

Code: Select all
/*
 * NRF24L_RX.c
 *
 * Created: 22-Sep-14 5:37:45 PM
 *  Author: Ravi Upadhyaya
 */

#ifndef F_CPU
#define F_CPU      16000000L
#endif

#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>

#include "spi.h"
#include "nrf.h"
#include "serial.h"

#define USDELAY         50

void writeRegister(uint8_t ui8Reg, uint8_t ui8Val)
{
   CSN_LO;
   readWriteSPI(0x20+ui8Reg);
   readWriteSPI(ui8Val);
   CSN_HI;
}

uint8_t readRegister(uint8_t ui8Reg)
{
   uint8_t      ui8Val;
   char achBuffer[9];
   
   CSN_LO;
   readWriteSPI(ui8Reg);
   ui8Val = readWriteSPI(0xFF);
   CSN_HI;
   
   itoa(ui8Reg, achBuffer, 16);
   writeStringSerial("Reg : "); writeStringSerial(achBuffer);
   itoa(ui8Val, achBuffer, 16);
   writeStringSerial("     Val : "); writeStringSerial(achBuffer); writeStringSerial("\r\n");

   return ui8Val;
}

void configureRX()
{
   uint8_t i, ui8RXAddr[5];
   
   writeRegister(0x00, 0x09);      // Config register - set CRC Enabled, Power Off, PRX enabled (0x39)
   readRegister(0x00);
   
   writeRegister(0x01, 0x00);      // Write Auto Ack Register (0x01) - disable auto ack on all channels
   readRegister(0x01);

   writeRegister(0x02, 0x01);      // Write Enable receive pipe register - set Pipe-0 for reception of payload
   readRegister(0x02);

   writeRegister(0x03, 0x03);      // Write addr width register, set to 5 byte address
   readRegister(0x03);

   writeRegister(0x05, 0x02);      // Write RF channel register - set it to channel 2
   readRegister(0x05);

   writeRegister(0x06, 0x07);      // Set RF Data rate register - set it to 1 MBPS
   readRegister(0x06);

   writeRegister(0x11, 0x04);      // Write Payload width register - set payload size to 4 bytes
   readRegister(0x11);

//=========================================================================================

   CSN_LO;
   readWriteSPI(0x2A);            // Set receiver address (0x10) - For pipe 0
   for(i=0; i<5; i++)
      readWriteSPI(0x4A);         // Receiver Address : 0x4A4A4A4A4A
   CSN_HI;
   _delay_us(USDELAY);

   CSN_LO;
   readWriteSPI(0x10);            // Read Receiver address
   for(i=0;i<5;i++)
      ui8RXAddr[i] = readWriteSPI(0xff);
   CSN_HI;
   writeStringSerial("\r\nReceiver address : ");
   for(i=0; i<5; i++)
      writeSerial(ui8RXAddr[i]);      // Should print J J J J J
   writeStringSerial("\r\n");
   _delay_us(USDELAY);

//============================================================================================

   writeRegister(0x00, 0x0B);      // Write config register - Power up the chip ()x3B)
   readRegister(0x00);
   
   CE_HI;
   _delay_ms(150);
}


int main(void)
{
   uint8_t         i, ui8Status=0x00;
   char         buffer[10] = {'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'}, achStatus[10];
   
   initSerial();

   writeStringSerial("------- RECEIVER ----------------------------\r\n");
   initSPI();
   configureRX();
   writeStringSerial("----------------------------------------------------------------\r\n");
    while(1)
    {

      CSN_LO;
      
      ui8Status = readRegister(0x07);
      itoa(ui8Status, achStatus, 2);
      writeStringSerial("RX - Status : "); writeStringSerial(achStatus); writeStringSerial("\r\n");
      
      CE_HI;
      readWriteSPI(0x61);
      for(i=0; i<4; i++)
         buffer[i] = readWriteSPI(0xff);
      CE_LO;
      CSN_HI;

      writeStringSerial(buffer);
      writeStringSerial("\r\n");

      CSN_LO;
      readWriteSPI(0xE2);         //Flush RX-FIFO
      CSN_HI;
   _delay_us(USDELAY);

      writeRegister(0x07, 0x40);      // Reset interrupt

   _delay_us(USDELAY);

    }
}


I am frustrated no-end since this is not working. Appreciate any help/suggestions in fixing this issue.

Note : I have added the 0x0 to the output values manually - as you can see in the code, the 0x0 does not happen when you itoa :)

Thanks in advance,
rrupad
 
Posts: 20
Joined: Thu Sep 25, 2014 9:24 am

Re: NRF24L01 and AVR - Does not transmit / Receive

Postby brennen » Thu Sep 25, 2014 1:05 pm

So once you have the TX set up with the proper values, load a packet into the FIFO using the W_TX_PAYLOAD command (A0), but don't send it (keep the CE pin low). Then read the value of the FIFO_STATUS register (address 0x17), and check if the TX_EMPTY bit is clear (bit 4). If so, you've successfully loaded the packet. Now you can try to send it by toggling the CE pin high for at least 10 microseconds. The packet should send, and you should see the IRQ pin go low (assuming you haven't masked out any of the interrupts in the CONFIG register (address 0x00) (bits 6, 5, and 4 should all be 0). At that point, you can read the STATUS register (address 0x07) and it should either have bit 4 or bit 5 set (MAX_RT or TX_DS interrupt, respectively). That should get you transmitting.
brennen
Site Admin
 
Posts: 395
Joined: Sun Aug 17, 2008 2:15 pm

Re: NRF24L01 and AVR - Does not transmit / Receive

Postby rrupad » Thu Sep 25, 2014 1:51 pm

Thank you, Brennen. I implemented your suggestion - Held the CE pin LO and read the FIFO status register - and the results are as follows.

Code: Select all
--------------- Transmitter ----------------
Reg : 0    Val : 8
Reg : 1    Val : 0
Reg : 2    Val : 1
Reg : 3    Val : 3
Reg : 4    Val : 0
Reg : 5    Val : 2
Reg : 6    Val : 7
Reg : 11    Val : 4

Tramsmit address : JJJJJ
Reg : 0    Val : a
--------------------------------------------------

Reg : 7    Val : f
Reg : 0x17    Val : 0x01 ---> Space available in the TX FIFO buffer, TX_FIFO is not empty   
TX - FIFO-Status : 1
Reg : 0x17    Val : 0x01 ---> Space available in the TX FIFO buffer, TX-FIFO is not empty
TX - FIFO-Status : 1
Reg : 0x17    Val : 0x21 ---> TX FIFO  full bit is set
TX - FIFO-Status : 100001
Reg : 0x17    Val : 0x21
TX - FIFO-Status : 100001
Reg : 0x17    Val : 0x21
TX - FIFO-Status : 100001
Reg : 0x17    Val : 0x21
TX - FIFO-Status : 100001
.
.
.
Outputs continuously the above tx-fifo


By the way, must the nRF module be connected with shortest wires possible to the AVR microcontroller?
rrupad
 
Posts: 20
Joined: Thu Sep 25, 2014 9:24 am

Re: NRF24L01 and AVR - Does not transmit / Receive

Postby brennen » Sat Sep 27, 2014 1:19 pm

OK so if you continue with that exercise and you then try to transmit a packet, does the TX_FULL bit clear when you send a packet with the TX FIFO full? If not, you're not applying the CE pin properly. And it's always advisable to use short wires where you can, just to avoid noise. SPI isn't particularly robust against electrical noise, so it's best to keep the wires short when you can.
brennen
Site Admin
 
Posts: 395
Joined: Sun Aug 17, 2008 2:15 pm

Re: NRF24L01 and AVR - Does not transmit / Receive

Postby rrupad » Sun Sep 28, 2014 2:42 am

Thank you, Brennen. Let me implement your suggestions and get back.

Ravi Upadhyaya
rrupad
 
Posts: 20
Joined: Thu Sep 25, 2014 9:24 am

Re: NRF24L01 and AVR - Does not transmit / Receive

Postby rrupad » Mon Sep 29, 2014 2:19 pm

Shortened the wires to as short as possible - no difference in the status :(

Checked the CE pin handling - and that seems to be ok too :(

Channel 5 is the IRQ and it is constant HI - and I have not masked the interrupts in the config register - only the power-up bit is set - all the others bits are set to 0.

Thanks in advance on any input.

PS. Is there a way to attach images to the post. I would like to share a couple of logic analyzer traces...
rrupad
 
Posts: 20
Joined: Thu Sep 25, 2014 9:24 am

Re: NRF24L01 and AVR - Does not transmit / Receive

Postby brennen » Mon Sep 29, 2014 4:44 pm

Did you check the FIFO_STATUS register values after loading a packet, and then after transmitting a packet? If they don't change at both of those events, then you're doing something wrong. You should also be able to poll the STATUS register after you transmit a packet and watch for the TX_DS interrupt bit to be flagged there. That would rule out if you had masked the interrupts in the CONFIG bit.
brennen
Site Admin
 
Posts: 395
Joined: Sun Aug 17, 2008 2:15 pm

Re: NRF24L01 and AVR - Does not transmit / Receive

Postby rrupad » Tue Sep 30, 2014 3:23 am

Yes-Brennen. I have checked the FIFO_STATUS register values after loading a packet and then after transmitting the packet. It did not change at both these events. I polled the STATUS register after the packet is transmitted and the TX_DS register is not flagged. Checked the CONFIG register bits - and the interrupt masks are not enabled in the CONFIG register.

I came across a Nordic forum https://devzone.nordicsemi.com/question/13891/nrf24l01-irq-issue/ and apparently the issue was solved by a 1uF capacitor between the GND and the 3.3V pins of the NRF. I have a 10nF and a 470uF capacitor connected between the 3.3V and GND. Is that a problem??!!!

Thanks,
Ravi Upadhyaya
rrupad
 
Posts: 20
Joined: Thu Sep 25, 2014 9:24 am

Re: NRF24L01 and AVR - Does not transmit / Receive

Postby brennen » Tue Sep 30, 2014 12:05 pm

I don't think the capacitor is the problem, although you could have a weak power supply or a bad ground connection. I would say the problem is almost definitely your CE pin, though. If I were you, I would check that you're operating the CE pin properly with an oscilloscope or logic analyzer.
brennen
Site Admin
 
Posts: 395
Joined: Sun Aug 17, 2008 2:15 pm

Re: NRF24L01 and AVR - Does not transmit / Receive

Postby rrupad » Tue Sep 30, 2014 2:06 pm

In fact I tried to attach the Logic Analyzer traces to the post - I could not. The [img] tag did not work. I could conclude that the CE is fine only from the Logic Analyzer traces. Is there a way I can send them to you?

Thanks,
Ravi Upadhyaya
rrupad
 
Posts: 20
Joined: Thu Sep 25, 2014 9:24 am

Next

Return to Wireless

Who is online

Users browsing this forum: No registered users and 1 guest

cron