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

Calling app_sched_event_put inside interrupt

Hi, I'm debugging a small app that is using the LPCOMP to trigger an interrupt when the BLE device is turned off. We have a capacitor to maintain alive the nRF for a while after the power is turned off (the idea is to let the nRF store some data in flash before die).

This is the code I use to configure and use the LPCOMP:

void LPCOMP_init(void) {
/* Enable interrupt on LPCOMP CROSS event */		
NRF_LPCOMP->INTENSET = LPCOMP_INTENSET_DOWN_Msk;
NVIC_EnableIRQ(LPCOMP_IRQn);

//  5 : 5V,  ref. 1/8 VDD
// 12 : 12V, ref. 3/8 VDD
// 24 : 24V, ref. 6/8 VDD

/* Configure LPCOMP */
if (power == 5) 
	NRF_LPCOMP->REFSEL = (LPCOMP_REFSEL_REFSEL_SupplyOneEighthPrescaling << LPCOMP_REFSEL_REFSEL_Pos);
else if (power == 12)
	NRF_LPCOMP->REFSEL = (LPCOMP_REFSEL_REFSEL_SupplyThreeEighthsPrescaling << LPCOMP_REFSEL_REFSEL_Pos);
else
	NRF_LPCOMP->REFSEL = (LPCOMP_REFSEL_REFSEL_SupplySixEighthsPrescaling << LPCOMP_REFSEL_REFSEL_Pos);

/* Configure LPCOMP - set reference input source to AIN2 */
NRF_LPCOMP->PSEL |= (LPCOMP_PSEL_PSEL_AnalogInput2 << LPCOMP_PSEL_PSEL_Pos);

/* Enable and start the low power comparator */
NRF_LPCOMP->ENABLE = LPCOMP_ENABLE_ENABLE_Enabled;	
NRF_LPCOMP->TASKS_START = 1;
}

/* Interrupt handler for LPCOMP */
void LPCOMP_COMP_IRQHandler(void)
{
uint32_t err_code;

// Clear event
NRF_LPCOMP->EVENTS_DOWN = 0;
// Stop LPCOMP
NRF_LPCOMP->TASKS_STOP = 1;
NRF_LPCOMP->ENABLE = LPCOMP_ENABLE_ENABLE_Disabled;

// Debug
nrf_gpio_pin_set(GPIO_PIN);

// Append store task in scheduler
err_code = app_sched_event_put(NULL, 0, config_store);
APP_ERROR_CHECK(err_code);

// Debug
nrf_gpio_pin_clear(GPIO_PIN);
}

void config_store(void *p_data, uint16_t p_size)
{
// Stop Advertising
sd_ble_gap_adv_stop();

// Store current configuration to flash
ps_config_store(&m_config);
}


int main(void)
{

...

// Enter main loop.
for (;;) {
    app_sched_execute();
	sd_app_evt_wait();
}
}

The problem I'm facing with this configuration is that when I call the app_sched_event_put() the code hangs and stops working. Looking inside at the app_sched_event_put() I see that there are two calls to CRITICAL_REGION_ENTER() and CRITICAL_REGION_EXIT(), I tried to comment out those calls and now the code works as expected. So my question is, why the CRITICAL_REGION_ENTER/EXIT macros are causing this problem?

The software is compiled with -DSOFTDEVICE_PRESENT and SoftDevice is enabled and inited.

Parents
  • I doubt the code hangs and stops working - I expect it goes to the hardfault handler, which a debugger would tell you.

    If that's so, most likely because your interrupt handler is running at HIGH priority and the critical region macros call a softdevice function and you can't call softdevice functions from APP_HIGH priority interrupt handlers, only from LOW or main thread context.

  • Hi, I think the problem is in the macro. To debug my code I put a

    uint32_t pri = current_int_priority_get();
    printf("pri = %u\r\n",(unsigned int)pri);
    

    and I've found that the interrupt priority value is 0 (APP_IRQ_PRIORITY_HIGHEST). The macro executes sd_nvic_critical_region_enter() if (CURRENT_INT_PRI != APP_IRQ_PRIORITY_HIGH), but the interrupt priority is APP_IRQ_PRIORITY_HIGHEST and the macro calls sd_nvic_critical_region_enter() causing the hardfault. I think that the macro should check if (CURRENT_INT_PRI == APP_IRQ_PRIORITY_LOW) instead of (CURRENT_INT_PRI != APP_IRQ_PRIORITY_HIGH).

Reply
  • Hi, I think the problem is in the macro. To debug my code I put a

    uint32_t pri = current_int_priority_get();
    printf("pri = %u\r\n",(unsigned int)pri);
    

    and I've found that the interrupt priority value is 0 (APP_IRQ_PRIORITY_HIGHEST). The macro executes sd_nvic_critical_region_enter() if (CURRENT_INT_PRI != APP_IRQ_PRIORITY_HIGH), but the interrupt priority is APP_IRQ_PRIORITY_HIGHEST and the macro calls sd_nvic_critical_region_enter() causing the hardfault. I think that the macro should check if (CURRENT_INT_PRI == APP_IRQ_PRIORITY_LOW) instead of (CURRENT_INT_PRI != APP_IRQ_PRIORITY_HIGH).

Children
No Data
Related