NRF24L01 Bare Metal. FIFO_STATUS TX FIFO REMAINS FULL AFTER SENDING

Hey everyone. I wanted to dive deep into registers and bare metal program just for fun, and i'm having a lot of trouble confirming that my TX device actually transmits any data.
As mentioned in the description, I'm expecting the FIFO_STATUS to be 1 at bit 4 that corrosponds to TX_EMPTY. Thanks to anyone willing to point me in the right direction :slight_smile: I have tried both pulsing the CE pin and also just having it on the whole time.
Im not using auto ack. I tried to keep it as simple as can be...

Below here is the code for the TX device...

#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#define RX_PW_P4 0x15
#define RX_PW_P5 0x16
#define FIFO_STATUS 0x17
#define DYNPD 0x1C
#define FEATURE 0x1D

/* Instruction Mnemonics */
#define R_REGISTER 0x00
#define W_REGISTER 0x20
#define REGISTER_MASK 0x1F
#define ACTIVATE 0x50
#define R_RX_PL_WID 0x60
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define W_ACK_PAYLOAD 0xA8
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define NOP 0xFF
#define dummyBYTE 0x00

#include <SPI.h>

#define CE_PIN 2
#define CSN_PIN 3
uint8_t TXDATAADRESS[5];
uint8_t TXadress[] = { 0xF4, 0xD3, 0xC3, 0xB3, 0xA3 };
uint8_t TXdata[32] = "Hello World\n";

void setup() {
  pinMode(CE_PIN, OUTPUT);
  pinMode(CSN_PIN, OUTPUT);
  digitalWrite(CSN_PIN, HIGH);
  Serial.begin(9600);
  SPI.begin();

  initializechip();


  txmode(TXadress, 10);


  uint8_t status = readRegister(STATUS);
  Serial.println();
  Serial.print("Status register is: ");
  Serial.println(STATUS, HEX);
  delay(2000);
}

void loop() {
  uint8_t status = transmitdata(TXdata);
  Serial.println(status);
}


void writeRegister(uint8_t REG, uint8_t VAL) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(W_REGISTER | REG);
  SPI.transfer(VAL);
  digitalWrite(CSN_PIN, HIGH);

  uint8_t status = readRegister(REG);
  Serial.println();
  Serial.print("Status for: ");
  Serial.println(REG, HEX);

  Serial.println(status, BIN);
}

void writeRegisterMulti(uint8_t REG, uint8_t *DATA, int SIZE) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(W_REGISTER | REG);
  for (int len = 0; len < SIZE; len++) {
    SPI.transfer(DATA[len]);
  }
  digitalWrite(CSN_PIN, HIGH);
}

uint8_t readRegister(uint8_t REG) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(R_REGISTER | REG);
  uint8_t registerstatus = SPI.transfer(dummyBYTE);
  digitalWrite(CSN_PIN, HIGH);

  return registerstatus;
}

void readRegisterMulti(uint8_t REG, uint8_t *DATA, int size) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(R_REGISTER | REG);
  for (int len = 0; len < size; len++) {
    DATA[len] = SPI.transfer(dummyBYTE);
  }

  digitalWrite(CSN_PIN, HIGH);
}

void sendcmd(uint8_t cmd) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(cmd);
  digitalWrite(CSN_PIN, HIGH);
}

void initializechip() {

  digitalWrite(CSN_PIN, HIGH);


  writeRegister(CONFIG, 0);       // config later
  writeRegister(EN_AA, 0);        // no auto ack
  writeRegister(EN_RXADDR, 0);    // disable all pipes
  writeRegister(SETUP_AW, 0x03);  // 5 byte address
  writeRegister(SETUP_RETR, 0);   // no retransmisson
  writeRegister(RF_CH, 0);        // later config
  writeRegister(RF_SETUP, 0x0E);  // power 0db 2 Mbps
}

void txmode(uint8_t *Adress, uint8_t channel) {
  digitalWrite(CE_PIN, LOW);
  digitalWrite(CSN_PIN, HIGH);

  writeRegister(RF_CH, channel);  // select channel
  writeRegisterMulti(TX_ADDR, Adress, 5);

  uint8_t config = readRegister(CONFIG);

  config = config | (1 << 1);

  writeRegister(CONFIG, config);
  config = readRegister(CONFIG);


  digitalWrite(CE_PIN, HIGH);
}

uint8_t transmitdata(uint8_t *data) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(W_TX_PAYLOAD);
  for (int i = 0; i < 32; i++) {
    SPI.transfer(data[i]);
  }

  digitalWrite(CSN_PIN, HIGH);

  delayMicroseconds(15);


  uint8_t fifostatus = readRegister(FIFO_STATUS);
  Serial.println(fifostatus, BIN);
  if ((fifostatus & (1 << 4)) && (!(fifostatus & (1 << 3)))) {
    uint8_t cmdtosend = FLUSH_TX;
    sendcmd(cmdtosend);
    return 1;
  }
  return 0;
}

What you should probably be doing is checking the STATUS register for the TX_DS flag prior to checking the FIFO, or simply check the fifo for a given timeout period.

I'm pretty sure you are just not waiting for the transmission to finish. Even without an ACK, its not instant.

I also put in some code to flush the FIFOs on startup.

Try this:

