diff options
| author | xoviat <[email protected]> | 2023-05-29 19:09:52 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2023-05-29 19:09:52 -0500 |
| commit | f8d35806dc773a6310a60115fbf90f48fe409207 (patch) | |
| tree | 34268d37c9bf9457d11fbf59040d4a64ff344121 | |
| parent | 403cbb1dc955376237f035e841d387d947f2181f (diff) | |
stm32/can: move to irq binding use embassy channel
| -rw-r--r-- | embassy-stm32/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/can/bxcan.rs | 176 |
2 files changed, 101 insertions, 76 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 5d4b26a36..4e29bb32f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -69,7 +69,6 @@ cfg-if = "1.0.0" | |||
| 69 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } | 69 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } |
| 70 | chrono = { version = "^0.4", default-features = false, optional = true} | 70 | chrono = { version = "^0.4", default-features = false, optional = true} |
| 71 | bit_field = "0.10.2" | 71 | bit_field = "0.10.2" |
| 72 | heapless = { version = "0.7.5", default-features = false } | ||
| 73 | 72 | ||
| 74 | [dev-dependencies] | 73 | [dev-dependencies] |
| 75 | critical-section = { version = "1.1", features = ["std"] } | 74 | critical-section = { version = "1.1", features = ["std"] } |
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 734efdc02..8ae1dcb94 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -1,17 +1,73 @@ | |||
| 1 | use core::future::poll_fn; | 1 | use core::future::poll_fn; |
| 2 | use core::marker::PhantomData; | ||
| 2 | use core::ops::{Deref, DerefMut}; | 3 | use core::ops::{Deref, DerefMut}; |
| 3 | use core::task::Poll; | 4 | use core::task::Poll; |
| 4 | 5 | ||
| 5 | pub use bxcan; | 6 | pub use bxcan; |
| 6 | use bxcan::{Data, ExtendedId, Frame, Id, StandardId}; | 7 | use bxcan::{Data, ExtendedId, Frame, Id, StandardId}; |
| 8 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 7 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 10 | use futures::FutureExt; | ||
| 8 | 11 | ||
| 9 | use crate::gpio::sealed::AFType; | 12 | use crate::gpio::sealed::AFType; |
| 10 | use crate::interrupt::InterruptExt; | 13 | use crate::interrupt::InterruptExt; |
| 11 | use crate::pac::can::vals::{Lec, RirIde}; | 14 | use crate::pac::can::vals::{Lec, RirIde}; |
| 12 | use crate::rcc::RccPeripheral; | 15 | use crate::rcc::RccPeripheral; |
| 13 | use crate::time::Hertz; | 16 | use crate::time::Hertz; |
| 14 | use crate::{peripherals, Peripheral}; | 17 | use crate::{interrupt, peripherals, Peripheral}; |
| 18 | |||
| 19 | /// Interrupt handler. | ||
| 20 | pub struct TxInterruptHandler<T: Instance> { | ||
| 21 | _phantom: PhantomData<T>, | ||
| 22 | } | ||
| 23 | |||
| 24 | impl<T: Instance> interrupt::Handler<T::TXInterrupt> for TxInterruptHandler<T> { | ||
| 25 | unsafe fn on_interrupt() { | ||
| 26 | T::regs().tsr().write(|v| { | ||
| 27 | v.set_rqcp(0, true); | ||
| 28 | v.set_rqcp(1, true); | ||
| 29 | v.set_rqcp(2, true); | ||
| 30 | }); | ||
| 31 | |||
| 32 | T::state().tx_waker.wake(); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | pub struct Rx0InterruptHandler<T: Instance> { | ||
| 37 | _phantom: PhantomData<T>, | ||
| 38 | } | ||
| 39 | |||
| 40 | impl<T: Instance> interrupt::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { | ||
| 41 | unsafe fn on_interrupt() { | ||
| 42 | Can::<T>::receive_fifo(RxFifo::Fifo0); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | pub struct Rx1InterruptHandler<T: Instance> { | ||
| 47 | _phantom: PhantomData<T>, | ||
| 48 | } | ||
| 49 | |||
| 50 | impl<T: Instance> interrupt::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { | ||
| 51 | unsafe fn on_interrupt() { | ||
| 52 | Can::<T>::receive_fifo(RxFifo::Fifo1); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | pub struct SceInterruptHandler<T: Instance> { | ||
| 57 | _phantom: PhantomData<T>, | ||
| 58 | } | ||
| 59 | |||
| 60 | impl<T: Instance> interrupt::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { | ||
| 61 | unsafe fn on_interrupt() { | ||
| 62 | let msr = T::regs().msr(); | ||
| 63 | let msr_val = msr.read(); | ||
| 64 | |||
| 65 | if msr_val.erri() { | ||
| 66 | msr.modify(|v| v.set_erri(true)); | ||
| 67 | T::state().err_waker.wake(); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 15 | 71 | ||
| 16 | pub struct Can<'d, T: Instance> { | 72 | pub struct Can<'d, T: Instance> { |
| 17 | can: bxcan::Can<BxcanInstance<'d, T>>, | 73 | can: bxcan::Can<BxcanInstance<'d, T>>, |
| @@ -64,12 +120,13 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 64 | peri: impl Peripheral<P = T> + 'd, | 120 | peri: impl Peripheral<P = T> + 'd, |
| 65 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 121 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 66 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 122 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 67 | tx_irq: impl Peripheral<P = T::TXInterrupt> + 'd, | 123 | _irqs: impl interrupt::Binding<T::TXInterrupt, TxInterruptHandler<T>> |
| 68 | rx0_irq: impl Peripheral<P = T::RX0Interrupt> + 'd, | 124 | + interrupt::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>> |
| 69 | rx1_irq: impl Peripheral<P = T::RX1Interrupt> + 'd, | 125 | + interrupt::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>> |
| 70 | sce_irq: impl Peripheral<P = T::SCEInterrupt> + 'd, | 126 | + interrupt::Binding<T::SCEInterrupt, SceInterruptHandler<T>> |
| 127 | + 'd, | ||
| 71 | ) -> Self { | 128 | ) -> Self { |
| 72 | into_ref!(peri, rx, tx, tx_irq, rx0_irq, rx1_irq, sce_irq); | 129 | into_ref!(peri, rx, tx); |
| 73 | 130 | ||
| 74 | unsafe { | 131 | unsafe { |
| 75 | rx.set_as_af(rx.af_num(), AFType::Input); | 132 | rx.set_as_af(rx.af_num(), AFType::Input); |
| @@ -79,21 +136,19 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 79 | T::enable(); | 136 | T::enable(); |
| 80 | T::reset(); | 137 | T::reset(); |
| 81 | 138 | ||
| 82 | tx_irq.unpend(); | 139 | unsafe { |
| 83 | tx_irq.set_handler(Self::tx_interrupt); | 140 | T::TXInterrupt::steal().unpend(); |
| 84 | tx_irq.enable(); | 141 | T::TXInterrupt::steal().enable(); |
| 85 | 142 | ||
| 86 | rx0_irq.unpend(); | 143 | T::RX0Interrupt::steal().unpend(); |
| 87 | rx0_irq.set_handler(Self::rx0_interrupt); | 144 | T::RX0Interrupt::steal().enable(); |
| 88 | rx0_irq.enable(); | ||
| 89 | 145 | ||
| 90 | rx1_irq.unpend(); | 146 | T::RX1Interrupt::steal().unpend(); |
| 91 | rx1_irq.set_handler(Self::rx1_interrupt); | 147 | T::RX1Interrupt::steal().enable(); |
| 92 | rx1_irq.enable(); | ||
| 93 | 148 | ||
| 94 | sce_irq.unpend(); | 149 | T::SCEInterrupt::steal().unpend(); |
| 95 | sce_irq.set_handler(Self::sce_interrupt); | 150 | T::SCEInterrupt::steal().enable(); |
| 96 | sce_irq.enable(); | 151 | } |
| 97 | 152 | ||
| 98 | let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(); | 153 | let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(); |
| 99 | Self { can } | 154 | Self { can } |
| @@ -133,12 +188,11 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 133 | 188 | ||
| 134 | pub async fn receive_frame_or_error(&mut self) -> FrameOrError { | 189 | pub async fn receive_frame_or_error(&mut self) -> FrameOrError { |
| 135 | poll_fn(|cx| { | 190 | poll_fn(|cx| { |
| 136 | if let Some(frame) = T::state().rx_queue.dequeue() { | 191 | if let Poll::Ready(frame) = T::state().rx_queue.recv().poll_unpin(cx) { |
| 137 | return Poll::Ready(FrameOrError::Frame(frame)); | 192 | return Poll::Ready(FrameOrError::Frame(frame)); |
| 138 | } else if let Some(err) = self.curr_error() { | 193 | } else if let Some(err) = self.curr_error() { |
| 139 | return Poll::Ready(FrameOrError::Error(err)); | 194 | return Poll::Ready(FrameOrError::Error(err)); |
| 140 | } | 195 | } |
| 141 | T::state().rx_waker.register(cx.waker()); | ||
| 142 | T::state().err_waker.register(cx.waker()); | 196 | T::state().err_waker.register(cx.waker()); |
| 143 | Poll::Pending | 197 | Poll::Pending |
| 144 | }) | 198 | }) |
| @@ -159,69 +213,42 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 159 | None | 213 | None |
| 160 | } | 214 | } |
| 161 | 215 | ||
| 162 | unsafe fn sce_interrupt(_: *mut ()) { | ||
| 163 | let msr = T::regs().msr(); | ||
| 164 | let msr_val = msr.read(); | ||
| 165 | |||
| 166 | if msr_val.erri() { | ||
| 167 | msr.modify(|v| v.set_erri(true)); | ||
| 168 | T::state().err_waker.wake(); | ||
| 169 | return; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | unsafe fn tx_interrupt(_: *mut ()) { | ||
| 174 | T::regs().tsr().write(|v| { | ||
| 175 | v.set_rqcp(0, true); | ||
| 176 | v.set_rqcp(1, true); | ||
| 177 | v.set_rqcp(2, true); | ||
| 178 | }); | ||
| 179 | T::state().tx_waker.wake(); | ||
| 180 | } | ||
| 181 | |||
| 182 | unsafe fn rx0_interrupt(_: *mut ()) { | ||
| 183 | Self::receive_fifo(RxFifo::Fifo0); | ||
| 184 | } | ||
| 185 | |||
| 186 | unsafe fn rx1_interrupt(_: *mut ()) { | ||
| 187 | Self::receive_fifo(RxFifo::Fifi1); | ||
| 188 | } | ||
| 189 | |||
| 190 | unsafe fn receive_fifo(fifo: RxFifo) { | 216 | unsafe fn receive_fifo(fifo: RxFifo) { |
| 191 | let state = T::state(); | 217 | let state = T::state(); |
| 192 | let regs = T::regs(); | 218 | let regs = T::regs(); |
| 193 | let fifo_idx = match fifo { | 219 | let fifo_idx = match fifo { |
| 194 | RxFifo::Fifo0 => 0usize, | 220 | RxFifo::Fifo0 => 0usize, |
| 195 | RxFifo::Fifi1 => 1usize, | 221 | RxFifo::Fifo1 => 1usize, |
| 196 | }; | 222 | }; |
| 197 | let rfr = regs.rfr(fifo_idx); | 223 | let rfr = regs.rfr(fifo_idx); |
| 198 | let fifo = regs.rx(fifo_idx); | 224 | let fifo = regs.rx(fifo_idx); |
| 199 | 225 | ||
| 200 | // If there are no pending messages, there is nothing to do | 226 | loop { |
| 201 | if rfr.read().fmp() == 0 { | 227 | // If there are no pending messages, there is nothing to do |
| 202 | return; | 228 | if rfr.read().fmp() == 0 { |
| 203 | } | 229 | return; |
| 230 | } | ||
| 204 | 231 | ||
| 205 | let rir = fifo.rir().read(); | 232 | let rir = fifo.rir().read(); |
| 206 | let id = if rir.ide() == RirIde::STANDARD { | 233 | let id = if rir.ide() == RirIde::STANDARD { |
| 207 | Id::from(StandardId::new_unchecked(rir.stid())) | 234 | Id::from(StandardId::new_unchecked(rir.stid())) |
| 208 | } else { | 235 | } else { |
| 209 | Id::from(ExtendedId::new_unchecked(rir.exid())) | 236 | Id::from(ExtendedId::new_unchecked(rir.exid())) |
| 210 | }; | 237 | }; |
| 211 | let data_len = fifo.rdtr().read().dlc() as usize; | 238 | let data_len = fifo.rdtr().read().dlc() as usize; |
| 212 | let mut data: [u8; 8] = [0; 8]; | 239 | let mut data: [u8; 8] = [0; 8]; |
| 213 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | 240 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); |
| 214 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | 241 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); |
| 215 | 242 | ||
| 216 | let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap()); | 243 | let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap()); |
| 217 | 244 | ||
| 218 | rfr.modify(|v| v.set_rfom(true)); | 245 | rfr.modify(|v| v.set_rfom(true)); |
| 219 | 246 | ||
| 220 | match state.rx_queue.enqueue(frame) { | 247 | /* |
| 221 | Ok(_) => {} | 248 | NOTE: consensus was reached that if rx_queue is full, packets should be dropped |
| 222 | Err(_) => defmt::error!("RX queue overflow"), | 249 | */ |
| 250 | let _ = state.rx_queue.try_send(frame); | ||
| 223 | } | 251 | } |
| 224 | state.rx_waker.wake(); | ||
| 225 | } | 252 | } |
| 226 | 253 | ||
| 227 | pub fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { | 254 | pub fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { |
| @@ -318,7 +345,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 318 | 345 | ||
| 319 | enum RxFifo { | 346 | enum RxFifo { |
| 320 | Fifo0, | 347 | Fifo0, |
| 321 | Fifi1, | 348 | Fifo1, |
| 322 | } | 349 | } |
| 323 | 350 | ||
| 324 | impl<'d, T: Instance> Drop for Can<'d, T> { | 351 | impl<'d, T: Instance> Drop for Can<'d, T> { |
| @@ -345,23 +372,22 @@ impl<'d, T: Instance> DerefMut for Can<'d, T> { | |||
| 345 | } | 372 | } |
| 346 | 373 | ||
| 347 | pub(crate) mod sealed { | 374 | pub(crate) mod sealed { |
| 375 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 376 | use embassy_sync::channel::Channel; | ||
| 348 | use embassy_sync::waitqueue::AtomicWaker; | 377 | use embassy_sync::waitqueue::AtomicWaker; |
| 349 | use heapless::mpmc::Q8; | ||
| 350 | 378 | ||
| 351 | pub struct State { | 379 | pub struct State { |
| 352 | pub tx_waker: AtomicWaker, | 380 | pub tx_waker: AtomicWaker, |
| 353 | pub rx_waker: AtomicWaker, | ||
| 354 | pub err_waker: AtomicWaker, | 381 | pub err_waker: AtomicWaker, |
| 355 | pub rx_queue: Q8<bxcan::Frame>, | 382 | pub rx_queue: Channel<CriticalSectionRawMutex, bxcan::Frame, 32>, |
| 356 | } | 383 | } |
| 357 | 384 | ||
| 358 | impl State { | 385 | impl State { |
| 359 | pub const fn new() -> Self { | 386 | pub const fn new() -> Self { |
| 360 | Self { | 387 | Self { |
| 361 | tx_waker: AtomicWaker::new(), | 388 | tx_waker: AtomicWaker::new(), |
| 362 | rx_waker: AtomicWaker::new(), | ||
| 363 | err_waker: AtomicWaker::new(), | 389 | err_waker: AtomicWaker::new(), |
| 364 | rx_queue: Q8::new(), | 390 | rx_queue: Channel::new(), |
| 365 | } | 391 | } |
| 366 | } | 392 | } |
| 367 | } | 393 | } |
