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

Using NRF52 Radio IRQhandler for sending and receiving data

Hello there,

I'd like to send and receive data through NRF Radio's handler. I've been able to configure the handler to receive data. Otherwise, I'm having difficulty on sending data.

Here's my current IRQHandler function:

void RADIO_IRQHandler(void) {
	nrf_gpio_pin_set(RECPIN);
	NRF_RADIO->EVENTS_END = 0U;
	NRF_RADIO->TASKS_START = 1U;
	if (NRF_RADIO->EVENTS_READY && (NRF_RADIO->INTENSET & RADIO_INTENSET_READY_Msk)) {
		NRF_RADIO->EVENTS_READY = 0;
	}

	if (NRF_RADIO->EVENTS_END && (NRF_RADIO->INTENSET & RADIO_INTENSET_END_Msk)) {
		NRF_RADIO->EVENTS_END = 0U;
	}

	if (NRF_RADIO->EVENTS_ADDRESS && (NRF_RADIO->INTENSET & RADIO_INTENSET_ADDRESS_Msk)) {
		NRF_RADIO->EVENTS_ADDRESS = 0;
	}
	NRF_RADIO->EVENTS_DISABLED = 0U;

	if (NRF_RADIO->CRCSTATUS == 1U) {
		receive_packet();
		if (targetID == MyID || targetID == ALL_NODES) {
			if (My_Role == MASTER) {
				communicator();
			} else {
				normal();
			}
		}
	}
	nrf_gpio_pin_clear(RECPIN);
}

And here's my send_packet function:

void send_packet()
{
    // send the packet:
    NRF_RADIO->EVENTS_READY = 0U;
    NRF_RADIO->TASKS_TXEN   = 1;

    while (NRF_RADIO->EVENTS_READY == 0U)
    {
        // wait
    }
    NRF_RADIO->EVENTS_END  = 0U;
    NRF_RADIO->TASKS_START = 1U;

    while (NRF_RADIO->EVENTS_END == 0U)
    {
        // wait
    }

    NRF_RADIO->EVENTS_DISABLED = 0U;
    // Disable radio
    NRF_RADIO->TASKS_DISABLE = 1U;

    while (NRF_RADIO->EVENTS_DISABLED == 0U)
    {
        // wait
    }
}

This function may lead my board to freeze somewhere

And:

void send_packet() {
	// send the radioTxBuffer:
	//	if (radioTxBuffer[1] == COLLECT_REPLY) {
	//		//printf("%d: Transmitting: %x %x %x %x\r\n", __LINE__, radioTxBuffer[0], radioTxBuffer[1], radioTxBuffer[2], radioTxBuffer[3]);
	//		copyThis(radioTxBuffer);
	//	}
	NRF_RADIO->EVENTS_DISABLED = 0;
	NRF_RADIO->TASKS_DISABLE = 1;
	while (!NRF_RADIO->EVENTS_DISABLED);		//wait for radio to be disabled

	NRF_RADIO->EVENTS_READY = 0U;
	NRF_RADIO->TASKS_TXEN	 = 1;

	while (NRF_RADIO->EVENTS_READY == 0U) {	//wait for radio to be in tx mode
		// wait
	}

	NRF_RADIO->PACKETPTR = (uint32_t)&radioTxBuffer;

	NRF_RADIO->EVENTS_END	= 0U;			// clear flag
	NRF_RADIO->TASKS_START = 1U;			// Start sending

	while (NRF_RADIO->EVENTS_END == 0U) {	// wait for radio to finish sending
		// wait
	}

	// Clear event
	NRF_RADIO->EVENTS_DISABLED = 0U;
	NRF_RADIO->EVENTS_END = 0;
	NRF_RADIO->EVENTS_READY = 0;
	// Disable radio
	//NRF_RADIO->TASKS_DISABLE = 1U;


	//	while (NRF_RADIO->EVENTS_DISABLED == 0U)
	//	{
	//		// wait
	//	}
}

This function will return normal as nothing happened, while not sending anything.

I would like some enlightenment on how to implement Radio Send and receive properly. (Proprietary radio, not BLE)

Thank you in advance

