Skip to content

Commit 2a4382e

Browse files
authored
Merge pull request #232 from brain113/serial_read_write_irq
Add read and write impl for Serial, Irq flags functions and RTIC example
2 parents d8f0b07 + 05e1e0c commit 2a4382e

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ panic-probe = "0.2.0"
5151
panic-semihosting = "0.5.6"
5252
usbd-serial = "0.1.1"
5353
usb-device = "0.2.8"
54+
cortex-m-rtic = "0.6.0-alpha.4"
55+
dwt-systick-monotonic = "0.1.0-alpha.2"
56+
panic-rtt-target = { version = "0.1", features = ["cortex-m"] }
57+
rtt-target = { version = "0.3.0", features = ["cortex-m"] }
5458

5559
[build-dependencies]
5660
cargo_metadata = "0.13.1"
@@ -163,6 +167,10 @@ required-features = ["ld", "can", "stm32f303"]
163167
name = "serial_dma"
164168
required-features = ["ld", "stm32f303"]
165169

170+
[[example]]
171+
name = "serial_echo_rtic"
172+
required-features = ["ld", "rt", "stm32f303xc"]
173+
166174
[[example]]
167175
name = "adc"
168176
required-features = ["ld", "stm32f303"]

examples/serial_echo_rtic.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
use panic_rtt_target as _;
5+
6+
#[rtic::app(device = stm32f3xx_hal::pac, dispatchers = [TIM20_BRK, TIM20_UP, TIM20_TRG_COM])]
7+
mod app {
8+
use dwt_systick_monotonic::DwtSystick;
9+
use rtt_target::{rprintln, rtt_init_print};
10+
use stm32f3xx_hal::{
11+
gpio::{self, Output, PushPull, AF7},
12+
prelude::*,
13+
serial::{Event, Serial},
14+
};
15+
16+
#[monotonic(binds = SysTick, default = true)]
17+
type DwtMono = DwtSystick<48_000_000>;
18+
19+
type SerialType = Serial<
20+
stm32f3xx_hal::pac::USART1,
21+
(
22+
gpio::gpioa::PA9<AF7<PushPull>>,
23+
gpio::gpioa::PA10<AF7<PushPull>>,
24+
),
25+
>;
26+
type DirType = stm32f3xx_hal::gpio::gpioe::PE13<Output<PushPull>>;
27+
#[resources]
28+
struct Resources {
29+
serial: SerialType,
30+
dir: DirType,
31+
}
32+
33+
#[init]
34+
fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) {
35+
let mut flash = cx.device.FLASH.constrain();
36+
let mut rcc = cx.device.RCC.constrain();
37+
let mut dcb = cx.core.DCB;
38+
let dwt = cx.core.DWT;
39+
let systick = cx.core.SYST;
40+
41+
rtt_init_print!(NoBlockSkip, 4096);
42+
rprintln!("pre init");
43+
44+
// Initialize the clocks
45+
let clocks = rcc.cfgr.sysclk(48.MHz()).freeze(&mut flash.acr);
46+
let mono = DwtSystick::new(&mut dcb, dwt, systick, clocks.sysclk().0);
47+
48+
// Initialize the peripherals
49+
// DIR
50+
let mut gpioe = cx.device.GPIOE.split(&mut rcc.ahb);
51+
let mut dir: DirType = gpioe
52+
.pe13
53+
.into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
54+
dir.set_low().unwrap();
55+
56+
// SERIAL
57+
let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb);
58+
let mut pins = (
59+
gpioa
60+
.pa9
61+
.into_af7_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh),
62+
gpioa
63+
.pa10
64+
.into_af7_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh),
65+
);
66+
pins.1.internal_pull_up(&mut gpioa.pupdr, true);
67+
let mut serial: SerialType = Serial::usart1(
68+
cx.device.USART1,
69+
pins,
70+
19200_u32.Bd(),
71+
clocks,
72+
&mut rcc.apb2,
73+
);
74+
serial.listen(Event::Rxne);
75+
76+
rprintln!("post init");
77+
78+
task1::spawn().unwrap();
79+
80+
(init::LateResources { dir, serial }, init::Monotonics(mono))
81+
}
82+
83+
#[task(binds = USART1_EXTI25, resources = [serial, dir])]
84+
fn protocol_serial_task(cx: protocol_serial_task::Context) {
85+
let mut serial = cx.resources.serial;
86+
let mut dir = cx.resources.dir;
87+
88+
serial.lock(|serial| {
89+
dir.lock(|dir| {
90+
if serial.is_rxne() {
91+
dir.set_high().unwrap();
92+
serial.unlisten(Event::Rxne);
93+
match serial.read() {
94+
Ok(byte) => {
95+
serial.write(byte).unwrap();
96+
serial.listen(Event::Tc);
97+
}
98+
Err(_error) => rprintln!("irq error"),
99+
};
100+
}
101+
102+
if serial.is_tc() {
103+
dir.set_low().unwrap();
104+
serial.unlisten(Event::Tc);
105+
serial.listen(Event::Rxne);
106+
}
107+
})
108+
});
109+
}
110+
111+
#[task]
112+
fn task1(_cx: task1::Context) {
113+
rprintln!("task1");
114+
}
115+
116+
#[idle]
117+
fn idle(_: idle::Context) -> ! {
118+
rprintln!("idle");
119+
loop {
120+
cortex_m::asm::nop();
121+
}
122+
}
123+
}

