forked from stm32-rs/stm32h7xx-hal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rtic_low_power.rs
166 lines (143 loc) · 5.03 KB
/
rtic_low_power.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//! Timers in RTIC with low power mode.
//!
//! After the end of init the CPU transitions into CStop mode, and D1/D2
//! (aka. CD) transition into DStop mode.
//!
//! However we set the run_d3/run_srd flag, and enable Autonomous mode on the
//! LPTIM3 PREC struture. Therefore LPTIM3 continues to run and fires an
//! interrupt that wakes the core. Following each interrupt the core returns to
//! CStop mode.
//!
//! On the first rising edge on PC13, the EXTI interrupt fires. We do not clear
//! this interrupt, so we loop in the handler forever.
//!
//! Nb. on dual core parts you will also need to ensure that CPU2 transitions to
//! DStop mode.
//!
#![deny(warnings)]
#![deny(unsafe_code)]
#![no_std]
#![no_main]
extern crate rtic;
#[macro_use]
mod utilities;
#[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true)]
mod app {
use stm32h7xx_hal::gpio::gpioc::{PC2, PC3, PC4};
use stm32h7xx_hal::gpio::{Edge, ExtiPin, Output, PushPull};
use stm32h7xx_hal::prelude::*;
use stm32h7xx_hal::rcc::LowPowerMode;
use stm32h7xx_hal::stm32::{LPTIM3, TIM1, TIM2};
use stm32h7xx_hal::time::MilliSeconds;
use stm32h7xx_hal::timer::{Enabled, Event, LpTimer, Timer};
use super::*;
#[shared]
struct SharedResources {}
#[local]
struct LocalResources {
led1: PC2<Output<PushPull>>,
led2: PC3<Output<PushPull>>,
led3: PC4<Output<PushPull>>,
timer1: Timer<TIM1>,
timer2: Timer<TIM2>,
timer3: LpTimer<LPTIM3, Enabled>,
}
#[init]
fn init(
ctx: init::Context,
) -> (SharedResources, LocalResources, init::Monotonics) {
utilities::logger::init();
let mut syscfg = ctx.device.SYSCFG;
// Run D3 / SRD domain
#[cfg(not(feature = "rm0455"))]
ctx.device.PWR.cpucr.modify(|_, w| w.run_d3().set_bit());
#[cfg(feature = "rm0455")] // 7b3/7a3/7b0 parts
ctx.device.PWR.cpucr.modify(|_, w| w.run_srd().set_bit());
let pwr = ctx.device.PWR.constrain();
let vos = example_power!(pwr).freeze();
// RCC
let rcc = ctx.device.RCC.constrain();
let ccdr = rcc
// D3 / SRD domain
.hclk(16.MHz()) // rcc_hclk4
.pclk4(4.MHz()) // rcc_pclk4
.freeze(vos, &syscfg);
// Timers
let mut timer1 = ctx.device.TIM1.timer(
MilliSeconds::from_ticks(250).into_rate(),
// Run in CSleep, but not CStop
ccdr.peripheral.TIM1.low_power(LowPowerMode::Enabled),
&ccdr.clocks,
);
timer1.listen(Event::TimeOut);
let mut timer2 = ctx.device.TIM2.timer(
MilliSeconds::from_ticks(500).into_rate(),
// Run in CSleep, but not CStop
ccdr.peripheral.TIM2.low_power(LowPowerMode::Enabled),
&ccdr.clocks,
);
timer2.listen(Event::TimeOut);
let mut timer3 = ctx
.device
.LPTIM3
.timer(
MilliSeconds::from_ticks(1000).into_rate(),
// Run in LPTIM in D3 / SRD autonomous mode
ccdr.peripheral.LPTIM3.low_power(LowPowerMode::Autonomous),
&ccdr.clocks,
)
.pause();
timer3.listen(Event::TimeOut);
let timer3 = timer3.resume();
// GPIO
let gpioc = ctx.device.GPIOC.split(ccdr.peripheral.GPIOC);
// Enter CStop mode
let mut scb = ctx.core.SCB;
scb.set_sleepdeep();
// Wakeup
let mut exti = ctx.device.EXTI;
let mut wakeup = gpioc.pc13.into_floating_input();
wakeup.make_interrupt_source(&mut syscfg);
wakeup.trigger_on_edge(&mut exti, Edge::Rising);
wakeup.enable_interrupt(&mut exti);
// LEDs
let mut led1 = gpioc.pc2.into_push_pull_output();
let mut led2 = gpioc.pc3.into_push_pull_output();
let mut led3 = gpioc.pc4.into_push_pull_output();
led1.set_high();
led2.set_high();
led3.set_high();
(
SharedResources {},
LocalResources {
led1,
led2,
led3,
timer1,
timer2,
timer3,
},
init::Monotonics(),
)
}
// RTIC inserts a default idle loop that calls asm::wfi()
#[task(binds = EXTI15_10, local = [], priority = 1)]
fn exti15_10_interrupt(_: exti15_10_interrupt::Context) {
// Once the wakeup is triggered, we loop here forever
}
#[task(binds = TIM1_UP, local = [led1, timer1], priority = 2)]
fn timer1_tick(ctx: timer1_tick::Context) {
ctx.local.timer1.clear_irq();
ctx.local.led1.toggle();
}
#[task(binds = TIM2, local = [led2, timer2], priority = 2)]
fn timer2_tick(ctx: timer2_tick::Context) {
ctx.local.timer2.clear_irq();
ctx.local.led2.toggle();
}
#[task(binds = LPTIM3, local = [led3, timer3], priority = 2)]
fn timer3_tick(ctx: timer3_tick::Context) {
ctx.local.timer3.clear_irq();
ctx.local.led3.toggle();
}
}