Parents
  • Hi 

    Is there any particular reason you are clearing events and activating tasks in the interrupt handler, regardless of what event triggered the interrupt?

    This seems a bit odd. 

    If the send packet function doesn't work it would be interesting to know the state of the radio when you call the function. If it is not in the disabled state then that might explain why it doesn't work as expected. 

    Knowing the rest of your radio configuration would also be helpful in order to see how the radio is set up. 

    Have you looked into the nrf_esb library in the SDK?
    It takes away a lot of the manual radio setup, making it easier to get started. 

    You can also consider third party options, like the one Craig mentioned, but then our ability to support you is a bit limited.  

    Best regards
    Torbjørn

Reply
  • Hi 

    Is there any particular reason you are clearing events and activating tasks in the interrupt handler, regardless of what event triggered the interrupt?

    This seems a bit odd. 

    If the send packet function doesn't work it would be interesting to know the state of the radio when you call the function. If it is not in the disabled state then that might explain why it doesn't work as expected. 

    Knowing the rest of your radio configuration would also be helpful in order to see how the radio is set up. 

    Have you looked into the nrf_esb library in the SDK?
    It takes away a lot of the manual radio setup, making it easier to get started. 

    You can also consider third party options, like the one Craig mentioned, but then our ability to support you is a bit limited.  

    Best regards
    Torbjørn

