aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Yanush <[email protected]>2024-04-22 13:54:15 -0600
committerEric Yanush <[email protected]>2024-04-22 14:04:39 -0600
commite65503e25537ba872f02137713bdc4e5bf645a13 (patch)
treeb6740ada4a8b6bcd68866413bbcb4542d297867b
parent3e00c1ac52ac847db44f83b6d94d493356a990ff (diff)
Add sleep/wakeup handling for bxCAN peripherals
-rw-r--r--embassy-stm32/src/can/bxcan/mod.rs48
1 files changed, 47 insertions, 1 deletions
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs
index fa408c260..342040c25 100644
--- a/embassy-stm32/src/can/bxcan/mod.rs
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -71,7 +71,10 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
71 let msr = T::regs().msr(); 71 let msr = T::regs().msr();
72 let msr_val = msr.read(); 72 let msr_val = msr.read();
73 73
74 if msr_val.erri() { 74 if msr_val.slaki() {
75 msr.modify(|m| m.set_slaki(true));
76 T::state().err_waker.wake();
77 } else if msr_val.erri() {
75 info!("Error interrupt"); 78 info!("Error interrupt");
76 // Disable the interrupt, but don't acknowledge the error, so that it can be 79 // Disable the interrupt, but don't acknowledge the error, so that it can be
77 // forwarded off the the bus message consumer. If we don't provide some way for 80 // forwarded off the the bus message consumer. If we don't provide some way for
@@ -251,6 +254,49 @@ impl<'d, T: Instance> Can<'d, T> {
251 } 254 }
252 } 255 }
253 256
257 /// Enables or disables the peripheral from automatically wakeup when a SOF is detected on the bus
258 /// while the peripheral is in sleep mode
259 pub fn set_automatic_wakeup(&mut self, enabled: bool) {
260 Registers(T::regs()).set_automatic_wakeup(enabled);
261 }
262
263 /// Manually wake the peripheral from sleep mode.
264 ///
265 /// Waking the peripheral manually does not trigger a wake-up interrupt.
266 /// This will wait until the peripheral has acknowledged it has awoken from sleep mode
267 pub fn wakeup(&mut self) {
268 Registers(T::regs()).wakeup()
269 }
270
271 /// Check if the peripheral is currently in sleep mode
272 pub fn is_sleeping(&self) -> bool {
273 T::regs().msr().read().slak()
274 }
275
276 /// Put the peripheral in sleep mode
277 ///
278 /// When the peripherial is in sleep mode, messages can still be queued for transmission
279 /// and any previously received messages can be read from the receive FIFOs, however
280 /// no messages will be transmitted and no additional messages will be received.
281 ///
282 /// If the peripheral has automatic wakeup enabled, when a Start-of-Frame is detected
283 /// the peripheral will automatically wake and receive the incoming message.
284 pub async fn sleep(&mut self) {
285 T::regs().ier().modify(|i| i.set_slkie(true));
286 T::regs().mcr().modify(|m| m.set_sleep(true));
287
288 poll_fn(|cx| {
289 T::state().err_waker.register(cx.waker());
290 if self.is_sleeping() {
291 Poll::Ready(())
292 } else {
293 Poll::Pending
294 }
295 }).await;
296
297 T::regs().ier().modify(|i| i.set_slkie(false));
298 }
299
254 /// Queues the message to be sent. 300 /// Queues the message to be sent.
255 /// 301 ///
256 /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. 302 /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.