4
4
//!
5
5
//! WARNING using `cortex_m_semihosting`'s `hprintln!` macro or `HStdout` API will corrupt `defmt`
6
6
//! log frames so don't use those APIs.
7
+ //!
8
+ //! # Critical section implementation
9
+ //!
10
+ //! This crate uses [`critical-section`](https://github.com/rust-embedded/critical-section) to ensure only one thread
11
+ //! is writing to the buffer at a time. You must import a crate that provides a `critical-section` implementation
12
+ //! suitable for the current target. See the `critical-section` README for details.
13
+ //!
14
+ //! For example, for single-core privileged-mode Cortex-M targets, you can add the following to your Cargo.toml.
15
+ //!
16
+ //! ```toml
17
+ //! [dependencies]
18
+ //! cortex-m = { version = "0.7.6", features = ["critical-section-single-core"]}
19
+ //! ```
7
20
8
21
#![ no_std]
9
22
// nightly warns about static_mut_refs, but 1.76 (our MSRV) does not know about
12
25
13
26
use core:: sync:: atomic:: { AtomicBool , Ordering } ;
14
27
15
- use cortex_m:: { interrupt, register} ;
16
28
use cortex_m_semihosting:: hio;
17
29
18
30
#[ defmt:: global_logger]
19
31
struct Logger ;
20
32
21
33
static TAKEN : AtomicBool = AtomicBool :: new ( false ) ;
22
- static INTERRUPTS_ACTIVE : AtomicBool = AtomicBool :: new ( false ) ;
34
+ static mut CS_RESTORE : critical_section :: RestoreState = critical_section :: RestoreState :: invalid ( ) ;
23
35
static mut ENCODER : defmt:: Encoder = defmt:: Encoder :: new ( ) ;
24
36
25
37
unsafe impl defmt:: Logger for Logger {
26
38
fn acquire ( ) {
27
- let primask = register :: primask :: read ( ) ;
28
- interrupt :: disable ( ) ;
39
+ // safety: Must be paired with corresponding call to release(), see below
40
+ let restore = unsafe { critical_section :: acquire ( ) } ;
29
41
30
42
if TAKEN . load ( Ordering :: Relaxed ) {
31
43
panic ! ( "defmt logger taken reentrantly" )
@@ -34,7 +46,8 @@ unsafe impl defmt::Logger for Logger {
34
46
// no need for CAS because interrupts are disabled
35
47
TAKEN . store ( true , Ordering :: Relaxed ) ;
36
48
37
- INTERRUPTS_ACTIVE . store ( primask. is_active ( ) , Ordering :: Relaxed ) ;
49
+ // safety: accessing the `static mut` is OK because we have acquired a critical section.
50
+ unsafe { CS_RESTORE = restore } ;
38
51
39
52
// safety: accessing the `static mut` is OK because we have disabled interrupts.
40
53
unsafe { ENCODER . start_frame ( do_write) }
@@ -52,10 +65,12 @@ unsafe impl defmt::Logger for Logger {
52
65
ENCODER . end_frame ( do_write) ;
53
66
54
67
TAKEN . store ( false , Ordering :: Relaxed ) ;
55
- if INTERRUPTS_ACTIVE . load ( Ordering :: Relaxed ) {
56
- // re-enable interrupts
57
- interrupt:: enable ( )
58
- }
68
+
69
+ // safety: accessing the `static mut` is OK because we have acquired a critical section.
70
+ let restore = unsafe { CS_RESTORE } ;
71
+
72
+ // safety: Must be paired with corresponding call to acquire(), see above
73
+ unsafe { critical_section:: release ( restore) } ;
59
74
}
60
75
61
76
unsafe fn write ( bytes : & [ u8 ] ) {
0 commit comments