This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

NRF24L01+ SPI Communication with NRF52 DK

Hi, I'm trying to use SPI to control an RF module to send audio data from one microcontroller to another. The parts and software I'm working with are:

I need one NRF52 to control an NRF24L01+ to act as a transmitter sending data and the other acting as a receiver; these roles will never need to change and this will be the only NRF24L01+ pair for this project. I've edited the NRF24 libraries from Github to use Nordic's functions instead of Arduino's to avoid having to include everything Arduino (changed delay(#) to nrf_delay_ms(#), using nrf SPI driver instead of Arduino's SPI, etc.). I am having problems getting the two devices to actually communicate with one another despite getting them to (seemingly) work on their own individually. The transmitter says it is transmitting, the receiver says it is waiting to receive, so I believe the initialization to be incorrect on one or both ends. For now all I care about is getting any data across and I can handle getting it up to speed and sending audio files later.
Strange things I've noticed thus far:

  • SPI with the NRF24L01+ only seems to work at 1Mbps
  • In order to not get garbage over SPI I needed to send a NOP first during initialization and then proceed as normal
  • Datasheet mentions the contents of the STATUS register are sent out whenever SS goes from high to low, seemed to be fixed by condensing as many SPI commands into single transmissions instead of using separate enable/ disable commands for the GPIO
  • Writing over the default address in either receive data pipes 0 or 1 did not seem to change their values, they output the same before and after (0xE7E7E7E7E7 for data pipe 0 and 0xC2C2C2C2C2 for data pipe 1).

Here's the print outs I'm getting from my receiver and transmitter test code so far (the data is all in hex with SPI's MOSI in the left column and MISO in the right column):

RECEIVER
Init
FF	00
Config setup
20	07
02	0E
RF setup
26	07
08	00
Set channel to #1
25	0E
01	00
Set Rx Mode
20	0E
03	00
27	0E
70	00
read address pipe line 1
0B	0E
FF	C2
FF	C2
FF	C2
FF	C2
FF	C2
	address: C2 C2 C2 C2 C2
writing address hopefully
2B	0E
41	07
6C	07
6D	07
61	07
6F	07
read address again
0B	07
41	C2
6C	C2
6D	C2
61	C2
6F	C2
	address: C2 C2 C2 C2 C2
read payload if available
17	0E
FF	11
read payload if available
17	0E
FF	11
 
TRANSMITTER
Init
FF	00
Config setup
20	07
02	2E
RF setup
26	07
08	00
Set channel to #1
25	2E
01	00
Flush TX
E1	2E
Write payload
A0	07
4E	2E
6F	00
72	00
64	00
69	00
63	00
00	00
Set to TX mode
20	07
02	00
27	2E
70	00
Flush TX
E1	2E
Write payload
A0	07
4E	2E
6F	00
72	00
64	00
69	00
63	00
00	00
Set to TX mode
20	07
02	00
27	2E
70	00
Flush TX
E1	2E

I'm initializing SPI with:

static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);

/* ... */

void spi_init()
{
    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;

    spi_config.ss_pin   = SPI_SS_PIN;
    spi_config.miso_pin = SPI_MISO_PIN;
    spi_config.mosi_pin = SPI_MOSI_PIN;
    spi_config.sck_pin  = SPI_SCK_PIN;
    spi_config.frequency = NRF_DRV_SPI_FREQ_1M;

    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
}

