1

I have recently bought a few of these chips on boards along with some "adapter boards" which supposedly regulates the 5v to propper 3.3v with the required capacitors. So power supply shouldn't be a problem although I haven't tried with a separate power supply. Ok, so I like to build my stuff from scratch to really know everything that's going on so I'm not using a library for this chip but I've read the datasheet in it's entirety and have understood all the features. At first after going through every option one of the modules was successfully sending out packets as indicated by the TX_DS interrupt but nothing was showing up on the one in receiver mode, and after lots of checking I chose to disable every feature and managed to finally get some action as the receiver interrupted each time the transmitter sent out a packet with no CRC and no ACK.

But now there's an issue, the datasheet clearly states:

The RX_DR IRQ is asserted by a new packet arrival event. The procedure for handling this interrupt should be:

1) read payload through SPI,

2) clear RX_DR IRQ,

3) read FIFO_STATUS to check if there are more payloads available in RX FIFO,

4) if there are more data in RX FIFO, repeat from step 1).

However upon getting the interrupt and reading out 33 bytes with the command, the status register reads 4E (0100 1110) saying that the interrupt was indeed RX_DR but also the pipe number bits are all on meaning an empty RX FIFO. The following 32 bytes read 0.

How can this be? Has anyone experienced something similar?

UPDATE: Tested with separate power supply on RX side, issue still stands.

Pictures: https://1drv.ms/f/s!Ag6xBMoahJ8xkOkWMG89RIAa1m71Kw

