6
6
use defmt_rtt as _;
7
7
use panic_probe as _;
8
8
9
- use defmt ;
9
+ use core :: cell :: RefCell ;
10
10
11
11
use cortex_m:: asm;
12
+ use cortex_m:: interrupt:: Mutex ;
12
13
use cortex_m_rt:: entry;
13
14
14
15
use embedded_hal:: adc:: OneShot ;
15
- use stm32f3xx_hal:: { adc, pac, prelude:: * } ;
16
+ use stm32f3xx_hal:: {
17
+ adc,
18
+ pac:: { self , interrupt} ,
19
+ prelude:: * ,
20
+ timer,
21
+ } ;
22
+
23
+ /// That's a mouthful, so explain it:
24
+ ///
25
+ /// 1. Wrap the Timer in a Mutex, so it can be safely shared between
26
+ /// main loop and interrupt or rather used in functions, which could theoretically
27
+ /// be preempted.
28
+ /// 2. Wrap the Timer in a RefCell to be able obtain a mutable reference to the Timer itself.
29
+ /// E.g. the interrupt can't take ownership of the timer, it is shared between main-loop and
30
+ /// interrupt context.
31
+ /// 3. Wrap the Timer in an Option, so that it can be "lazily initialized". Statics have to be
32
+ /// initialized with const values, which the timer itself is obviously not, but None is.
33
+ ///
34
+ /// This could all be done just with a static mut && unsafe as
35
+ /// the usecase it pretty clear, but this is to show the definitely safe
36
+ /// alternative.
37
+ static TIMER : Mutex < RefCell < Option < timer:: Timer < pac:: TIM2 > > > > = Mutex :: new ( RefCell :: new ( None ) ) ;
16
38
17
39
#[ entry]
18
40
fn main ( ) -> ! {
@@ -21,12 +43,26 @@ fn main() -> ! {
21
43
let mut rcc = dp. RCC . constrain ( ) ;
22
44
let clocks = rcc. cfgr . freeze ( & mut dp. FLASH . constrain ( ) . acr ) ;
23
45
46
+ // This is a workaround, so that the debugger will not disconnect imidiatly on asm::wfi();
47
+ // https://github.com/probe-rs/probe-rs/issues/350#issuecomment-740550519
48
+ dp. DBGMCU . cr . modify ( |_, w| {
49
+ w. dbg_sleep ( ) . set_bit ( ) ;
50
+ w. dbg_standby ( ) . set_bit ( ) ;
51
+ w. dbg_stop ( ) . set_bit ( )
52
+ } ) ;
53
+
54
+ // Create a Common ADC instance, which is shared between ADC1 and ADC2 in this case,
55
+ // and for example is in control of the clock of both of these peripherals.
24
56
let mut adc_common = adc:: CommonAdc :: new ( dp. ADC1_2 , & clocks, & mut rcc. ahb ) ;
25
57
58
+ // We have to pack these peripherals in a tuple, so that `TemperatureSensor` can
59
+ // get a mutable reference to both of these as a singular argument.
60
+ //
61
+ // This is needed, as both ADC1 and ADC2 have to be of to enable the `TemperatureSensor`.
26
62
let mut tuple = ( dp. ADC1 , dp. ADC2 ) ;
27
63
let mut ts = adc:: TemperatureSensor :: new ( & mut adc_common, & mut tuple) ;
28
64
29
- // set up adc1
65
+ // Set up ADC1
30
66
let mut adc = adc:: Adc :: new (
31
67
tuple. 0 , // The ADC we are going to control
32
68
adc:: config:: Config :: default ( ) ,
@@ -54,6 +90,19 @@ fn main() -> ! {
54
90
let mut gpioa = dp. GPIOA . split ( & mut rcc. ahb ) ;
55
91
let mut analog_pin = gpioa. pa0 . into_analog ( & mut gpioa. moder , & mut gpioa. pupdr ) ;
56
92
93
+ let mut timer = timer:: Timer :: new ( dp. TIM2 , clocks, & mut rcc. apb1 ) ;
94
+
95
+ unsafe {
96
+ cortex_m:: peripheral:: NVIC :: unmask ( timer. interrupt ( ) ) ;
97
+ }
98
+ timer. enable_interrupt ( timer:: Event :: Update ) ;
99
+ // Start a timer which fires regularly to wake up from `asm::wfi`
100
+ timer. start ( 500 . milliseconds ( ) ) ;
101
+ // Put the timer in the global context.
102
+ cortex_m:: interrupt:: free ( |cs| {
103
+ TIMER . borrow ( cs) . replace ( Some ( timer) ) ;
104
+ } ) ;
105
+
57
106
// Be aware that the values in the table below depend on the input of VREF.
58
107
// To have a stable VREF input, put a condensator and a volt limiting diode in front of it.
59
108
//
@@ -77,8 +126,24 @@ fn main() -> ! {
77
126
defmt:: trace!( "PA0 reads {}" , adc_data) ;
78
127
let adc_data: u16 = adc. read ( & mut ts) . unwrap ( ) ;
79
128
defmt:: trace!( "TemperatureSensor reads {}" , adc_data) ;
80
- asm:: delay ( 2_000_000 ) ;
129
+ asm:: wfi ( ) ;
81
130
}
82
131
}
83
132
84
- // TODO: Add adc example, which uses Continuous or Discontinous and interrupts.
133
+ #[ interrupt]
134
+ fn TIM2 ( ) {
135
+ // Just handle the pending interrupt event.
136
+ cortex_m:: interrupt:: free ( |cs| {
137
+ TIMER
138
+ // Unlock resource for use in critical section
139
+ . borrow ( cs)
140
+ // Get a mutable reference from the RefCell
141
+ . borrow_mut ( )
142
+ // Make the inner Option<T> -> Option<&mut T>
143
+ . as_mut ( )
144
+ // Unwrap the option, we know, that it has Some()!
145
+ . unwrap ( )
146
+ // Finally operate on the timer itself.
147
+ . clear_event ( timer:: Event :: Update ) ;
148
+ } )
149
+ }
0 commit comments