Are there any libraries or methods I could be using to more easily interface with the NRF24L01+'s than reusing an Arduino library? I'm going to continue experimenting with SPI commands, timings, ordering, and initialization to see if I can get it working on my own for the time being unless I can find something better.

  • Hi Andy

    Thanks for your detailed report. 

    If the UART is running at 115200 baud it could definitely be slower than the radio, which can easily send 500kbps or more. Especially if you add some additional data to each printf statement. 
    You could try to toggle a pin on each received packet instead, or printing just the first byte, to at least see if you are getting the packets you expect without overloading the UART. 

    The false packets you see when using a short address and no CRC is to be expected. When the receiver is enabled you will always be receiving something, whether it is random noise from the receiver chain or a valid packet. Since you are decoding 1 or 2 million samples per second it doesn't take that long for the random noise to match your address, when the chance of accidentally hitting a 3 byte address is about 1 over 16 million. 

    With CRC enabled you would discard most of these packets because of CRC failure, but without it they are all accepted. 

    It will happen with a 4 or 5 byte address as well, but a lot less frequently. 

    When CRC/ACK's make the reception stop it usually means there is some configuration inconsistency between the TX and RX. 

    The channel, bitrate and address is clearly good since you can receive without CRC, but there could be some problem with the payload length configuration. If you don't enable dynamic payload length it is important to configure the payload length in the receiver equal to the length of the payload uploaded on the TX side. 
    Can you double check this?

    Also, can you let me know where you got the module, and what is printed on the nRF24L01+ device?

    There are a lot of counterfeit nRF24L01+ devices out there, and they are not guaranteed to work in the same way. 

    Best regards
    Torbjørn

  • Hi Ovrebekk,

    Sorry for taking so long to make a response, things have not been going very well with these modules and the project is falling behind because of my inability to get these working. 

    void NRF24L_init(void)
    {
        NRF24L.spi_instance = spi;
        NRF24L.pin_ce = CE_PIN;
        NRF24L.pin_irq = IRQ_PIN;
        NRF24L.pin_csn = CSN_PIN;
    
        hal_nrf_nrf52_init(&NRF24L, &NRF24L_config, l01_irq);
    
        nrf_delay_us(5000);
        hal_nrf_set_power_mode(HAL_NRF_PWR_DOWN);
        nrf_delay_us(5000);
        hal_nrf_set_power_mode(HAL_NRF_PWR_UP);
        nrf_delay_us(5000);
    
        hal_nrf_set_rf_channel(RF_CHANNEL); //RF_CHANNEL = 120, default = 2
        hal_nrf_clear_irq_flags_get_status();
        hal_nrf_flush_rx();
        hal_nrf_flush_tx();
        
        nrf_delay_ms(10);
    
        hal_nrf_set_address(HAL_NRF_PIPE0, rf_address);//rf_address[] = "TS E"
        hal_nrf_set_address(HAL_NRF_TX, rf_address);
        hal_nrf_set_address_width(HAL_NRF_AW_5BYTES); //default is 5
    
        hal_nrf_write_reg(EN_AA, 0x00); //auto enables off
        hal_nrf_set_crc_mode(HAL_NRF_CRC_OFF);  //no crc
        nrf_delay_ms(10);
    
        hal_nrf_set_rx_payload_width(PIPE_LINE, PAYLOAD_WIDTH); //Sets payload width
        hal_nrf_set_auto_retr(0, 0);  //disable auto retransmits
    
        #ifdef TRANSMITTER
            hal_nrf_set_irq_mode(HAL_NRF_MAX_RT, false);  //no interrupt for max retransmits
            hal_nrf_set_irq_mode(HAL_NRF_TX_DS, true);    //interrupt for data transmitted
            hal_nrf_set_irq_mode(HAL_NRF_RX_DR, false);   //no interrupt for data received
            hal_nrf_set_operation_mode(HAL_NRF_PTX);  //Set as transmitter
        #endif
        
        #ifdef RECEIVER
            hal_nrf_set_irq_mode(HAL_NRF_MAX_RT, false);  //no interrupt for max retransmits
            hal_nrf_set_irq_mode(HAL_NRF_TX_DS, false);   //no interrupt for data transmitted
            hal_nrf_set_irq_mode(HAL_NRF_RX_DR, true);    //interrupt for data received
            hal_nrf_set_operation_mode(HAL_NRF_PRX);  //Set as receiver
            hal_nrf_chip_enable(CE_ENABLE); //Enter Rx mode
        #endif
        nrf_delay_ms(10);
    }

    Both ends have had the same payload width of 32B, the max allowable size for packets with the NRF24L01+. I've had packets send (without auto acknowledge and CRC) that have been the correct size and data, though sometimes they go missing because there's no acknowledges and sometimes a few bits are flipped because there's no CRC. I have reached the point in this project where not having ACKs or CRC is no longer acceptable and am working towards getting both enabled and functioning correctly.

    Another Devzone thread sounds very alarming to me however because the identification on the ICs of every NRF24L01+ module we have match the code user "orbitcoms" posted here: https://devzone.nordicsemi.com/f/nordic-q-a/36537/nrf24l01-tx-and-rx-address-issue . Our devices' markings read: 

              NRF M

              24L01+

              1808 AH

    We purchased our modules from MakerFocus on Amazon at this link: https://www.amazon.com/MakerFocus-nRF24L01P-Wireless-Transmission-Interface/dp/B07GRMJJY5 

  • Hi Andy

    In that case you should try to find some alternative modules to test as soon as possible, to figure out if the issue is with the module or the code. 

    Ideally something like this one from Sparkfun, which is known to use authentic Nordic devices. 

    If we verify that it is the module that is the issue you can obviously work to find cheaper options that will still work properly. 

    Best regards
    Torbjørn

  • The modules are DEFINITELY functional!

    It took too long for me to get these working so instead we switched to using ESB with the NRF52832s themselves for our communication. With the ESB examples and some effort we made a system that was transmitting decent quality audio over the air in real time successfully. Doing so involved delving into ESB more and getting a better understanding of how everything worked and how the details I overlooked previously. In my original attempts I misunderstood how the pipelines worked and tried manually using pipe 0 incorrectly. I needed to use two pipes to get it working correctly since pipe 0 is used behind the scenes with auto acknowledgements by ESB.
    My current testing setup is using an NRF52832 connected through SPI to one of the NRF24L01+ modules as a receiver catching data sent by an NRF52832 runnning a modified "esb_ptx" example from the proprietary RF examples in the SDK. In the ESB initialization for the transmitter there are configuration settings for both ESB and ESB legacy, the latter of which is intended for use with NRF24L01s. I ensured the settings were the same on both ends to make this work correctly:

    • pipe 0 addresses matching (tested default and custom values)
    • pipe 1 addresses matching (tested default and custom values)
    • tx pipe addresses matching (tested default and custom values)
    • payload lengths matching (32B, no dynamic payload length)
    • RF channels matching (tested default channel and a few others)
    • address widths matching (5B)
    • data rates matching (2Mbps)
    • Auto ACKs enabled
    • CRC lengths matching (2B)

    Thankfully large chunks of the code I had previously been testing with when auto ACKs and CRC were disabled worked correctly with this setup, and I was able to transmit meaningful data consistently. I have only done testing for a short period on this setup so I will keep working on this to make sure that everything is working correctly with these modules as well as replace the transmitting side with another module controlled through SPI. I'm genuinely upset I did not catch this detail earlier since it was such a simple fix to get things working properly but I only understood why after delving deeper into ESB separately.

    I'll keep working with my setup and make an update if I find anything else bizarre since I have somewhere to really start from now!

  • Bizarrity has occurred when trying to set up two different Dev Kits with their own NRF24L01+'s, but since the immediate problem of getting them to work at all has been figured out I'll open a new ticket for this.

Related