Arduino code: (feel free to correct me I'm no expert in this language :p)

Main

void setup() {
  attachInterrupt(digitalPinToInterrupt(radio.irq), interrupt, FALLING);
  Serial.begin(9600) ;
  Serial.write("\n    ----Boot----\n\nInitializing radio...\n");

  //Starts radio as PRX
  //Sets channel
  //Sets bitrate to 1Mbps
  if (radio.init()) {
    Serial.println("Radio ready.\n\n ----Boot complete----\n\n");
  } else {
    Serial.write("Couldn't initialize radio!\n\n  ----Boot failed----\n");
    return;
  }
  delay(10);
  digitalWrite(9, HIGH);
}


void loop() {
}


void interrupt() {
  Serial.write("\nINTERRUPT\n");
  digitalWrite(9, LOW);

  radio.readRegister(0x17, 2, true, BIN);
  radio.readRXpayload(true);
  radio.clearIRQ();

  digitalWrite(9, HIGH);
}

Radio class

#include "BitUtils.h"

BitUtils utils;

uint8_t* tmp = (uint8_t*)malloc(sizeof(uint8_t) * 33);
uint8_t initialPipe0[5] = {0x28, 0x18, 0xdb, 0xc2, 0x86};
uint8_t beaconAddress[5] = {0x29, 0x26, 0x13, 0x12, 0x00};

class Radio {
  public:
    uint8_t nullmsg[1] = {0x00};

    uint8_t rx_config[1] = {0b00100011}; //0x00
    uint8_t tx_config[1] = {0b00100010}; //0x00
    uint8_t aa_config[1] = {0b00000000}; //0x01
    uint8_t ch_config[1] = {0b00110100}; //0x05
    uint8_t rf_config[1] = {0b00000110}; //0x06
    uint8_t features_config[1] = {0b00000000}; //0x1D

    uint8_t clear_irq[1] = {0b01110000}; //0x07

    uint8_t clk = 13;
    uint8_t miso = 12;
    uint8_t mosi = 11;
    uint8_t slaveselect = 10;
    uint8_t chipenable = 9;
    uint8_t irq = 2;

    SPISettings spiConfig = SPISettings(2000000, MSBFIRST, SPI_MODE0);


    boolean init() {
      noInterrupts();

      pinMode(clk, OUTPUT);
      pinMode(miso, INPUT);
      pinMode(mosi, OUTPUT);
      pinMode(slaveselect, OUTPUT);
      pinMode(chipenable, OUTPUT);
      pinMode(irq, INPUT);
      digitalWrite(clk, LOW);
      digitalWrite(slaveselect, HIGH);
      digitalWrite(chipenable, LOW);
      delay(11);

      transfer(nullmsg, 1, tmp);
      if (tmp[0] != 0b00001110) {
        return false;
      }

      writeRegister(0x00, rx_config, 2); Serial.print("0x00: ");
      readRegister(0x00, 2, true, BIN);
      writeRegister(0x01, aa_config, 2); Serial.print("0x01: ");
      readRegister(0x01, 2, true, BIN);
      writeRegister(0x05, ch_config, 2); Serial.print("0x05: ");
      readRegister(0x05, 2, true, BIN);
      writeRegister(0x06, rf_config, 2); Serial.print("0x06: ");
      readRegister(0x06, 2, true, BIN);
      writeRegister(0x1D, features_config, 2); Serial.print("0x1D: ");
      readRegister(0x1D, 2, true, BIN);

      pipeAddress(initialPipe0, 0);
      pipeAddress(beaconAddress, 1);

      Serial.print("Pipe 0 address: ");
      readRegister(0x0A, 6, true, HEX);
      Serial.print("Pipe 1 address: ");
      readRegister(0x0B, 6, true, HEX);

      delay(2);
      interrupts();
      return true;
}


    //    -- Operations --

    void clearIRQ() {
      writeRegister(0x07, clear_irq, 2);
      Serial.println("Cleared IRQ");
    }

    void sendTXpayload(uint8_t data[], boolean ack) {
      uint8_t message[33] = {0b10100000};
      if (!ack) {
        message[0] = 0b10110000;
      }
      for (int i = 31; i > -1; i--) {
        message[32 - i] = data[i];
      }

      transfer(message, 33, tmp);
      pulseCE(12);
      delay(2);
    }
    void readRXpayload(boolean report) {
      uint8_t message[33] = {0b01100001};

      transfer(message, 33, tmp);
      if (report) {
        utils.prtArr(tmp, 33, HEX);
      }
    }

    void mode(char m) {
      digitalWrite(chipenable, LOW);

      if (m == 't') {
        writeRegister(0x00, tx_config, 2);
        Serial.println("Set tx mode.");
      }
      if (m == 'r') {
        writeRegister(0x00, rx_config, 2);
        Serial.println("Set rx mode.");
      }
    }

    void pipeAddress(uint8_t* address, uint8_t number) {
      uint8_t pipeNumber = 0x0A + number;
      for (int i = 4; i > -1; i--) {tmp[4 - i] = address[i];}

      if (number < 2) {
        writeRegister(pipeNumber, tmp, 6);
      }else{
        writeRegister(pipeNumber, address, 2);
      }
    }

    void sendTo(uint8_t* address) {
      for (int i = 4; i > -1; i--) {
        tmp[4 - i] = address[i];
      } 
      writeRegister(0x10, tmp, 6);
      Serial.print("TX Address: ");
      readRegister(0x10, 6, true, HEX);
    }

    void setChannel(uint8_t ch) {
      writeRegister(0b00000101, new uint8_t[1] {ch}, 2);
      Serial.write("Frequency set to: ");
      Serial.print(2400 + tmp[1], DEC);
      Serial.println("MHz");
    }


    //    -- Low operations --

    void readStatus(boolean prt) {
      transfer(nullmsg, 1, tmp);
      if (prt) {
        utils.prtArr(tmp, 2, BIN);
      }
    }
    void readRegister(uint8_t address, uint8_t amount, boolean prt, uint8_t format) {
      uint8_t message[amount] = {address};
      transfer(message, amount, tmp);

      if (prt) {
        utils.prtArr(tmp, amount, format);
      }
    }
    void writeRegister(uint8_t address, uint8_t* data, uint8_t amount) {
      uint8_t message[amount] = {(uint8_t)(0b00100000 | address)};
      for (uint8_t i = 1; i < amount; i++) {
        message[i] = data[i - 1];
      }

      transfer(message, amount, tmp);
    }
    void pulseCE(int duration) {
      digitalWrite(chipenable, HIGH);
      delayMicroseconds(duration);
      digitalWrite(chipenable, LOW);
    }


    //    -- Bidirectional SPI bus --

    void transfer(uint8_t* data, uint8_t amount, uint8_t* output) {
      SPI.beginTransaction(spiConfig);
      digitalWrite(slaveselect, LOW);
      delayMicroseconds(1);

      for (uint8_t i = 0; i < amount; i++) {
        output[i] = SPI.transfer(data[i]);
      }

      delayMicroseconds(1);
      digitalWrite(slaveselect, HIGH);
      SPI.endTransaction();
    }
};
  • Can you post the Arduino code? – MichaelT Sep 24 '18 at 0:00
  • @MichaelT edited in the code – Manuel Covas Sep 24 '18 at 0:19
1

My advice would be to strip out all of the unnecessary code to make a minimal complete example (MCVE). The nRF24L01 is not so complicated when you get to know the data registers, and unfortunately that's where a lot of people get stuck, by trying to use the libraries without reading the datasheet. However, the posted code suggests that you have done your homework. This is how I set up nRF24L01 to use IRQ (chronological order from top to bottom):

// Begin SPI 
// Register 0x0A: set receiver addresses
// Register 0x11: set payload number of bytes

// flush RX (spi transfer B11100010) and TX (spi transfer B11100001)

// attach ISR on IRQ digital input pin.

// start the main program loop

This is the ISR called:

void isr(){
// Read payload data
digitalWrite(CSN_pin, LOW);
 data_in[0] = SPI.transfer(B01100001); //read payload register
 data_in[1] = SPI.transfer(B00000000);
 data_in[2] = SPI.transfer(B00000000);
 data_in[3] = SPI.transfer(B00000000);
 // etc
digitalWrite(CSN_pin, HIGH);

// flush RX
digitalWrite(CSN_pin, LOW);
 SPI.transfer(B11100010);//flush RX
digitalWrite(CSN_pin, HIGH);

// Read status register 0x07
digitalWrite(CSN_pin, LOW);
 SPI.transfer(0x07);
 reg7 = SPI.transfer(0x00);
digitalWrite(CSN_pin, HIGH);

reg7 |= B01000000; // RX_DR set bit 6
// write back to status register
digitalWrite(CSN_pin, LOW);
 SPI.transfer(0x20+0x07);
 SPI.transfer(reg7);
digitalWrite(CSN_pin, HIGH);
}    

Edit: bit 6 of the status register is the RX_DR flag. If this is 1 (which is the case in the OP's example), then the data have not been received. Set bit 6 to clear the interrupt.

  • I thought RX_DR stood for Data Ready, and in page 30 they state: After the packet is validated, Enhanced ShockBurst™ disassembles the packet and loads the payload into the RX FIFO, and asserts the RX_DR IRQ. – Manuel Covas Oct 9 '18 at 19:45
  • You're right, but the data sheet (p59) also says RX_DR=0 is asserted when new data arrive in RX FIFO, write 1 to clear bit. This is what the code in my answer does. Remember also MASK_RX_DR=0, but that's default on startup. – MichaelT Oct 9 '18 at 21:05
  • That would be odd no? The reset values for the IRQs are 0, and I do get the interrupt when a packet is sent out by the other radio. RX_DR transitions to 1 in the status register, furthermore, upon writing 1 to clear the bit it does go back to 0. Don't know why they made it this way but at least this is what is happening with me. Main issue was asserted IRQ and rest of device stating empty FIFOs. – Manuel Covas Oct 9 '18 at 23:04
  • I just follow what the data sheet says. The (pseudo) code written above does work, I use that with my own nRF24 projects. – MichaelT Oct 10 '18 at 8:02

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.