forked from stm32-rs/stm32f1xx-hal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
timer-interrupt-rtic.rs
106 lines (92 loc) · 3.62 KB
/
timer-interrupt-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
//! Uses the timer interrupt to blink a led with different frequencies.
//!
//! This assumes that a LED is connected to pc13 as is the case on the blue pill board.
//!
//! Note: Without additional hardware, PC13 should not be used to drive an LED, see page 5.1.2 of
//! the reference manual for an explanation. This is not an issue on the blue pill.
#![no_std]
#![no_main]
// you can put a breakpoint on `rust_begin_unwind` to catch panics
use panic_halt as _;
#[rtic::app(device = stm32f1xx_hal::pac)]
mod app {
use stm32f1xx_hal::{
gpio::{gpioc::PC13, Output, PinState, PushPull},
pac,
prelude::*,
timer::{CounterMs, Event},
};
#[shared]
struct Shared {}
#[local]
struct Local {
led: PC13<Output<PushPull>>,
timer_handler: CounterMs<pac::TIM1>,
}
#[init]
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
// Take ownership over the raw flash and rcc devices and convert them into the corresponding
// HAL structs
let mut flash = cx.device.FLASH.constrain();
let rcc = cx.device.RCC.constrain();
// Freeze the configuration of all the clocks in the system and store the frozen frequencies
// in `clocks`
let clocks = rcc.cfgr.freeze(&mut flash.acr);
// Acquire the GPIOC peripheral
let mut gpioc = cx.device.GPIOC.split();
// Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the
// function in order to configure the port. For pins 0-7, crl should be passed instead
let led = gpioc
.pc13
.into_push_pull_output_with_state(&mut gpioc.crh, PinState::High);
// Configure the syst timer to trigger an update every second and enables interrupt
let mut timer = cx.device.TIM1.counter_ms(&clocks);
timer.start(1.secs()).unwrap();
timer.listen(Event::Update);
// Init the static resources to use them later through RTIC
(
Shared {},
Local {
led,
timer_handler: timer,
},
init::Monotonics(),
)
}
// Optional.
//
// https://rtic.rs/dev/book/en/by-example/app_idle.html
// > When no idle function is declared, the runtime sets the SLEEPONEXIT bit and then
// > sends the microcontroller to sleep after running init.
#[idle]
fn idle(_cx: idle::Context) -> ! {
loop {
cortex_m::asm::wfi();
}
}
#[task(binds = TIM1_UP, priority = 1, local = [led, timer_handler, led_state: bool = false, count: u8 = 0])]
fn tick(cx: tick::Context) {
// Depending on the application, you could want to delegate some of the work done here to
// the idle task if you want to minimize the latency of interrupts with same priority (if
// you have any). That could be done
if *cx.local.led_state {
// Uses resources managed by rtic to turn led off (on bluepill)
cx.local.led.set_high();
*cx.local.led_state = false;
} else {
cx.local.led.set_low();
*cx.local.led_state = true;
}
// Count used to change the timer update frequency
*cx.local.count += 1;
if *cx.local.count == 4 {
// Changes timer update frequency
cx.local.timer_handler.start(500.millis()).unwrap();
} else if *cx.local.count == 12 {
cx.local.timer_handler.start(1.secs()).unwrap();
*cx.local.count = 0;
}
// Clears the update flag
cx.local.timer_handler.clear_interrupt(Event::Update);
}
}