diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-04-22 22:57:22 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-04-22 22:57:22 +0000 |
| commit | 511bee7230d319abfef02b1ac8bfb21e1d2e83d8 (patch) | |
| tree | c70d2e604c6846d39c6912bee1449a14658037c5 /embassy-stm32 | |
| parent | e581c9f027e981622ccd13409992652bd7a68dfd (diff) | |
| parent | 5c56aff9c263308ccc866082bfbcfff2dadf80c4 (diff) | |
Merge pull request #2854 from ericyanush/feat/add-bxcan-sleep-wakeup
Add stm32 bxCAN sleep/wakeup functionality
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/can/bxcan/mod.rs | 65 | ||||
| -rw-r--r-- | embassy-stm32/src/can/bxcan/registers.rs | 16 |
2 files changed, 77 insertions, 4 deletions
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 65fd0e9c2..912634b84 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs | |||
| @@ -67,12 +67,23 @@ pub struct SceInterruptHandler<T: Instance> { | |||
| 67 | 67 | ||
| 68 | impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { | 68 | impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { |
| 69 | unsafe fn on_interrupt() { | 69 | unsafe fn on_interrupt() { |
| 70 | // info!("sce irq"); | 70 | info!("sce irq"); |
| 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(|v| v.set_erri(true)); | 75 | msr.modify(|m| m.set_slaki(true)); |
| 76 | T::state().err_waker.wake(); | ||
| 77 | } else if msr_val.erri() { | ||
| 78 | info!("Error interrupt"); | ||
| 79 | // Disable the interrupt, but don't acknowledge the error, so that it can be | ||
| 80 | // forwarded off the the bus message consumer. If we don't provide some way for | ||
| 81 | // downstream code to determine that it has already provided this bus error instance | ||
| 82 | // to the bus message consumer, we are doomed to re-provide a single error instance for | ||
| 83 | // an indefinite amount of time. | ||
| 84 | let ier = T::regs().ier(); | ||
| 85 | ier.modify(|i| i.set_errie(false)); | ||
| 86 | |||
| 76 | T::state().err_waker.wake(); | 87 | T::state().err_waker.wake(); |
| 77 | } | 88 | } |
| 78 | } | 89 | } |
| @@ -180,6 +191,10 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 180 | w.set_fmpie(0, true); | 191 | w.set_fmpie(0, true); |
| 181 | w.set_fmpie(1, true); | 192 | w.set_fmpie(1, true); |
| 182 | w.set_tmeie(true); | 193 | w.set_tmeie(true); |
| 194 | w.set_bofie(true); | ||
| 195 | w.set_epvie(true); | ||
| 196 | w.set_ewgie(true); | ||
| 197 | w.set_lecie(true); | ||
| 183 | }); | 198 | }); |
| 184 | 199 | ||
| 185 | T::regs().mcr().write(|w| { | 200 | T::regs().mcr().write(|w| { |
| @@ -239,6 +254,50 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 239 | } | 254 | } |
| 240 | } | 255 | } |
| 241 | 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 | }) | ||
| 296 | .await; | ||
| 297 | |||
| 298 | T::regs().ier().modify(|i| i.set_slkie(false)); | ||
| 299 | } | ||
| 300 | |||
| 242 | /// Queues the message to be sent. | 301 | /// Queues the message to be sent. |
| 243 | /// | 302 | /// |
| 244 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | 303 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. |
diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs index 732567797..446f3ad6f 100644 --- a/embassy-stm32/src/can/bxcan/registers.rs +++ b/embassy-stm32/src/can/bxcan/registers.rs | |||
| @@ -145,7 +145,21 @@ impl Registers { | |||
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | pub fn curr_error(&self) -> Option<BusError> { | 147 | pub fn curr_error(&self) -> Option<BusError> { |
| 148 | let err = { self.0.esr().read() }; | 148 | if !self.0.msr().read().erri() { |
| 149 | // This ensures that once a single error instance has | ||
| 150 | // been acknowledged and forwared to the bus message consumer | ||
| 151 | // we don't continue to re-forward the same error occurrance for an | ||
| 152 | // in-definite amount of time. | ||
| 153 | return None; | ||
| 154 | } | ||
| 155 | |||
| 156 | // Since we have not already acknowledge the error, and the interrupt was | ||
| 157 | // disabled in the ISR, we will acknowledge the current error and re-enable the interrupt | ||
| 158 | // so futher errors are captured | ||
| 159 | self.0.msr().modify(|m| m.set_erri(true)); | ||
| 160 | self.0.ier().modify(|i| i.set_errie(true)); | ||
| 161 | |||
| 162 | let err = self.0.esr().read(); | ||
| 149 | if err.boff() { | 163 | if err.boff() { |
| 150 | return Some(BusError::BusOff); | 164 | return Some(BusError::BusOff); |
| 151 | } else if err.epvf() { | 165 | } else if err.epvf() { |
