Skip to content

Commit b0b7b3c

Browse files
authored
Merge pull request #2849 from pan-/fix_nordic_critical_section
Fix nordic critical section entry and exit
2 parents 1047ab4 + dcf0331 commit b0b7b3c

File tree

3 files changed

+140
-2
lines changed

3 files changed

+140
-2
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2015-2016, ARM Limited, All Rights Reserved
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
* not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include <stdint.h> // uint32_t, UINT32_MAX
19+
#include <assert.h> // uint32_t, UINT32_MAX
20+
#include "cmsis.h"
21+
#include "nrf_soc.h"
22+
#include "nrf_sdm.h"
23+
24+
static union {
25+
uint32_t _PRIMASK_state;
26+
uint8_t _sd_state;
27+
} _state = { 0 } ;
28+
static volatile uint32_t _entry_count = 0;
29+
static bool _use_softdevice_routine = false;
30+
31+
void core_util_critical_section_enter()
32+
{
33+
// if a critical section has already been entered, just update the counter
34+
if (_entry_count) {
35+
++_entry_count;
36+
return;
37+
}
38+
39+
// in this path, a critical section has never been entered
40+
uint32_t primask = __get_PRIMASK();
41+
42+
// if interrupts are enabled, try to use the soft device
43+
uint8_t sd_enabled;
44+
if ((primask == 0) && (sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) && sd_enabled == 1) {
45+
// if the soft device can be use, use it
46+
sd_nvic_critical_region_enter(&_state._sd_state);
47+
_use_softdevice_routine = true;
48+
} else {
49+
// if interrupts where enabled, disable them
50+
if(primask == 0) {
51+
__disable_irq();
52+
}
53+
54+
// store the PRIMASK state, it will be restored at the end of the critical section
55+
_state._PRIMASK_state = primask;
56+
_use_softdevice_routine = false;
57+
}
58+
59+
assert(_entry_count == 0); // entry count should always be equal to 0 at this point
60+
++_entry_count;
61+
}
62+
63+
void core_util_critical_section_exit()
64+
{
65+
assert(_entry_count > 0);
66+
--_entry_count;
67+
68+
// If their is other segments which have entered the critical section, just leave
69+
if (_entry_count) {
70+
return;
71+
}
72+
73+
// This is the last segment of the critical section, state should be restored as before entering
74+
// the critical section
75+
if (_use_softdevice_routine) {
76+
sd_nvic_critical_region_exit(_state._sd_state);
77+
} else {
78+
__set_PRIMASK(_state._PRIMASK_state);
79+
}
80+
}

hal/common/mbed_critical.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "cmsis.h"
2121
#include "mbed_assert.h"
22+
#include "toolchain.h"
2223

2324
#define EXCLUSIVE_ACCESS (!defined (__CORTEX_M0) && !defined (__CORTEX_M0PLUS))
2425

@@ -34,7 +35,7 @@ bool core_util_are_interrupts_enabled(void)
3435
#endif
3536
}
3637

37-
void core_util_critical_section_enter(void)
38+
MBED_WEAK void core_util_critical_section_enter(void)
3839
{
3940
bool interrupts_disabled = !core_util_are_interrupts_enabled();
4041
__disable_irq();
@@ -59,7 +60,7 @@ void core_util_critical_section_enter(void)
5960
interrupt_enable_counter++;
6061
}
6162

62-
void core_util_critical_section_exit(void)
63+
MBED_WEAK void core_util_critical_section_exit(void)
6364
{
6465
/* If critical_section_enter has not previously been called, do nothing */
6566
if (interrupt_enable_counter) {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2015-2016, ARM Limited, All Rights Reserved
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
* not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include <stdint.h> // uint32_t, UINT32_MAX
19+
#include <assert.h> // uint32_t, UINT32_MAX
20+
#include "cmsis.h"
21+
#include "nrf_soc.h"
22+
#include "nrf_sdm.h"
23+
#include "nrf_nvic.h"
24+
25+
static uint8_t _sd_state = 0;
26+
static volatile uint32_t _entry_count = 0;
27+
28+
void core_util_critical_section_enter()
29+
{
30+
// if a critical section has already been entered, just update the counter
31+
if (_entry_count) {
32+
++_entry_count;
33+
return;
34+
}
35+
36+
// in this path, a critical section has never been entered
37+
// routine of SD V11 work even if the softdevice is not active
38+
sd_nvic_critical_region_enter(&_sd_state);
39+
40+
assert(_entry_count == 0); // entry count should always be equal to 0 at this point
41+
++_entry_count;
42+
}
43+
44+
void core_util_critical_section_exit()
45+
{
46+
assert(_entry_count > 0);
47+
--_entry_count;
48+
49+
// If their is other segments which have entered the critical section, just leave
50+
if (_entry_count) {
51+
return;
52+
}
53+
54+
// This is the last segment of the critical section, state should be restored as before entering
55+
// the critical section
56+
sd_nvic_critical_region_exit(_sd_state);
57+
}

0 commit comments

Comments
 (0)