Skip to content

Commit 5d6bf43

Browse files
committed
new interrupt driven serial echo
1 parent eed06fb commit 5d6bf43

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- PWM complementary output capability for TIM1 with new example to demonstrate
13+
- New `serial_echo_irq` example to showcase an interrupt driven serial echo
1014
### Changed
1115

1216
- Updated the `cast` dependency from 0.2 to 0.3

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: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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 = 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 per CriticalSection).
39+
*/
40+
static SER_PORT: Mutex<RefCell<Option<SERIAL>>> = 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+
*SER_PORT.borrow(cs).borrow_mut() =
63+
Some(Serial::usart1(dp.USART1, (tx, rx), 9_600.bps(), &mut rcc));
64+
65+
if let Some(ser) = SER_PORT.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+
cortex_m::interrupt::free(|cs| {
89+
if let Some(ser) = SER_PORT.borrow(cs).borrow_mut().as_mut() {
90+
if let Ok(data) = block!(ser.read()) {
91+
block!(ser.write(data)).ok();
92+
} else {
93+
/*
94+
Failed to read a byte:
95+
96+
There could be some kind of alignment error or the UART
97+
was disconnected or something.
98+
*/
99+
}
100+
}
101+
});
102+
}

0 commit comments

Comments
 (0)