1
+ //! Interrupt Driven Serial Echo Example
2
+
3
+ #![ no_main]
4
+ #![ no_std]
5
+ #![ deny( unsafe_code) ]
6
+ #![ allow( non_camel_case_types) ]
7
+
8
+ use panic_halt as _;
9
+ use nb:: block;
10
+ use core:: cell:: RefCell ;
11
+
12
+ use cortex_m:: interrupt:: Mutex ;
13
+ use cortex_m_rt:: entry;
14
+
15
+ use stm32f0xx_hal as hal;
16
+ use hal:: {
17
+ pac:: { self , interrupt, Interrupt , USART1 } ,
18
+ prelude:: * ,
19
+ serial:: Serial , gpio:: { gpioa:: { PA2 , PA15 } , Alternate , AF1 , Output , PushPull , gpiob:: PB3 } ,
20
+ delay:: Delay
21
+ } ;
22
+
23
+ // setup some types for our globally shared resources
24
+ type LED_PIN = PB3 < Output < PushPull > > ;
25
+ type SERIAL = Serial < USART1 , PA2 < Alternate < AF1 > > , PA15 < Alternate < AF1 > > > ;
26
+
27
+ /*
28
+ Create our global variables:
29
+
30
+ We use a Mutex because Mutexes require a CriticalSection
31
+ context in order to be borrowed. Since CriticalSection
32
+ contexts cannot overlap (by definition) we can rest assured
33
+ that the resource inside the Mutex will not violate
34
+ the RefMut's runtime borrowing rules (Given that we do not
35
+ try to borrow the RefMute more than once per CriticalSection).
36
+ */
37
+ static LED : Mutex < RefCell < Option < LED_PIN > > > = Mutex :: new ( RefCell :: new ( None ) ) ;
38
+ static SER_PORT : Mutex < RefCell < Option < SERIAL > > > = Mutex :: new ( RefCell :: new ( None ) ) ;
39
+
40
+ // some helper macros to ensure safe usage of our globals
41
+ macro_rules! init_global {
42
+ ( $CS: ident, $GLOBAL: ident, $VAL: expr) => {
43
+ * $GLOBAL. borrow( $CS) . borrow_mut( ) = Some ( $VAL) ;
44
+ } ;
45
+ }
46
+
47
+ macro_rules! with_global_mut {
48
+ ( $CS: ident, $GLOBAL: ident, $LOCAL: ident, $CODE: block) => {
49
+ if let Some ( $LOCAL) = $GLOBAL. borrow( $CS) . borrow_mut( ) . as_mut( ) {
50
+ $CODE
51
+ } else {
52
+ panic!( ) ;
53
+ }
54
+ } ;
55
+ }
56
+
57
+ // a helper macro to generalize the initialization of a UART
58
+ macro_rules! setup_uart {
59
+ ( $CS: ident, $DP: ident, $RCC: ident, $GPIOx: ident ) => {
60
+ let ( tx, rx) =
61
+ (
62
+ $GPIOx. pa2. into_alternate_af1( $CS) ,
63
+ $GPIOx. pa15. into_alternate_af1( $CS) ,
64
+ ) ;
65
+
66
+ init_global!( $CS, SER_PORT , Serial :: usart1( $DP. USART1 , ( tx, rx) , 9_600 . bps( ) , & mut $RCC) ) ;
67
+ with_global_mut!( $CS, SER_PORT , ser, {
68
+ ser. listen( hal:: serial:: Event :: Rxne ) ;
69
+ } ) ;
70
+ } ;
71
+ }
72
+
73
+ #[ entry]
74
+ fn main ( ) -> ! {
75
+ let dp = pac:: Peripherals :: take ( ) . unwrap ( ) ; // might as well panic if this doesn't work
76
+ let cp = cortex_m:: peripheral:: Peripherals :: take ( ) . unwrap ( ) ;
77
+ let mut flash = dp. FLASH ;
78
+ let mut rcc = dp. RCC . configure ( ) . sysclk ( 48 . mhz ( ) ) . freeze ( & mut flash) ;
79
+
80
+ let gpioa = dp. GPIOA . split ( & mut rcc) ;
81
+ let gpiob = dp. GPIOB . split ( & mut rcc) ;
82
+
83
+ let mut delay = Delay :: new ( cp. SYST , & rcc) ;
84
+
85
+ cortex_m:: interrupt:: free ( |cs| {
86
+ setup_uart ! ( cs, dp, rcc, gpioa) ;
87
+
88
+ init_global ! ( cs, LED , gpiob. pb3. into_push_pull_output( cs) ) ;
89
+ } ) ;
90
+
91
+ #[ allow( unsafe_code) ] // just this once ;)
92
+ unsafe { cortex_m:: peripheral:: NVIC :: unmask ( Interrupt :: USART1 ) ; }
93
+
94
+ loop {
95
+ cortex_m:: interrupt:: free ( |cs| {
96
+ with_global_mut ! ( cs, LED , led, {
97
+ led. toggle( ) . ok( ) ;
98
+ } ) ;
99
+ } ) ;
100
+
101
+ delay. delay_ms ( 1_000u16 ) ;
102
+ }
103
+ }
104
+
105
+ #[ interrupt]
106
+ fn USART1 ( ) {
107
+ cortex_m:: interrupt:: free ( |cs| {
108
+ with_global_mut ! ( cs, SER_PORT , ser, {
109
+ if let Ok ( data) = block!( ser. read( ) ) {
110
+ block!( ser. write( data) ) . ok( ) ;
111
+ } else {
112
+ /*
113
+ Failed to read a byte:
114
+
115
+ There could be some kind of alignment error or the UART
116
+ was disconnected or something.
117
+ */
118
+ }
119
+ } ) ;
120
+ } ) ;
121
+ }
0 commit comments