|
16 | 16 | #include "sleep_api.h"
|
17 | 17 | #include "cmsis.h"
|
18 | 18 | #include "mbed_interface.h"
|
| 19 | +#include "nrf_soc.h" |
| 20 | +#include "nrf_sdm.h" |
| 21 | + |
| 22 | +// Mask of reserved bits of the register ICSR in the System Control Block peripheral |
| 23 | +// In this case, bits which are equal to 0 are the bits reserved in this register |
| 24 | +#define SCB_ICSR_RESERVED_BITS_MASK 0x9E43F03F |
19 | 25 |
|
20 | 26 | void sleep(void)
|
21 | 27 | {
|
22 | 28 | // ensure debug is disconnected if semihost is enabled....
|
23 | 29 | NRF_POWER->TASKS_LOWPWR = 1;
|
24 |
| - // wait for interrupt |
25 |
| - __WFE(); |
| 30 | + |
| 31 | + SCB->SCR |= SCB_SCR_SEVONPEND_Msk; /* send an event when an interrupt is pending. |
| 32 | + * This helps with the wakeup from the following app_evt_wait(). */ |
| 33 | + |
| 34 | + uint8_t sd_enabled; |
| 35 | + |
| 36 | + // look if exceptions are enabled or not, if they are, it is possible to make an SVC call |
| 37 | + // and check if the soft device is running |
| 38 | + if ((__get_PRIMASK() == 0) && (sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) && (sd_enabled == 1)) { |
| 39 | + // soft device is enabled, use the primitives from the soft device to go to sleep |
| 40 | + sd_app_evt_wait(); |
| 41 | + } else { |
| 42 | + // Note: it is not possible to just use WFE at this stage because WFE |
| 43 | + // will read the event register (not accessible) and if an event occured, |
| 44 | + // in the past, it will just clear the event register and continue execution. |
| 45 | + // SVC call like sd_softdevice_is_enabled set the event register to 1. |
| 46 | + // This means that a making an SVC call followed by WFE will never put the |
| 47 | + // CPU to sleep. |
| 48 | + // Our startegy here is to clear the event register then, if there is any |
| 49 | + // interrupt, return from here. If no interrupts are pending, just call |
| 50 | + // WFE. |
| 51 | + |
| 52 | + // Set an event and wake up whatsoever, this will clear the event |
| 53 | + // register from all previous events set (SVC call included) |
| 54 | + __SEV(); |
| 55 | + __WFE(); |
| 56 | + |
| 57 | + // Test if there is an interrupt pending (mask reserved regions) |
| 58 | + if (SCB->ICSR & (SCB_ICSR_RESERVED_BITS_MASK)) { |
| 59 | + // Ok, there is an interrut pending, no need to go to sleep |
| 60 | + return; |
| 61 | + } else { |
| 62 | + // next event will wakeup the CPU |
| 63 | + // If an interrupt occured between the test of SCB->ICSR and this |
| 64 | + // instruction, WFE will just not put the CPU to sleep |
| 65 | + __WFE(); |
| 66 | + } |
| 67 | + } |
26 | 68 | }
|
27 | 69 |
|
28 | 70 | void deepsleep(void)
|
|
0 commit comments