FPU flag interrupt raised and not cleared on standard division

I have an issue on 52833 board, SDK 16.0.0, SD s113 v7.1.0
I am using Hard FPU : arm_fp_abi="Hard"   arm_fpu_type="FPv4-SP-D16"

I have a computation that runs for a few seconds on main loop, and that sometimes does a float computation.
After it returns from the main loop, every call of nrf_pwr_mgmt_run, directly goes through, due to the FPU interrupt not being cleared.
So power consumption is very high as it never sleeps.

This is similar to https://devzone.nordicsemi.com/f/nordic-q-a/12433/fpu-divide-by-0-and-high-current-consumption, but I am not dividing by 0.

I reproduce with something as minimal as :

while (count++ < 5000) {
    nrf_delay_ms(4);
    watchdog_feed();
    if (count % 30 == 0) {
        uint8_t percent = (float) count / 5000 * 100;
    }
}

Replacing the float computation by a integer computation solves the issue.

Clearing the interrupt flag manually before nrf_pwr_mgmt_run alspo solves the issue :

__set_FPSCR(__get_FPSCR()  & ~(FPU_EXCEPTION_MASK));
(void) __get_FPSCR();
NVIC_ClearPendingIRQ(FPU_IRQn);

nrf_pwr_mgmt_run();


What do you think happens ? What should I do ?

Parents
  • The reason why that happens is that the FPU interrupt is not enabled in NVIC(using NVIC_EnableIRQ) but yet it is configured to generate interrupt. Which means that the fired interrupt ends up as a pending bit in the NVIC register. The pending bit never gets cleared automatically since the ISR is never run (since we never enabled it). Softdevice won't sleep as long as there are any pending interrupt. In short

    1) FPU operation triggers an interrupt setting the pending bit in NVIC which is never cleared automatically.
    2) softdevice will never enter sleep mode as long as there any application interrupt pending to be serviced.

    This causes the CPU to be active all the time keeping your HFCLK active, hence the high power consumption.

    To come out of it,

    1) you manually clear the pending bit of the interrupt (like what you did in your code snippet or
    2) you enable the FPU interrupt in NVIC (using NVIC_ENABLE_IRQ) and implement the FPU_IRQ handler to clear the pending bit automatically when the FPU_ISR is run.

  • This is puzzling.

    Is this an expected behaviour ? I would expect the SD to clear it automatically if I didn't implement the handler

    Why is there an interrupt at all ? The computation goes through correctly.

    Are every project on 52833 doing float computation expected to implement the FPU_IRQ handler or clearing the interrupt bit manually ? I don't see it much in the examples.

Reply Children
  • The softdevice never enables application specific interrupts and it never clear the same. It only forwards the ISR handling to application ISR (by fetching it from application vector table), but for the forwarding to happen, the interrupt must be enabled both in the peripheral and also in the NVIC.

    Why is there an interrupt at all ? The computation goes through correctly.

    You can look into the contents of __get_FPSCR and see which bit is set to know why it generated the interrupt at all. FPU is a peripheral and seems like your usage is causing it to generate interrupt. And this interrupt only ends up in the pending bit of NVIC since its ISR never gets called since your application never enabled the interrupt in NVIC (NVIC_EnableIRQ). It is application responsibility to enable application specific interrupts. The softdevice documentation never says anywhere that it enables all application interrupts for all peripherals.

    Are every project on 52833 doing float computation expected to implement the FPU_IRQ handler or clearing the interrupt bit manually ? I don't see it much in the examples.

    You need to just enable the interrupt, there is a default WEAK handler for every peripheral that can clear the pending bit once run. Yes, you need to do this for every application that uses hardware float operation. If you use a software float library, then you do not have to do it.

Related