I have a beginner's problem. I have 2 nRF24L01+ devices. They are communicating with each other great, and I can talk with the nRF via SPI.

The problem is I want to display, on the serial monitor, the number of retransmitted packets (ARC_CNT) and the number of lost packets (PLOS_CNT), which are both in the "observe_tx" register on the nRF.

I am using the "Getting Started" example from RF24 1.3.1, with Arduino 1.84, with a few more bits added, and it all works great apart from getting it to show PLOS_CNT & ARC_CNT! I have tried:

printf_P(PSTR("OBSERVE_TX=%02x: PLOS_CNT=%x ARC_CNT=%x\r\n")); 

But this does not give the correct result.

As you have probably guessed, I know nothing about C or C++. There must be a simple way of showing the 2 numbers?

The code I am using is:

#include <SPI.h>
#include "RF24.h"
#include <printf.h> // Required for "radio.printDetails();"

/****************** User Config ***************************/
/***      Set this radio as radio number 0 or 1         ***/
bool radioNumber = 0;

/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7, 8);

byte addresses[][6] = {"1Node", "2Node"};

// Used to control whether this node is sending or receiving
bool role = 0;

void setup() {
  //pinMode(53,OUTPUT); //may not be required after all
  printf_begin(); //required for "radio.printDetails();" to work
  Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
  // Set the PA Level low to prevent power supply related issues since this is a
  // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
  radio.setPALevel(RF24_PA_LOW); // _MIN, _LOW, _HIGH, _MAX
  radio.setDataRate(RF24_250KBPS); //250KBPS, _1MBPS, _2MBPS  Lowest rate gives longest range.
  radio.setChannel(108); // 0 - 124 (2.4GHz - 2.524GHz) Usually above 100 best. USA 70 - 80 best.
  radio.setRetries(15, 15); // set retry delay and no of retries. delay between retries, 0=250uS, 15 = 4000uS
  radio.setCRCLength(RF24_CRC_16);  // 8 or 16 bit crc
  // Open a writing and reading pipe on each radio, with opposite addresses
  if (radioNumber) {
    radio.openReadingPipe(1, addresses[0]);
  } else {
    radio.openReadingPipe(1, addresses[1]);
  // Start the radio listening for data

void loop() {
  /****************** Ping Out Role ***************************/
  if (role == 1)  {
    radio.stopListening(); // First, stop listening so we can talk.
    Serial.println(F("Now sending"));
    unsigned long start_time = micros();
    // Take the time, and send it.  This will block until complete
    if (!radio.write( &start_time, sizeof(unsigned long) )) {
    radio.startListening(); // Now, continue listening
    unsigned long started_waiting_at = micros(); // Set up a timeout period, get the current microseconds
    boolean timeout = false; // Set up a variable to indicate if a response was received or not
    while (!radio.available()) {
      // While nothing is received
      if (micros() - started_waiting_at > 200000 ) {
        // If waited longer than 200ms, indicate timeout and exit while loop
        timeout = true;

    if (timeout) {
      // Describe the results
      Serial.println(F("Failed, response timed out."));
      printf_P(PSTR("OBSERVE_TX=%02x: PLOS_CNT=%x ARC_CNT=%x\r\n"));
    } else {
      unsigned long got_time;
      // Grab the response, compare, and send to debugging spew
      radio.read( &got_time, sizeof(unsigned long) );
      unsigned long end_time = micros();
      // Spew it
      Serial.print(F("Sent "));
      Serial.print(F(", Got response "));
      Serial.print(F(", Round-trip delay "));
      Serial.print(end_time - start_time);
      Serial.println(F(" microseconds"));
    // Try again 1s later

  /****************** Pong Back Role ***************************/
  if (role == 0) {
    unsigned long got_time;
    if (radio.available()) {
      // Variable for the received timestamp
      while (radio.available()) {
        // While there is data ready
        radio.read(&got_time, sizeof(unsigned long));
        // Get the payload
      // First, stop listening so we can talk
      radio.write(&got_time, sizeof(unsigned long));
      // Send the final one back.
      // Now, resume listening so we catch the next packets.
      Serial.print(F("Sent response "));

  /****************** Change Roles via Serial Commands ***************************/

  if (Serial.available()) {
    char c = toupper(Serial.read());
    if (c == 'T' && role == 0) {
      Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
      role = 1; // Become the primary transmitter (ping out)
    } else if (c == 'R' && role == 1) {
      Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
      role = 0; // Become the primary receiver (pong back)
} // Loop

1 Answer 1

printf_P(PSTR("OBSERVE_TX=%02x: PLOS_CNT=%x ARC_CNT=%x\r\n")); 

This should be

printf_P(PSTR("OBSERVE_TX=%02x: PLOS_CNT=%x ARC_CNT=%x\r\n"), 

Where the two variables contain the values.

  • first OBSERVE_TX= means the text that is literally printed
  • %02X is the format of the variable which is printed
  • OBSERVE_TX is the variable name

The variable names should be in the same order as the formatting (%'s).

However, in your case the above will not result in the values you want. The items above (OBSERVE_PLOS_CNT and ARC_CNT) are offsets from an addres. What you want is to print the content of that address. Since I don't have an Arduino IDE nearby, you should find yourself the address, and use *(address + OBSERVE_PLOS_CNT). This will use the address, adds OBSERVE_PLOS_CNT, and * means it will show the content of that new address.

Btw, I'm not sure about the exact use of printf_P and PSTR.

  • 1
    When i try that, it gives me "observe_tx was not declared in this scope" and the same error for "plos_cnt", and does not compile. So if i declare a variable called "observe_tx", and substitute "4" for "plos_cnt" ("#define PLOS_CNT 4", in nRF24l01.h), then it prints in the serial monitor : "OBSERVE_TX=401: PLOS_CNT=0 ARC_CNT=7304, with ARC jumping 7304, 1ec4, ca88, 7650, 2218, cddc, 79a8.... each time the loop executes. I expect PLOS, ARC to initially both be 0, and for ARC to increment Thanks for your explanation of the additional details - good for my understanding.
    – Mr Chips
    Apr 11, 2018 at 15:14
  • The "observe_tx" register is address 0x08. "PLOS_CNT" is defined as 0x04, and ARC_CNT as 0x00. Bits 0-3 of 0x08 register are counting retries, bits 4-7 of 0x08 are counting packet loss. So, if i substitiute address 0x08, and the other numbers: printf_P(PSTR("OBSERVE_TX=%02x: PLOS_CNT=%x ARC_CNT=%x\r\n"), *(0x08), 0x04, 0x00); it prints OBSERVE_TX=8: PLOS_CNT=4 ARC_CNT=0. These are the numbers, rather than the any value of an address. Have i understood it right ?
    – Mr Chips
    Apr 11, 2018 at 16:52
  • True, if you put * in front of it, it shows the content, HOWEVER, I'm sure OBSERVE_TX is not the address itself, it is an offset from a base address, but to be honest, I don't know which one. There must be another #define that contains the base address, so you should use *(base_address + OBSERVE_TX), and similar for others. Apr 11, 2018 at 19:06
  • many thanks for your help. I have it working now.
    – Mr Chips
    Apr 12, 2018 at 15:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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