Hello, this is a continuation from a different question I previously had answered: https://devzone.nordicsemi.com/f/nordic-q-a/40452/nrf24l01-spi-communication-with-nrf52-dk
I am using two NRF52 Dev Kits and two NRF24L01+ modules to try and communicate wirelessly without needing to use the NRF52832's radio as I would like to leave open the option of also using a soft device and BLE in the future when working with these products. I am using the Nordic SDK 14.2.0 and have started from some base code written by a Nordic engineer from the previous question: link . My end goal is to have two NRF52832s writing to/ reading from NRF24L01+ modules to communicate with each other custom 5B addresses with auto acknowledgement, 2B CRC, 2Mbps data rate, and ideally also dynamic payload length but for now static is fine as well.
I can read and write from the modules over SPI seemingly successfully: I have compared against the datasheet and everything is set as expected. All the functions from the example set up given to me appear to work correctly as I can set any specific register to whatever values I need it to be easily in my NRF24L_init. I have taken out most of the settings I plan on using in the future (RF channels, data rates, custom addresses, etc.) and have left the init mostly empty to leave the modules on as default the settings as I can get them since I keep reading that they should be pretty good to go from just powering up. Here are the settings for my two units set in their init functions:
//PRX #define PAYLOAD_WIDTH 32 //1-32B #define SPI_INSTANCE 0 //enabled in config & using EASY DMA, 6 IRQ priority, 8MHz static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); //SPI instance l01_instance_t NRF24L; l01_config_t NRF24L_config = L01_MODULE_CONFIG(SPI_INSTANCE, CE_PIN, CSN_PIN, SPI_SCK_PIN, SPI_MOSI_PIN, SPI_MISO_PIN, IRQ_PIN); void NRF24L_init(void) { NRF24L.spi_instance = spi; NRF24L.pin_ce = CE_PIN; NRF24L.pin_irq = IRQ_PIN; //GPIOTE 6 IRQ priority NRF24L.pin_csn = CSN_PIN; hal_nrf_nrf52_init(&NRF24L, &NRF24L_config, NRF24L_irq_handler); //Hardware prepared nrf_delay_ms(100); //delay 100ms for coming online after power loss hal_nrf_set_power_mode(HAL_NRF_PWR_DOWN); //power down internals, entering power down mode nrf_delay_us(1500); //wait 1.5ms to settle hal_nrf_set_power_mode(HAL_NRF_PWR_UP); //power up internals, entering standby mode I nrf_delay_us(1500); //wait 1.5ms to ensure in standby mode I hal_nrf_clear_irq_flags_get_status(); //clear all IRQ flags in case any are set hal_nrf_flush_rx(); //empty out everything in RX FIFO in case they contain data hal_nrf_flush_tx(); //empty out everything in TX FIFO in case they contain data for(uint8_t i = 0; i < 6; i++){ hal_nrf_set_rx_payload_width(i, PAYLOAD_WIDTH); //sets payload witdh for all rx pipes (0-5) } hal_nrf_set_operation_mode(HAL_NRF_PRX); //Set as receiver hal_nrf_chip_enable(CE_ENABLE); //Enter Rx mode nrf_delay_ms(10); }
//PTX #define PAYLOAD_WIDTH 32 //1-32B #define SPI_INSTANCE 0 //enabled in config & using EASY DMA, 6 IRQ priority, 8MHz static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); //SPI instance l01_instance_t NRF24L; l01_config_t NRF24L_config = L01_MODULE_CONFIG(SPI_INSTANCE, CE_PIN, CSN_PIN, SPI_SCK_PIN, SPI_MOSI_PIN, SPI_MISO_PIN, IRQ_PIN); void NRF24L_init(void) { NRF24L.spi_instance = spi; NRF24L.pin_ce = CE_PIN; NRF24L.pin_irq = IRQ_PIN; //GPIOTE 6 IRQ priority NRF24L.pin_csn = CSN_PIN; hal_nrf_nrf52_init(&NRF24L, &NRF24L_config, NRF24L_irq_handler); //Hardware prepared nrf_delay_ms(100); //delay 100ms for coming online after power loss hal_nrf_set_power_mode(HAL_NRF_PWR_DOWN); //power down internals, entering power down mode nrf_delay_us(1500); //wait 1.5ms to settle hal_nrf_set_power_mode(HAL_NRF_PWR_UP); //power up internals, entering standby mode I nrf_delay_us(1500); //wait 1.5ms to ensure in standby mode I hal_nrf_clear_irq_flags_get_status(); //clear all IRQ flags in case any are set hal_nrf_flush_rx(); //empty out everything in RX FIFO in case they contain data hal_nrf_flush_tx(); //empty out everything in TX FIFO in case they contain data for(uint8_t i = 0; i < 6; i++){ hal_nrf_set_rx_payload_width(i, PAYLOAD_WIDTH); //sets payload witdh for all rx pipes (0-5) } hal_nrf_set_operation_mode(HAL_NRF_PTX); //Set as receiver nrf_delay_ms(10); }
My previous setup with this works when I replace the transmitter NRF24L01+ module with an NRF52 Dev Kit running a slightly modified ESB Tx example from the proprietary RF folder, including custom addresses, address widths, payload widths, RF channels, data rates, transmitting powers, 2B CRC, auto ACKs, basically everything EXCEPT dynamic payload lengths, which was breaking it for some reason.
I've been experiencing some anomalies when leaving the transmitter and receiver both running for several minutes where in the PTX will detect a successful transmission (TX data sent IRQ read from status register in the interrupt handler) in a sea of failures to transmit (max retransmits hit without an acknowledge). When debugging the receiver the PRX will trigger a data received interrupt properly (RX data received IRQ) and most of the data is correct, but in seemingly random spots the values will change randomly. I could not find any rhyme or reason to the change; I tried repeatedly sending a 32B array with value 0 in the first index incrementing up to 31 in the final index as constants and additionally incrementing index 1 every time. I have checked on the transmitter side and the data being sent is as expected:
Packet No. | 0 | 1 | 2 | 3 | ... | 31 0 | 0 | 1 | 2 | 3 | ... | 31 1 | 0 | 2 | 2 | 3 | ... | 31 2 | 0 | 3 | 2 | 3 | ... | 31 etc.
I've tried changing settings one at a time with this setup and thus far I've found is RF channels need to be the same for this to occur (obvious) and enabling dynamic payload length or disabling auto acknowledges break it. The only significant change I noticed was when changing the CRC, but this only confused me further since my results are contradictory to what I understand about CRC.
- No CRC [ hal_nrf_set_crc_mode(HAL_NRF_CRC_OFF); ] => no successful packets are sent
- 1B CRC [ hal_nrf_set_crc_mode(HAL_NRF_CRC_8BIT); ] => periodic "successful" packets sent, one every couple of seconds
- 2B CRC [ hal_nrf_set_crc_mode(HAL_NRF_CRC_16bit); ] => rarely "successful" packets sent, one maybe every 30 seconds to a minute
At this point I'm fairly confident I do not have any errors with my wiring (SPI & IRQ seem to work correct for both reading & writing + interrupt triggers properly) or power supply since I often read that adding capacitance by the modules helps stabilize them: both modules have a 0.1uF ceramic cap & 100uF electrolytic cap nearby and there doesn't appear to be much ripple on the voltage seen on an oscilloscope. I've also tested with multiple modules to ensure that the units I had weren't damaged and even fresh ones I hadn't touched before behave in the same manner.
My understanding of how these modules works is as follows:
Set PTX's TX_ADDR address to match whatever receiving pipe is used on PRX as that is the address the PRX will transmit to for sending an ack Match the PTX's pipe 0 address to match the TX_ADDR before sending a packet, this will be scanned after transmitting for any incoming ack If no ack is received after a set delay reattempt this process for the set number of retransmit attempts until either receive an ack or hit the max limit Generate an interrupt appropriate for whether data was sent proper or not on PTX & generate a data received interrupt on PRX when a non-repeat packet is received
All the documentation, threads, and articles I've read on this seem to be pretty clear on how things must be set up (though it's unfortunate a lot of Arduino related stuff refer to "reading pipes" & "writing pipes" when most nothing else I found does) and I believe that I am correctly setting things up, especially since I am able to use an NRF24L01+ as a receiver when using my NRF52 Dev Kit running ESB as the transmitter. The settings for everything should be basically identical on both the PTX and PRX modules except for the PRIM_RX bit in the configuration register (Reg 0x00) as that controls whether it is acting as a PTX or PRX. To send data, use the W_TX_PAYLOAD SPI command then send the data bytes over SPI continuously to write a packet into the TX FIFO and then pulse the CE pin high for at least 10us to begin transmitting following the flow chart from page 33. For receiving, set the device as a PRX & set the CE pin high to enter receiving mode where it will continuously check the air for incoming packets following the flow chart from page 35.
If I have something basic wrong in here, PLEASE let me know. We have quite a few of these modules on hand at the moment and we would like to use these in various projects but just can't get the darn things to work!