src/serial.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ pub enum Event {
2525
Rxne,
2626
/// New data can be sent
2727
Txe,
28+
/// Transmission complete
29+
Tc,
2830
}
2931

3032
/// Serial error
@@ -151,6 +153,9 @@ macro_rules! hal {
151153
Event::Txe => {
152154
self.usart.cr1.modify(|_, w| w.txeie().set_bit())
153155
},
156+
Event::Tc => {
157+
self.usart.cr1.modify(|_, w| w.tcie().set_bit())
158+
},
154159
}
155160
}
156161

@@ -163,9 +168,31 @@ macro_rules! hal {
163168
Event::Txe => {
164169
self.usart.cr1.modify(|_, w| w.txeie().clear_bit())
165170
},
171+
Event::Tc => {
172+
self.usart.cr1.modify(|_, w| w.tcie().clear_bit())
173+
},
166174
}
167175
}
168176

177+
/// Return true if the line idle status is set
178+
pub fn is_tc(&self) -> bool {
179+
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
180+
isr.tc().bit_is_set()
181+
}
182+
183+
/// Return true if the tx register is empty (and can accept data)
184+
pub fn is_txe(&self) -> bool {
185+
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
186+
isr.txe().bit_is_set()
187+
}
188+
189+
/// Return true if the rx register is not empty (and can be read)
190+
pub fn is_rxne(&self) -> bool {
191+
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
192+
isr.rxne().bit_is_set()
193+
}
194+
195+
169196
/// Splits the `Serial` abstraction into a transmitter and a receiver half
170197
pub fn split(self) -> (Tx<$USARTX>, Rx<$USARTX>) {
171198
(
@@ -184,6 +211,35 @@ macro_rules! hal {
184211
}
185212
}
186213

214+
impl<TX, RX> serial::Read<u8> for Serial<$USARTX, (TX, RX)> {
215+
type Error = Error;
216+
217+
fn read(&mut self) -> nb::Result<u8, Error> {
218+
let mut rx: Rx<$USARTX> = Rx {
219+
_usart: PhantomData,
220+
};
221+
rx.read()
222+
}
223+
}
224+
225+
impl<TX, RX> serial::Write<u8> for Serial<$USARTX, (TX, RX)> {
226+
type Error = Infallible;
227+
228+
fn flush(&mut self) -> nb::Result<(), Infallible> {
229+
let mut tx: Tx<$USARTX> = Tx {
230+
_usart: PhantomData,
231+
};
232+
tx.flush()
233+
}
234+
235+
fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> {
236+
let mut tx: Tx<$USARTX> = Tx {
237+
_usart: PhantomData,
238+
};
239+
tx.write(byte)
240+
}
241+
}
242+
187243
impl serial::Read<u8> for Rx<$USARTX> {
188244
type Error = Error;
189245

0 commit comments

Comments
 (0)