Skip to content

Commit e410157

Browse files
authored
Merge pull request #2865 from anangl/hal_fixes
TARGET_NRF5: A few corrections in HAL implementation.
2 parents d642b9f + 691969c commit e410157

File tree

5 files changed

+122
-6
lines changed

5 files changed

+122
-6
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2006-2013 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include "sleep_api.h"
17+
#include "cmsis.h"
18+
#include "mbed_interface.h"
19+
#include "softdevice_handler.h"
20+
#include "nrf_soc.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
25+
26+
void sleep(void)
27+
{
28+
// ensure debug is disconnected if semihost is enabled....
29+
30+
// Trigger an event when an interrupt is pending. This allows to wake up
31+
// the processor from disabled interrupts.
32+
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
33+
34+
// If the SoftDevice is enabled, its API must be used to go to sleep.
35+
if (softdevice_handler_isEnabled()) {
36+
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
37+
sd_app_evt_wait();
38+
} else {
39+
NRF_POWER->TASKS_LOWPWR = 1;
40+
41+
// Note: it is not sufficient to just use WFE here, since the internal
42+
// event register may be already set from an event that occurred in the
43+
// past (like an SVC call to the SoftDevice) and in such case WFE will
44+
// just clear the register and continue execution.
45+
// Therefore, the strategy here is to first clear the event register
46+
// by using SEV/WFE pair, and then execute WFE again, unless there is
47+
// a pending interrupt.
48+
49+
// Set an event and wake up whatsoever, this will clear the event
50+
// register from all previous events set (SVC call included)
51+
__SEV();
52+
__WFE();
53+
54+
// Test if there is an interrupt pending (mask reserved regions)
55+
if (SCB->ICSR & (SCB_ICSR_RESERVED_BITS_MASK)) {
56+
// Ok, there is an interrut pending, no need to go to sleep
57+
return;
58+
} else {
59+
// next event will wakeup the CPU
60+
// If an interrupt occured between the test of SCB->ICSR and this
61+
// instruction, WFE will just not put the CPU to sleep
62+
__WFE();
63+
}
64+
}
65+
}
66+
67+
void deepsleep(void)
68+
{
69+
sleep();
70+
// NRF_POWER->SYSTEMOFF=1;
71+
}

targets/TARGET_NORDIC/TARGET_MCU_NRF51822/sleep.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,17 @@
1616
#include "sleep_api.h"
1717
#include "cmsis.h"
1818
#include "mbed_interface.h"
19+
#include "toolchain.h"
1920

20-
void sleep(void)
21+
MBED_WEAK void sleep(void)
2122
{
2223
// ensure debug is disconnected if semihost is enabled....
2324
NRF_POWER->TASKS_LOWPWR = 1;
2425
// wait for interrupt
2526
__WFE();
2627
}
2728

28-
void deepsleep(void)
29+
MBED_WEAK void deepsleep(void)
2930
{
3031
sleep();
3132
// NRF_POWER->SYSTEMOFF=1;

targets/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832/TARGET_NRF52_DK/PinNames.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ typedef enum {
120120
P0_28 = p28,
121121
P0_29 = p29,
122122
P0_30 = p30,
123+
P0_31 = p31,
123124

124125
LED1 = p17,
125126
LED2 = p18,

targets/TARGET_NORDIC/TARGET_NRF5/gpio_api.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
#include "nrf_drv_gpiote.h"
2121

2222

23-
#define GPIO_PIN_COUNT 31
23+
#if defined(TARGET_MCU_NRF51822)
24+
#define GPIO_PIN_COUNT 31
25+
#else
26+
#define GPIO_PIN_COUNT 32
27+
#endif
2428

2529
typedef struct {
2630
bool used_as_gpio : 1;

targets/TARGET_NORDIC/TARGET_NRF5/sleep.c

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,52 @@
1616
#include "sleep_api.h"
1717
#include "cmsis.h"
1818
#include "mbed_interface.h"
19+
#include "softdevice_handler.h"
20+
#include "nrf_soc.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
1925

2026
void sleep(void)
2127
{
2228
// ensure debug is disconnected if semihost is enabled....
23-
NRF_POWER->TASKS_LOWPWR = 1;
24-
// wait for interrupt
25-
__WFE();
29+
30+
// Trigger an event when an interrupt is pending. This allows to wake up
31+
// the processor from disabled interrupts.
32+
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
33+
34+
// If the SoftDevice is enabled, its API must be used to go to sleep.
35+
if (softdevice_handler_isEnabled()) {
36+
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
37+
sd_app_evt_wait();
38+
} else {
39+
NRF_POWER->TASKS_LOWPWR = 1;
40+
41+
// Note: it is not sufficient to just use WFE here, since the internal
42+
// event register may be already set from an event that occurred in the
43+
// past (like an SVC call to the SoftDevice) and in such case WFE will
44+
// just clear the register and continue execution.
45+
// Therefore, the strategy here is to first clear the event register
46+
// by using SEV/WFE pair, and then execute WFE again, unless there is
47+
// a pending interrupt.
48+
49+
// Set an event and wake up whatsoever, this will clear the event
50+
// register from all previous events set (SVC call included)
51+
__SEV();
52+
__WFE();
53+
54+
// Test if there is an interrupt pending (mask reserved regions)
55+
if (SCB->ICSR & (SCB_ICSR_RESERVED_BITS_MASK)) {
56+
// Ok, there is an interrut pending, no need to go to sleep
57+
return;
58+
} else {
59+
// next event will wakeup the CPU
60+
// If an interrupt occured between the test of SCB->ICSR and this
61+
// instruction, WFE will just not put the CPU to sleep
62+
__WFE();
63+
}
64+
}
2665
}
2766

2867
void deepsleep(void)

0 commit comments

Comments
 (0)