Children
  • Hi, Torbjørn,

    I do not have any particular reason why I am clearing events and activating tasks in the interrupt handler.

    I was not able to find any official NRF52's Radio Interrupt example; and the example included in SDK 14.2 > examples > peripheral does not seem like to be it.

    After re-checking things, I figured out that it actually worked. Otherwise, it's still not working as I expected. Using the following codes for sending and handling incoming data using interrupt will let the board to communicate only once:

    void send_packet() {
    //	nrf_gpio_pin_set(SENDPIN);
    	// send the radioTxBuffer:
    	//	if (radioTxBuffer[1] == COLLECT_REPLY) {
    	//		//printf("%d: Transmitting: %x %x %x %x\r\n", __LINE__, radioTxBuffer[0], radioTxBuffer[1], radioTxBuffer[2], radioTxBuffer[3]);
    	//		copyThis(radioTxBuffer);
    	//	}
    	NRF_RADIO->EVENTS_DISABLED = 0;
    	NRF_RADIO->TASKS_DISABLE = 1;
    	while (!NRF_RADIO->EVENTS_DISABLED);		//wait for radio to be disabled
    
    	NRF_RADIO->PACKETPTR = (uint32_t)&radioTxBuffer;
    
    	NRF_RADIO->EVENTS_READY = 0U;
    	NRF_RADIO->TASKS_TXEN	 = 1;
    
    	while (NRF_RADIO->EVENTS_READY == 0U) {	//wait for radio to be in tx mode
    		// wait
    	}
    
    	NRF_RADIO->EVENTS_END	= 0U;			// clear flag
    	NRF_RADIO->TASKS_START = 1U;			// Start sending
    
    	while (NRF_RADIO->EVENTS_END == 0U) {	// wait for radio to finish sending
    		// wait
    	}
    
    	// Clear event
    	NRF_RADIO->EVENTS_DISABLED = 0U;
    	NRF_RADIO->TASKS_DISABLE = 1U;
    //	NRF_RADIO->EVENTS_END = 0;
    //	NRF_RADIO->EVENTS_READY = 0;
    	// Disable radio
    	//NRF_RADIO->TASKS_DISABLE = 1U;
    
    
    	while (NRF_RADIO->EVENTS_DISABLED == 0U)
    	{
    		// wait
    	}
    //	nrf_gpio_pin_clear(SENDPIN);
    }

    (The code is similar with the one from post #1: I set the NRF_RADIO->PACKETPTR before TASKS_EN, as Craig suggested).

    And here is my Radio Interrupt handler:

    void RADIO_IRQHandler(void) {
    	nrf_gpio_pin_set(RECPIN);
    	
    	if(NRF_RADIO->EVENTS_READY) {
    		NRF_RADIO->EVENTS_READY = 0;
    
            // Start listening and wait for the END event
            NRF_RADIO->TASKS_START = 1;
        }
    
        if(NRF_RADIO->EVENTS_END) {
            NRF_RADIO->EVENTS_END = 0;
            if(NRF_RADIO->CRCSTATUS == 1) {
    			receive_packet();
    			if (targetID == MyID || targetID == ALL_NODES) {
    				if (My_Role == MASTER) {
    					communicator();
    				} else {
    					normal();
    				}
    			}
    		}
            // Start listening and wait for the END event
            NRF_RADIO->TASKS_START = 1;
    	}
    //	NRF_RADIO->EVENTS_END = 0U;
    //	NRF_RADIO->TASKS_START = 1U;
    //	if (NRF_RADIO->EVENTS_READY && (NRF_RADIO->INTENSET & RADIO_INTENSET_READY_Msk)) {
    //		NRF_RADIO->EVENTS_READY = 0;
    //	}
    
    //	if (NRF_RADIO->EVENTS_END && (NRF_RADIO->INTENSET & RADIO_INTENSET_END_Msk)) {
    //		NRF_RADIO->EVENTS_END = 0U;
    //	}
    
    //	if (NRF_RADIO->EVENTS_ADDRESS && (NRF_RADIO->INTENSET & RADIO_INTENSET_ADDRESS_Msk)) {
    //		NRF_RADIO->EVENTS_ADDRESS = 0;
    //	}
    //	NRF_RADIO->EVENTS_DISABLED = 0U;
    
    //	if (NRF_RADIO->CRCSTATUS == 1U) {
    //		receive_packet();
    //		if (targetID == MyID || targetID == ALL_NODES) {
    //			if (My_Role == MASTER) {
    //				communicator();
    //			} else {
    //				normal();
    //			}
    //		}
    //	}
    	nrf_gpio_pin_clear(RECPIN);
    }

    (I changed it a little bit and keep the old one down there, commented. Would you suggest me which version is better or do you have a better solution for it?)

    Also, a question that has been bothering me is that: since this code was handed over to me, I don't understand: does the proprietary Radio requires two buffer? Since I currently have "radioRxBuffer" and "radioTxBuffer" (which has been pointed to be radio's main buffer?)

    Oh right, about the radio initialization:

    void radio_init() {
    	radio_configure();
    	NRF_RADIO->PACKETPTR = (uint32_t)&radioTxBuffer;
    	//printf("%u\r\n",NRF_RADIO->PCNF1);
    	NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
    	NRF_RADIO->TASKS_RXEN = 1U;
    	NRF_RADIO->TASKS_START = 1U;
    	NVIC_ClearPendingIRQ(RADIO_IRQn);
    	NVIC_SetPriority(RADIO_IRQn, 6);
    	NVIC_EnableIRQ(RADIO_IRQn);
    }

    Thank you,

    Winz

  • Hi Winz

    My point regarding the interrupt is that it seems strange to clear the same event and fire the same task regardless of which event actually caused the interrupt?

    This means that whatever event was triggered, and whatever state the radio is actually in, you run the same code in the interrupt handler. 

    Normally you would run tasks and events depending on the current state of the radio, which is typically different when the different events occur. 

    The radio peripheral only has a single DMA access point, and technically you don't need to use more than one buffer. Still it is normal for radio protocols to use separate TX and RX buffers, and define multiple buffers for TX and RX to allow multiple packets to be stored at a time. When this is done it is necessary to change the PACKETPTR register in the radio to point to the currently active buffer. 
    If only a single buffer is used you only have to write PACKETPTR once, but you will have to change the content of the RAM buffer every time you want to send a new packet, and copy the content out every time a new packet is received, since this buffer will be overwritten for each new packet. 

    In general I would suggest upgrading to the latest SDK, unless you already have a big project which uses a lot of different SDK modules. The more SDK modules and drivers you use the more work it is to upgrade a project from one SDK version to another. 

    For the code you shared, which mainly accesses hardware registers, upgrading to a new SDK should be easier. 

    And again I would strongly suggest having a look at one of the existing protocols, such as nrf_esb. 
    This one has been tested internally by us, and externally by various customers, and should be much easier to use than to create an RF protocol from scratch. 

    Best regards
    Torbjørn

Related