1use crate::{
4 gpio::*,
5 rcc::{Enable, Rcc},
6 stm32::PWR,
7};
8
9pub enum LowPowerMode {
10 StopMode1 = 0b000,
11 StopMode2 = 0b001,
12 Standby = 0b011,
13 Shutdown = 0b111,
14}
15
16pub enum PowerMode {
17 Run,
18 LowPower(LowPowerMode),
19 UltraLowPower(LowPowerMode),
20}
21
22pub enum WakeUp {
23 InternalLine,
24 Line1,
25 Line2,
26 Line4,
28 Line5,
29 Line6,
30}
31
32pub struct Power {
33 rb: PWR,
34}
35
36impl Power {
37 pub fn new(pwr: PWR, rcc: &mut Rcc) -> Self {
38 PWR::enable(rcc);
39 Self { rb: pwr }
40 }
41
42 pub fn get_standby_flag(&mut self) -> bool {
43 self.rb.sr1.read().sbf().bit_is_set()
44 }
45
46 pub fn get_wakeup_flag<L: Into<WakeUp>>(&self, lane: L) -> bool {
47 match lane.into() {
48 WakeUp::Line1 => self.rb.sr1.read().wuf1().bit_is_set(),
49 WakeUp::Line2 => self.rb.sr1.read().wuf2().bit_is_set(),
50 WakeUp::Line4 => self.rb.sr1.read().wuf4().bit_is_set(),
51 WakeUp::Line5 => self.rb.sr1.read().wuf5().bit_is_set(),
52 WakeUp::Line6 => self.rb.sr1.read().wuf6().bit_is_set(),
53 _ => false,
54 }
55 }
56
57 pub fn clear_wakeup_flag<L: Into<WakeUp>>(&mut self, lane: L) {
58 match lane.into() {
59 WakeUp::Line1 => self.rb.scr.write(|w| w.cwuf1().set_bit()),
60 WakeUp::Line2 => self.rb.scr.write(|w| w.cwuf2().set_bit()),
61 WakeUp::Line4 => self.rb.scr.write(|w| w.cwuf4().set_bit()),
62 WakeUp::Line5 => self.rb.scr.write(|w| w.cwuf5().set_bit()),
63 WakeUp::Line6 => self.rb.scr.write(|w| w.cwuf6().set_bit()),
64 _ => {}
65 }
66 }
67
68 pub fn clear_standby_flag(&mut self) {
69 if self.rb.sr1.read().sbf().bit_is_set() {
70 self.rb.scr.write(|w| w.csbf().set_bit());
71 }
72 }
73
74 pub fn enable_wakeup_lane<L: Into<WakeUp>>(&mut self, lane: L, edge: SignalEdge) {
75 assert!(edge != SignalEdge::All);
76
77 let edge = edge == SignalEdge::Falling;
78 match lane.into() {
79 WakeUp::Line1 => {
80 self.rb.cr3.modify(|_, w| w.ewup1().set_bit());
81 self.rb.cr4.modify(|_, w| w.wp1().bit(edge));
82 }
83 WakeUp::Line2 => {
84 self.rb.cr3.modify(|_, w| w.ewup2().set_bit());
85 self.rb.cr4.modify(|_, w| w.wp2().bit(edge));
86 }
87 WakeUp::Line4 => {
88 self.rb.cr3.modify(|_, w| w.ewup4().set_bit());
89 self.rb.cr4.modify(|_, w| w.wp4().bit(edge));
90 }
91 WakeUp::Line5 => {
92 self.rb.cr3.modify(|_, w| w.ewup5().set_bit());
93 self.rb.cr4.modify(|_, w| w.wp5().bit(edge));
94 }
95 WakeUp::Line6 => {
96 self.rb.cr3.modify(|_, w| w.ewup6().set_bit());
97 self.rb.cr4.modify(|_, w| w.wp6().bit(edge));
98 }
99 WakeUp::InternalLine => self.rb.cr3.modify(|_, w| w.eiwul().set_bit()),
100 }
101 }
102
103 pub fn disable_wakeup_lane<L: Into<WakeUp>>(&mut self, lane: L) {
104 match lane.into() {
105 WakeUp::Line1 => self.rb.cr3.modify(|_, w| w.ewup1().clear_bit()),
106 WakeUp::Line2 => self.rb.cr3.modify(|_, w| w.ewup2().clear_bit()),
107 WakeUp::Line4 => self.rb.cr3.modify(|_, w| w.ewup4().clear_bit()),
108 WakeUp::Line5 => self.rb.cr3.modify(|_, w| w.ewup5().clear_bit()),
109 WakeUp::Line6 => self.rb.cr3.modify(|_, w| w.ewup6().clear_bit()),
110 WakeUp::InternalLine => self.rb.cr3.modify(|_, w| w.eiwul().clear_bit()),
111 }
112 }
113
114 pub fn set_mode(&mut self, mode: PowerMode) {
115 match mode {
116 PowerMode::Run => {
117 self.rb.cr1.modify(|_, w| w.lpr().clear_bit());
118 while !self.rb.sr2.read().reglpf().bit_is_clear() {}
119 }
120 PowerMode::LowPower(sm) => {
121 self.rb.cr3.modify(|_, w| w.ulpen().clear_bit());
122 self.rb
123 .cr1
124 .modify(|_, w| unsafe { w.lpr().set_bit().lpms().bits(sm as u8) });
125 while !self.rb.sr2.read().reglps().bit_is_set()
126 || !self.rb.sr2.read().reglpf().bit_is_set()
127 {}
128 }
129 PowerMode::UltraLowPower(sm) => {
130 self.rb.cr3.modify(|_, w| w.ulpen().set_bit());
131 self.rb
132 .cr1
133 .modify(|_, w| unsafe { w.lpr().set_bit().lpms().bits(sm as u8) });
134 while !self.rb.sr2.read().reglps().bit_is_set()
135 || !self.rb.sr2.read().reglpf().bit_is_set()
136 {}
137 }
138 }
139 }
140}
141
142macro_rules! wakeup_pins {
143 ($($PIN:path: $line:expr,)+) => {
144 $(
145 impl<M> From<&$PIN> for WakeUp {
146 fn from(_: &$PIN) -> Self {
147 $line
148 }
149 }
150 )+
151 }
152}
153
154wakeup_pins! {
155 PA0<M>: WakeUp::Line1,
156 PA4<M>: WakeUp::Line2,
157 PC13<M>: WakeUp::Line2,
158 PA2<M>: WakeUp::Line4,
159 PC5<M>: WakeUp::Line5,
160 PB5<M>: WakeUp::Line6,
161}
162
163pub trait PowerExt {
164 fn constrain(self, rcc: &mut Rcc) -> Power;
165}
166
167impl PowerExt for PWR {
168 fn constrain(self, rcc: &mut Rcc) -> Power {
169 Power::new(self, rcc)
170 }
171}