diff options
| author | Eric Yanush <[email protected]> | 2024-04-22 13:54:15 -0600 |
|---|---|---|
| committer | Eric Yanush <[email protected]> | 2024-04-22 14:04:39 -0600 |
| commit | e65503e25537ba872f02137713bdc4e5bf645a13 (patch) | |
| tree | b6740ada4a8b6bcd68866413bbcb4542d297867b | |
| parent | 3e00c1ac52ac847db44f83b6d94d493356a990ff (diff) | |
Add sleep/wakeup handling for bxCAN peripherals
| -rw-r--r-- | embassy-stm32/src/can/bxcan/mod.rs | 48 |
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. |
