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

Inverted Radio Notification

I have observed that the Radio Notification from ble_radio_notification.c becomes inverted sometimes. I saw this post about the same problem:

devzone.nordicsemi.com/.../

In that post the inverted value was caused by a long-running high-prio interrupt, but I don't have that. I have a CRITICAL_REGION_ENTER / CRITICAL_REGION_EXIT region that takes about 4ms, but that shouldn't mask the radio notification interrupt?

This is my init code, which is called directly after Softdevice enable:

uint32_t err_code = ble_radio_notification_init(APP_IRQ_PRIORITY_HIGH,
                                                NRF_RADIO_NOTIFICATION_DISTANCE_5500US,
                                                radio_cb);
APP_ERROR_CHECK(err_code);

Right now we have a workaround where we busy-wait and check if the radio is marked as on for more than 10ms, and invert the value in that case, but it would be good to have a better solution.

I have read the Radio Notification tutorial at devzone.nordicsemi.com/.../ but didn't find any solutions there.

  • CRITICAL_REGION_ENTER will disable application interrupts including the radio notification interrupt, so this is probably the problem. You can still have one pending interrupt. If you are in a critical region and two (or a multiple of two) radio notification interrupts triggers, then the radio notification will be inverted.

    Update 2016.09.16:

    You can make your own critical region enter that only disables low priority interrupts. Below is code that will do this on 51. The SWI1 interrupt is added to the SD interrupts. All other interrupts than SD interrupts and SWI1 interrupts will be disabled when calling sd_nvic_critical_region_enter_app_low. Add more interrupts to the __NRF_NVIC_APP_HIGH_IRQS_0 group if they are not to be disabled. Note that this code is not thoroughly tested so there may be issues (for example when mixing the original sd_nvic_critical_region_enter and this).

    /**@brief Interrupts used by app_high. */
    #define __NRF_NVIC_APP_HIGH_IRQS_0 ((uint32_t)( \
        (1U << (uint32_t)SWI1_IRQn) \
    ))
    
    /**@brief Interrupts available for app_low. */
    #define __NRF_NVIC_APP_LOW_IRQS_0 ( ~(__NRF_NVIC_SD_IRQS_0 | __NRF_NVIC_APP_HIGH_IRQS_0) )
    
    static inline uint32_t sd_nvic_critical_region_enter_app_low(uint8_t * p_is_nested_critical_region)
    {
      int was_masked = __sd_nvic_irq_disable();
      if (!nrf_nvic_state.__cr_flag)
      {
        nrf_nvic_state.__cr_flag = 1;
        nrf_nvic_state.__irq_masks[0] = ( NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0 );
        NVIC->ICER[0] = __NRF_NVIC_APP_LOW_IRQS_0;
        *p_is_nested_critical_region = 0;
      }
      else
      {
        *p_is_nested_critical_region = 1;
      }
      if (!was_masked)
      {
        __sd_nvic_irq_enable();
      }
      return NRF_SUCCESS;
    }
    
    static inline uint32_t sd_nvic_critical_region_exit_app_low(uint8_t is_nested_critical_region)
    {
      if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0))
      {
        int was_masked = __sd_nvic_irq_disable();
        NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0];
        nrf_nvic_state.__cr_flag = 0;
        if (!was_masked)
        {
          __sd_nvic_irq_enable();
        }
      }
    
      return NRF_SUCCESS;
    }
    
  • Thanks for the info. I thought that CRITICAL_REGION_ENTER only disabled APP_IRQ_PRIORITY_LOW. Is there a way to only disable APP_IRQ_PRIORITY_LOW? Or is it safe to set ble_radio_notification to use IRQ priority 0 - or is that also disabled by CRITICAL_REGION_ENTER? (I think I tried to use priority 0, but still got inverted values, but I can try that again)

  • You should never use priority 0 in your code as this is reserved for the SoftDevice. I just updated the answer with a possible solution to not disable the radio notification interrupt when entering critical section. Also edited the answer to be more correct (can have one pending interrupt while in critical section).

Related