-
Notifications
You must be signed in to change notification settings - Fork 69
/
Copy pathserial_echo_rtic.rs
143 lines (123 loc) · 5.35 KB
/
serial_echo_rtic.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#![no_main]
#![no_std]
use panic_rtt_target as _;
// This example application prints all characters it receives via Serial and sends them back.
//
// NOTES:
// - Depending on the board you're using, `Serial` might need different Tx and Rx pins instead of
// pa9 and pa10 (for example, the STM32f3DISCOVERY board uses pc4 and pc5).
// Check your boards' schematic and adjust the code accordingly.
// - https://docs.rust-embedded.org/discovery/10-serial-communication/nix-tooling.html?highlight=*nix#nix-tooling
// has instructions on how to connect to your Serial device (make sure to adjust the baud rate)
#[rtic::app(device = stm32f3xx_hal::pac, dispatchers = [TIM20_BRK, TIM20_UP, TIM20_TRG_COM])]
mod app {
use rtt_target::{rprintln, rtt_init_print};
use stm32f3xx_hal::{
gpio::{self, Output, PushPull, AF7},
pac,
prelude::*,
serial::{Event, Serial},
Switch,
};
use systick_monotonic::*;
#[monotonic(binds = SysTick, default = true)]
type AppMono = Systick<100>; // 100 Hz / 10 ms granularity
type SerialType = Serial<pac::USART1, (gpio::PA9<AF7<PushPull>>, gpio::PA10<AF7<PushPull>>)>;
// The LED that will light up when data is received via serial
type DirType = gpio::PE13<Output<PushPull>>;
#[shared]
struct Shared {}
#[local]
struct Local {
serial: SerialType,
dir: DirType,
}
#[init]
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
let mut flash = cx.device.FLASH.constrain();
let mut rcc = cx.device.RCC.constrain();
let systick = cx.core.SYST;
rtt_init_print!(NoBlockSkip, 4096);
rprintln!("pre init");
// Initialize the clocks
let clocks = rcc.cfgr.sysclk(48.MHz()).freeze(&mut flash.acr);
let mono = Systick::new(systick, 48_000_000);
// Initialize the peripherals
// DIR (the LED that lights up during serial rx)
let mut gpioe = cx.device.GPIOE.split(&mut rcc.ahb);
let mut dir: DirType = gpioe
.pe13
.into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
dir.set_low().unwrap();
// SERIAL
let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb);
let mut pins = (
gpioa
// Tx pin
.pa9
// configure this pin to make use of its `USART1_TX` alternative function
// (AF mapping taken from table 14 "Alternate functions for port A" of the datasheet at
// https://www.st.com/en/microcontrollers-microprocessors/stm32f303vc.html)
.into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh),
gpioa
// Rx pin
.pa10
// configure this pin to make use of its `USART1_RX` alternative function
// (AF mapping taken from table 14 "Alternate functions for port A" of the datasheet at
// https://www.st.com/en/microcontrollers-microprocessors/stm32f303vc.html)
.into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh),
);
pins.1.internal_pull_up(&mut gpioa.pupdr, true);
let mut serial: SerialType =
Serial::new(cx.device.USART1, pins, 19200.Bd(), clocks, &mut rcc.apb2);
serial.configure_interrupt(Event::ReceiveDataRegisterNotEmpty, Switch::On);
rprintln!("post init");
// A kick of for the infitinte loop in protocol_serial_task()
nb::block!(serial.write(b'c')).unwrap();
task1::spawn().unwrap();
(Shared {}, Local { serial, dir }, init::Monotonics(mono))
}
#[task(binds = USART1_EXTI25, local = [serial, dir])]
fn protocol_serial_task(cx: protocol_serial_task::Context) {
let serial = cx.local.serial;
let dir = cx.local.dir;
if serial.is_event_triggered(Event::ReceiveDataRegisterNotEmpty) {
dir.set_high().unwrap();
serial.configure_interrupt(Event::ReceiveDataRegisterNotEmpty, Switch::Off);
match serial.read() {
Ok(byte) => {
serial.write(byte).unwrap();
rprintln!("{:?}", char::from_u32(byte.into()).unwrap_or('?'));
serial.configure_interrupt(Event::TransmissionComplete, Switch::On);
}
Err(_error) => rprintln!("irq error"),
};
}
// It is perfectly viable to just use `is_event_triggered` here,
// but this is a showcase, to also be able to used `triggered_events`
// and other functions enabled by the "enumset" feature.
let events = serial.triggered_events();
if events.contains(Event::TransmissionComplete) {
dir.set_low().unwrap();
let interrupts = {
let mut interrupts = enumset::EnumSet::new();
interrupts.insert(Event::ReceiveDataRegisterNotEmpty);
interrupts
};
serial.clear_event(Event::TransmissionComplete);
// Disable all interrupts, except ReceiveDataRegisterNotEmpty.
serial.configure_interrupts(interrupts);
}
}
#[task]
fn task1(_cx: task1::Context) {
rprintln!("task1");
}
#[idle]
fn idle(_: idle::Context) -> ! {
rprintln!("idle");
loop {
cortex_m::asm::nop();
}
}
}