#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#define RX_PW_P4 0x15
#define RX_PW_P5 0x16
#define FIFO_STATUS 0x17
#define DYNPD 0x1C
#define FEATURE 0x1D

/* Instruction Mnemonics */
#define R_REGISTER 0x00
#define W_REGISTER 0x20
#define REGISTER_MASK 0x1F
#define ACTIVATE 0x50
#define R_RX_PL_WID 0x60
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define W_ACK_PAYLOAD 0xA8
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define NOP 0xFF
#define dummyBYTE 0x00

#include <SPI.h>

#define CE_PIN 2
#define CSN_PIN 3
uint8_t TXDATAADRESS[5];
uint8_t TXadress[] = { 0xF4, 0xD3, 0xC3, 0xB3, 0xA3 };
uint8_t TXdata[32] = "Hello World\n";

void setup() {
  pinMode(CE_PIN, OUTPUT);
  pinMode(CSN_PIN, OUTPUT);
  digitalWrite(CSN_PIN, HIGH);
  Serial.begin(9600);
  while (!Serial) { delay(1); }
  SPI.begin();

  initializechip();

  uint8_t cmdtosend = FLUSH_TX;
  sendcmd(cmdtosend);
  cmdtosend = FLUSH_RX;
  sendcmd(cmdtosend);
  txmode(TXadress, 10);


  uint8_t status = readRegister(STATUS);
  Serial.println();
  Serial.print("Status register is: ");
  Serial.println(STATUS, HEX);
  delay(2000);
}

void loop() {
  uint8_t status = transmitdata(TXdata);
  Serial.println(status);
  delay(1000);
}


void writeRegister(uint8_t REG, uint8_t VAL) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(W_REGISTER | REG);
  SPI.transfer(VAL);
  digitalWrite(CSN_PIN, HIGH);

  uint8_t status = readRegister(REG);
  Serial.println();
  Serial.print("Status for: ");
  Serial.println(REG, HEX);

  Serial.println(status, BIN);
}

void writeRegisterMulti(uint8_t REG, uint8_t *DATA, int SIZE) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(W_REGISTER | REG);
  for (int len = 0; len < SIZE; len++) {
    SPI.transfer(DATA[len]);
  }
  digitalWrite(CSN_PIN, HIGH);
}

uint8_t readRegister(uint8_t REG) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(R_REGISTER | REG);
  uint8_t registerstatus = SPI.transfer(dummyBYTE);
  digitalWrite(CSN_PIN, HIGH);

  return registerstatus;
}

void readRegisterMulti(uint8_t REG, uint8_t *DATA, int size) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(R_REGISTER | REG);
  for (int len = 0; len < size; len++) {
    DATA[len] = SPI.transfer(dummyBYTE);
  }

  digitalWrite(CSN_PIN, HIGH);
}

void sendcmd(uint8_t cmd) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(cmd);
  digitalWrite(CSN_PIN, HIGH);
}

void initializechip() {

  digitalWrite(CSN_PIN, HIGH);


  writeRegister(CONFIG, 0);       // config later
  writeRegister(EN_AA, 0);        // no auto ack
  writeRegister(EN_RXADDR, 0);    // disable all pipes
  writeRegister(SETUP_AW, 0x03);  // 5 byte address
  writeRegister(SETUP_RETR, 0);   // no retransmisson
  writeRegister(RF_CH, 0);        // later config
  writeRegister(RF_SETUP, 0x0E);  // power 0db 2 Mbps
}

void txmode(uint8_t *Adress, uint8_t channel) {
  digitalWrite(CE_PIN, LOW);
  digitalWrite(CSN_PIN, HIGH);

  writeRegister(RF_CH, channel);  // select channel
  writeRegisterMulti(TX_ADDR, Adress, 5);

  uint8_t config = readRegister(CONFIG);

  config = config | (1 << 1);

  writeRegister(CONFIG, config);
  config = readRegister(CONFIG);
  Serial.print("CONFIG: ");
  Serial.println(config, HEX);

  digitalWrite(CSN_PIN, LOW);
}

uint8_t transmitdata(uint8_t *data) {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(W_TX_PAYLOAD);
  for (int i = 0; i < 32; i++) {
    SPI.transfer(data[i]);
  }

  digitalWrite(CSN_PIN, HIGH);

  digitalWrite(CE_PIN, HIGH);
  delayMicroseconds(15);
  digitalWrite(CE_PIN, LOW);

  delay(500);
  uint8_t fifostatus = readRegister(FIFO_STATUS);
  Serial.print("FIFO: ");
  Serial.println(fifostatus, BIN);
  if ((fifostatus & (1 << 4)) && (!(fifostatus & (1 << 3)))) {
    uint8_t cmdtosend = FLUSH_TX;
    sendcmd(cmdtosend);
    fifostatus = readRegister(FIFO_STATUS);
    Serial.print("FIFO2: ");
    Serial.println(fifostatus, BIN);
    return 1;
  }
  return 0;
}

Wow thanks you so much. I just woke up and tried it and it worked, the bit was set correctly. Im gonna play around with what you gave me to really understand it. Again thanks alot!. May i ask you why you also flush the RX in the setup?

Flushing the FIFOs on startup seems to be good practice in the case of any leftover packets or newly received packets.

We do it in the RF24 Library also.

Thank you very much for your time!