Skip to content

Commit 2d3fcec

Browse files
committed
new interrupt driven serial echo
1 parent eed06fb commit 2d3fcec

File tree

3 files changed

+126
-0
lines changed

3 files changed

+126
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1616
- Provide getters to serial status flags idle/txe/rxne/tc.
1717
- Provide ability to reset timer UIF interrupt flag
1818
- PWM complementary output capability for TIM1 with new example to demonstrate
19+
- New `serial_echo_irq` example to showcase an interrupt driven serial echo
1920

2021
### Fixed
2122

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,7 @@ required-features = ["stm32f042", "rt"]
9797
[[example]]
9898
name = "usb_serial"
9999
required-features = ["rt", "stm32f042", "stm32-usbd"]
100+
101+
[[example]]
102+
name = "serial_echo_irq"
103+
required-features = ["stm32f031"]

examples/serial_echo_irq.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//! Interrupt Driven Serial Echo Example
2+
//! For NUCLEO-F031K6
3+
4+
#![no_main]
5+
#![no_std]
6+
#![deny(unsafe_code)]
7+
#![allow(non_camel_case_types)]
8+
9+
use core::cell::RefCell;
10+
use nb::block;
11+
use panic_halt as _;
12+
13+
use cortex_m::interrupt::Mutex;
14+
use cortex_m_rt::entry;
15+
16+
use hal::{
17+
delay::Delay,
18+
gpio::{
19+
gpioa::{PA15, PA2},
20+
Alternate, AF1,
21+
},
22+
pac::{self, interrupt, Interrupt, USART1},
23+
prelude::*,
24+
serial::Serial,
25+
};
26+
use stm32f0xx_hal as hal;
27+
28+
type SERIAL_PORT = Serial<USART1, PA2<Alternate<AF1>>, PA15<Alternate<AF1>>>;
29+
30+
/*
31+
Create our global variables:
32+
33+
We use a Mutex because Mutexes require a CriticalSection
34+
context in order to be borrowed. Since CriticalSection
35+
contexts cannot overlap (by definition) we can rest assured
36+
that the resource inside the Mutex will not violate
37+
the RefMut's runtime borrowing rules (Given that we do not
38+
try to borrow the RefMut more than once at a time).
39+
*/
40+
static GSERIAL: Mutex<RefCell<Option<SERIAL_PORT>>> = Mutex::new(RefCell::new(None));
41+
42+
#[entry]
43+
fn main() -> ! {
44+
let (mut delay, mut led) = cortex_m::interrupt::free(|cs| {
45+
let dp = pac::Peripherals::take().unwrap(); // might as well panic if this doesn't work
46+
let cp = cortex_m::peripheral::Peripherals::take().unwrap();
47+
let mut flash = dp.FLASH;
48+
let mut rcc = dp.RCC.configure().sysclk(48.mhz()).freeze(&mut flash);
49+
50+
let gpioa = dp.GPIOA.split(&mut rcc);
51+
let gpiob = dp.GPIOB.split(&mut rcc);
52+
53+
let delay = Delay::new(cp.SYST, &rcc);
54+
55+
// setup UART
56+
let (tx, rx) = (
57+
gpioa.pa2.into_alternate_af1(cs),
58+
gpioa.pa15.into_alternate_af1(cs),
59+
);
60+
61+
// initialize global serial
62+
*GSERIAL.borrow(cs).borrow_mut() =
63+
Some(Serial::usart1(dp.USART1, (tx, rx), 9_600.bps(), &mut rcc));
64+
65+
if let Some(ser) = GSERIAL.borrow(cs).borrow_mut().as_mut() {
66+
ser.listen(hal::serial::Event::Rxne); // trigger the USART1 interrupt when bytes are available (receive buffer not empty)
67+
}
68+
69+
let led = gpiob.pb3.into_push_pull_output(cs);
70+
71+
(delay, led)
72+
});
73+
74+
#[allow(unsafe_code)] // just this once ;)
75+
unsafe {
76+
cortex_m::peripheral::NVIC::unmask(Interrupt::USART1);
77+
}
78+
79+
loop {
80+
led.toggle().ok();
81+
82+
delay.delay_ms(1_000u16);
83+
}
84+
}
85+
86+
#[interrupt]
87+
fn USART1() {
88+
static mut SERIAL: Option<SERIAL_PORT> = None;
89+
90+
/*
91+
Once the main function has initialized the serial port,
92+
we move it into this interrupt handler, giving
93+
it exclusive access to the serial port.
94+
*/
95+
let ser = SERIAL.get_or_insert_with(|| {
96+
cortex_m::interrupt::free(|cs| {
97+
if let Some(ser) = GSERIAL.borrow(cs).take() {
98+
ser
99+
} else {
100+
/*
101+
This means the main function failed to initialize
102+
the serial port.
103+
104+
For this example, we will panic.
105+
*/
106+
panic!();
107+
}
108+
})
109+
});
110+
111+
if let Ok(data) = block!(ser.read()) {
112+
block!(ser.write(data)).ok();
113+
} else {
114+
/*
115+
Failed to read a byte:
116+
117+
There could be some kind of alignment error or the UART
118+
was disconnected or something.
119+
*/
120+
}
121+
}

0 commit comments

Comments
 (0)