diff options
| author | xoviat <[email protected]> | 2023-05-30 21:14:25 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2023-05-30 21:14:25 -0500 |
| commit | 16bfbd4e99dbc765c93610557a7857a9013ff756 (patch) | |
| tree | 3103c09168aa1c672daa47b97eb86e663333e057 /embassy-stm32 | |
| parent | f8d35806dc773a6310a60115fbf90f48fe409207 (diff) | |
stm32/can: add hw test and cleanup
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/can/bxcan.rs | 78 |
1 files changed, 36 insertions, 42 deletions
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 8ae1dcb94..08ba783ff 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -39,6 +39,7 @@ pub struct Rx0InterruptHandler<T: Instance> { | |||
| 39 | 39 | ||
| 40 | impl<T: Instance> interrupt::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { | 40 | impl<T: Instance> interrupt::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { |
| 41 | unsafe fn on_interrupt() { | 41 | unsafe fn on_interrupt() { |
| 42 | // info!("rx0 irq"); | ||
| 42 | Can::<T>::receive_fifo(RxFifo::Fifo0); | 43 | Can::<T>::receive_fifo(RxFifo::Fifo0); |
| 43 | } | 44 | } |
| 44 | } | 45 | } |
| @@ -49,6 +50,7 @@ pub struct Rx1InterruptHandler<T: Instance> { | |||
| 49 | 50 | ||
| 50 | impl<T: Instance> interrupt::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { | 51 | impl<T: Instance> interrupt::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { |
| 51 | unsafe fn on_interrupt() { | 52 | unsafe fn on_interrupt() { |
| 53 | // info!("rx1 irq"); | ||
| 52 | Can::<T>::receive_fifo(RxFifo::Fifo1); | 54 | Can::<T>::receive_fifo(RxFifo::Fifo1); |
| 53 | } | 55 | } |
| 54 | } | 56 | } |
| @@ -59,6 +61,7 @@ pub struct SceInterruptHandler<T: Instance> { | |||
| 59 | 61 | ||
| 60 | impl<T: Instance> interrupt::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { | 62 | impl<T: Instance> interrupt::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { |
| 61 | unsafe fn on_interrupt() { | 63 | unsafe fn on_interrupt() { |
| 64 | // info!("sce irq"); | ||
| 62 | let msr = T::regs().msr(); | 65 | let msr = T::regs().msr(); |
| 63 | let msr_val = msr.read(); | 66 | let msr_val = msr.read(); |
| 64 | 67 | ||
| @@ -87,36 +90,10 @@ pub enum BusError { | |||
| 87 | BusWarning, | 90 | BusWarning, |
| 88 | } | 91 | } |
| 89 | 92 | ||
| 90 | pub enum FrameOrError { | ||
| 91 | Frame(Frame), | ||
| 92 | Error(BusError), | ||
| 93 | } | ||
| 94 | |||
| 95 | impl<'d, T: Instance> Can<'d, T> { | 93 | impl<'d, T: Instance> Can<'d, T> { |
| 96 | /// Creates a new Bxcan instance, blocking for 11 recessive bits to sync with the CAN bus. | ||
| 97 | pub fn new( | ||
| 98 | peri: impl Peripheral<P = T> + 'd, | ||
| 99 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 100 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||
| 101 | ) -> Self { | ||
| 102 | into_ref!(peri, rx, tx); | ||
| 103 | |||
| 104 | unsafe { | ||
| 105 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 106 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 107 | } | ||
| 108 | |||
| 109 | T::enable(); | ||
| 110 | T::reset(); | ||
| 111 | |||
| 112 | Self { | ||
| 113 | can: bxcan::Can::builder(BxcanInstance(peri)).enable(), | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. | 94 | /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. |
| 118 | /// You must call [Can::enable_non_blocking] to use the peripheral. | 95 | /// You must call [Can::enable_non_blocking] to use the peripheral. |
| 119 | pub fn new_disabled( | 96 | pub fn new( |
| 120 | peri: impl Peripheral<P = T> + 'd, | 97 | peri: impl Peripheral<P = T> + 'd, |
| 121 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 98 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 122 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 99 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| @@ -137,6 +114,25 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 137 | T::reset(); | 114 | T::reset(); |
| 138 | 115 | ||
| 139 | unsafe { | 116 | unsafe { |
| 117 | use crate::pac::can::vals::{Errie, Fmpie, Tmeie}; | ||
| 118 | |||
| 119 | T::regs().ier().write(|w| { | ||
| 120 | // TODO: fix metapac | ||
| 121 | |||
| 122 | w.set_errie(Errie(1)); | ||
| 123 | w.set_fmpie(0, Fmpie(1)); | ||
| 124 | w.set_fmpie(1, Fmpie(1)); | ||
| 125 | w.set_tmeie(Tmeie(1)); | ||
| 126 | }); | ||
| 127 | |||
| 128 | T::regs().mcr().write(|w| { | ||
| 129 | // Enable timestamps on rx messages | ||
| 130 | |||
| 131 | w.set_ttcm(true); | ||
| 132 | }) | ||
| 133 | } | ||
| 134 | |||
| 135 | unsafe { | ||
| 140 | T::TXInterrupt::steal().unpend(); | 136 | T::TXInterrupt::steal().unpend(); |
| 141 | T::TXInterrupt::steal().enable(); | 137 | T::TXInterrupt::steal().enable(); |
| 142 | 138 | ||
| @@ -159,12 +155,8 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 159 | self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); | 155 | self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); |
| 160 | } | 156 | } |
| 161 | 157 | ||
| 162 | pub async fn transmit(&mut self, frame: &Frame) { | 158 | /// Queues the message to be sent but exerts backpressure |
| 163 | let tx_status = self.queue_transmit(frame).await; | 159 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { |
| 164 | self.wait_transission(tx_status.mailbox()).await; | ||
| 165 | } | ||
| 166 | |||
| 167 | async fn queue_transmit(&mut self, frame: &Frame) -> bxcan::TransmitStatus { | ||
| 168 | poll_fn(|cx| { | 160 | poll_fn(|cx| { |
| 169 | if let Ok(status) = self.can.transmit(frame) { | 161 | if let Ok(status) = self.can.transmit(frame) { |
| 170 | return Poll::Ready(status); | 162 | return Poll::Ready(status); |
| @@ -175,7 +167,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 175 | .await | 167 | .await |
| 176 | } | 168 | } |
| 177 | 169 | ||
| 178 | async fn wait_transission(&self, mb: bxcan::Mailbox) { | 170 | pub async fn flush(&self, mb: bxcan::Mailbox) { |
| 179 | poll_fn(|cx| unsafe { | 171 | poll_fn(|cx| unsafe { |
| 180 | if T::regs().tsr().read().tme(mb.index()) { | 172 | if T::regs().tsr().read().tme(mb.index()) { |
| 181 | return Poll::Ready(()); | 173 | return Poll::Ready(()); |
| @@ -186,12 +178,13 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 186 | .await; | 178 | .await; |
| 187 | } | 179 | } |
| 188 | 180 | ||
| 189 | pub async fn receive_frame_or_error(&mut self) -> FrameOrError { | 181 | /// Returns a tuple of the time the message was received and the message frame |
| 182 | pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> { | ||
| 190 | poll_fn(|cx| { | 183 | poll_fn(|cx| { |
| 191 | if let Poll::Ready(frame) = T::state().rx_queue.recv().poll_unpin(cx) { | 184 | if let Poll::Ready((time, frame)) = T::state().rx_queue.recv().poll_unpin(cx) { |
| 192 | return Poll::Ready(FrameOrError::Frame(frame)); | 185 | return Poll::Ready(Ok((time, frame))); |
| 193 | } else if let Some(err) = self.curr_error() { | 186 | } else if let Some(err) = self.curr_error() { |
| 194 | return Poll::Ready(FrameOrError::Error(err)); | 187 | return Poll::Ready(Err(err)); |
| 195 | } | 188 | } |
| 196 | T::state().err_waker.register(cx.waker()); | 189 | T::state().err_waker.register(cx.waker()); |
| 197 | Poll::Pending | 190 | Poll::Pending |
| @@ -240,6 +233,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 240 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | 233 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); |
| 241 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | 234 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); |
| 242 | 235 | ||
| 236 | let time = fifo.rdtr().read().time(); | ||
| 243 | let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap()); | 237 | let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap()); |
| 244 | 238 | ||
| 245 | rfr.modify(|v| v.set_rfom(true)); | 239 | rfr.modify(|v| v.set_rfom(true)); |
| @@ -247,11 +241,11 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 247 | /* | 241 | /* |
| 248 | NOTE: consensus was reached that if rx_queue is full, packets should be dropped | 242 | NOTE: consensus was reached that if rx_queue is full, packets should be dropped |
| 249 | */ | 243 | */ |
| 250 | let _ = state.rx_queue.try_send(frame); | 244 | let _ = state.rx_queue.try_send((time, frame)); |
| 251 | } | 245 | } |
| 252 | } | 246 | } |
| 253 | 247 | ||
| 254 | pub fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { | 248 | pub const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { |
| 255 | const BS1_MAX: u8 = 16; | 249 | const BS1_MAX: u8 = 16; |
| 256 | const BS2_MAX: u8 = 8; | 250 | const BS2_MAX: u8 = 8; |
| 257 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; | 251 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; |
| @@ -316,7 +310,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 316 | // - With rounding to zero | 310 | // - With rounding to zero |
| 317 | let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first | 311 | let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first |
| 318 | let mut bs2 = bs1_bs2_sum - bs1; | 312 | let mut bs2 = bs1_bs2_sum - bs1; |
| 319 | assert!(bs1_bs2_sum > bs1); | 313 | core::assert!(bs1_bs2_sum > bs1); |
| 320 | 314 | ||
| 321 | let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16; | 315 | let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16; |
| 322 | if sample_point_permill > MAX_SAMPLE_POINT_PERMILL { | 316 | if sample_point_permill > MAX_SAMPLE_POINT_PERMILL { |
| @@ -379,7 +373,7 @@ pub(crate) mod sealed { | |||
| 379 | pub struct State { | 373 | pub struct State { |
| 380 | pub tx_waker: AtomicWaker, | 374 | pub tx_waker: AtomicWaker, |
| 381 | pub err_waker: AtomicWaker, | 375 | pub err_waker: AtomicWaker, |
| 382 | pub rx_queue: Channel<CriticalSectionRawMutex, bxcan::Frame, 32>, | 376 | pub rx_queue: Channel<CriticalSectionRawMutex, (u16, bxcan::Frame), 32>, |
| 383 | } | 377 | } |
| 384 | 378 | ||
| 385 | impl State { | 379 | impl State { |
