diff options
| author | JuliDi <[email protected]> | 2023-06-21 11:52:53 +0200 |
|---|---|---|
| committer | JuliDi <[email protected]> | 2023-06-21 11:52:53 +0200 |
| commit | fdb3c3d6ffad31ffc61c66d0d8a6f4db70a1c32b (patch) | |
| tree | e15a31a2850e2d98284b33e0b4cc44e2b16cdbe5 /embassy-stm32 | |
| parent | 56ab6d9f143ecc3041ac9726e621eedea729ca4d (diff) | |
| parent | 2e625138ff8384a96f1f8a4d7a9c557b50353836 (diff) | |
Merge remote-tracking branch 'upstream/main'
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/can/bxcan.rs | 432 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/bdma.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/gpdma.rs | 1 |
3 files changed, 416 insertions, 18 deletions
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 85f6e99ac..88eef528f 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -1,22 +1,106 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::marker::PhantomData; | ||
| 1 | use core::ops::{Deref, DerefMut}; | 3 | use core::ops::{Deref, DerefMut}; |
| 4 | use core::task::Poll; | ||
| 2 | 5 | ||
| 3 | pub use bxcan; | 6 | pub use bxcan; |
| 7 | use bxcan::{Data, ExtendedId, Frame, Id, StandardId}; | ||
| 4 | use embassy_hal_common::{into_ref, PeripheralRef}; | 8 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 9 | use futures::FutureExt; | ||
| 5 | 10 | ||
| 6 | use crate::gpio::sealed::AFType; | 11 | use crate::gpio::sealed::AFType; |
| 12 | use crate::interrupt::typelevel::Interrupt; | ||
| 13 | use crate::pac::can::vals::{Lec, RirIde}; | ||
| 7 | use crate::rcc::RccPeripheral; | 14 | use crate::rcc::RccPeripheral; |
| 8 | use crate::{peripherals, Peripheral}; | 15 | use crate::time::Hertz; |
| 16 | use crate::{interrupt, peripherals, Peripheral}; | ||
| 17 | |||
| 18 | /// Interrupt handler. | ||
| 19 | pub struct TxInterruptHandler<T: Instance> { | ||
| 20 | _phantom: PhantomData<T>, | ||
| 21 | } | ||
| 22 | |||
| 23 | impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptHandler<T> { | ||
| 24 | unsafe fn on_interrupt() { | ||
| 25 | T::regs().tsr().write(|v| { | ||
| 26 | v.set_rqcp(0, true); | ||
| 27 | v.set_rqcp(1, true); | ||
| 28 | v.set_rqcp(2, true); | ||
| 29 | }); | ||
| 30 | |||
| 31 | T::state().tx_waker.wake(); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | pub struct Rx0InterruptHandler<T: Instance> { | ||
| 36 | _phantom: PhantomData<T>, | ||
| 37 | } | ||
| 38 | |||
| 39 | impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { | ||
| 40 | unsafe fn on_interrupt() { | ||
| 41 | // info!("rx0 irq"); | ||
| 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::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { | ||
| 51 | unsafe fn on_interrupt() { | ||
| 52 | // info!("rx1 irq"); | ||
| 53 | Can::<T>::receive_fifo(RxFifo::Fifo1); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | pub struct SceInterruptHandler<T: Instance> { | ||
| 58 | _phantom: PhantomData<T>, | ||
| 59 | } | ||
| 60 | |||
| 61 | impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { | ||
| 62 | unsafe fn on_interrupt() { | ||
| 63 | // info!("sce irq"); | ||
| 64 | let msr = T::regs().msr(); | ||
| 65 | let msr_val = msr.read(); | ||
| 66 | |||
| 67 | if msr_val.erri() { | ||
| 68 | msr.modify(|v| v.set_erri(true)); | ||
| 69 | T::state().err_waker.wake(); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | } | ||
| 9 | 73 | ||
| 10 | pub struct Can<'d, T: Instance> { | 74 | pub struct Can<'d, T: Instance> { |
| 11 | can: bxcan::Can<BxcanInstance<'d, T>>, | 75 | can: bxcan::Can<BxcanInstance<'d, T>>, |
| 12 | } | 76 | } |
| 13 | 77 | ||
| 78 | #[derive(Debug)] | ||
| 79 | pub enum BusError { | ||
| 80 | Stuff, | ||
| 81 | Form, | ||
| 82 | Acknowledge, | ||
| 83 | BitRecessive, | ||
| 84 | BitDominant, | ||
| 85 | Crc, | ||
| 86 | Software, | ||
| 87 | BusOff, | ||
| 88 | BusPassive, | ||
| 89 | BusWarning, | ||
| 90 | } | ||
| 91 | |||
| 14 | impl<'d, T: Instance> Can<'d, T> { | 92 | impl<'d, T: Instance> Can<'d, T> { |
| 15 | /// Creates a new Bxcan instance, blocking for 11 recessive bits to sync with the CAN bus. | 93 | /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. |
| 94 | /// You must call [Can::enable_non_blocking] to use the peripheral. | ||
| 16 | pub fn new( | 95 | pub fn new( |
| 17 | peri: impl Peripheral<P = T> + 'd, | 96 | peri: impl Peripheral<P = T> + 'd, |
| 18 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 97 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 19 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 98 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 99 | _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>> | ||
| 100 | + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>> | ||
| 101 | + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>> | ||
| 102 | + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>> | ||
| 103 | + 'd, | ||
| 20 | ) -> Self { | 104 | ) -> Self { |
| 21 | into_ref!(peri, rx, tx); | 105 | into_ref!(peri, rx, tx); |
| 22 | 106 | ||
| @@ -26,30 +110,242 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 26 | T::enable(); | 110 | T::enable(); |
| 27 | T::reset(); | 111 | T::reset(); |
| 28 | 112 | ||
| 29 | Self { | 113 | { |
| 30 | can: bxcan::Can::builder(BxcanInstance(peri)).enable(), | 114 | use crate::pac::can::vals::{Errie, Fmpie, Tmeie}; |
| 115 | |||
| 116 | T::regs().ier().write(|w| { | ||
| 117 | // TODO: fix metapac | ||
| 118 | |||
| 119 | w.set_errie(Errie(1)); | ||
| 120 | w.set_fmpie(0, Fmpie(1)); | ||
| 121 | w.set_fmpie(1, Fmpie(1)); | ||
| 122 | w.set_tmeie(Tmeie(1)); | ||
| 123 | }); | ||
| 124 | |||
| 125 | T::regs().mcr().write(|w| { | ||
| 126 | // Enable timestamps on rx messages | ||
| 127 | |||
| 128 | w.set_ttcm(true); | ||
| 129 | }); | ||
| 31 | } | 130 | } |
| 32 | } | ||
| 33 | 131 | ||
| 34 | /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. | 132 | unsafe { |
| 35 | /// You must call [Can::enable_non_blocking] to use the peripheral. | 133 | T::TXInterrupt::unpend(); |
| 36 | pub fn new_disabled( | 134 | T::TXInterrupt::enable(); |
| 37 | peri: impl Peripheral<P = T> + 'd, | 135 | |
| 38 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 136 | T::RX0Interrupt::unpend(); |
| 39 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 137 | T::RX0Interrupt::enable(); |
| 40 | ) -> Self { | 138 | |
| 41 | into_ref!(peri, rx, tx); | 139 | T::RX1Interrupt::unpend(); |
| 140 | T::RX1Interrupt::enable(); | ||
| 141 | |||
| 142 | T::SCEInterrupt::unpend(); | ||
| 143 | T::SCEInterrupt::enable(); | ||
| 144 | } | ||
| 42 | 145 | ||
| 43 | rx.set_as_af(rx.af_num(), AFType::Input); | 146 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 44 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | 147 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 45 | 148 | ||
| 46 | T::enable(); | 149 | let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(); |
| 47 | T::reset(); | 150 | Self { can } |
| 151 | } | ||
| 152 | |||
| 153 | pub fn set_bitrate(&mut self, bitrate: u32) { | ||
| 154 | let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); | ||
| 155 | self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); | ||
| 156 | } | ||
| 48 | 157 | ||
| 49 | Self { | 158 | /// Queues the message to be sent but exerts backpressure |
| 50 | can: bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(), | 159 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { |
| 160 | poll_fn(|cx| { | ||
| 161 | T::state().tx_waker.register(cx.waker()); | ||
| 162 | if let Ok(status) = self.can.transmit(frame) { | ||
| 163 | return Poll::Ready(status); | ||
| 164 | } | ||
| 165 | |||
| 166 | Poll::Pending | ||
| 167 | }) | ||
| 168 | .await | ||
| 169 | } | ||
| 170 | |||
| 171 | pub async fn flush(&self, mb: bxcan::Mailbox) { | ||
| 172 | poll_fn(|cx| { | ||
| 173 | T::state().tx_waker.register(cx.waker()); | ||
| 174 | if T::regs().tsr().read().tme(mb.index()) { | ||
| 175 | return Poll::Ready(()); | ||
| 176 | } | ||
| 177 | |||
| 178 | Poll::Pending | ||
| 179 | }) | ||
| 180 | .await; | ||
| 181 | } | ||
| 182 | |||
| 183 | /// Returns a tuple of the time the message was received and the message frame | ||
| 184 | pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> { | ||
| 185 | poll_fn(|cx| { | ||
| 186 | T::state().err_waker.register(cx.waker()); | ||
| 187 | if let Poll::Ready((time, frame)) = T::state().rx_queue.recv().poll_unpin(cx) { | ||
| 188 | return Poll::Ready(Ok((time, frame))); | ||
| 189 | } else if let Some(err) = self.curr_error() { | ||
| 190 | return Poll::Ready(Err(err)); | ||
| 191 | } | ||
| 192 | |||
| 193 | Poll::Pending | ||
| 194 | }) | ||
| 195 | .await | ||
| 196 | } | ||
| 197 | |||
| 198 | fn curr_error(&self) -> Option<BusError> { | ||
| 199 | let err = { T::regs().esr().read() }; | ||
| 200 | if err.boff() { | ||
| 201 | return Some(BusError::BusOff); | ||
| 202 | } else if err.epvf() { | ||
| 203 | return Some(BusError::BusPassive); | ||
| 204 | } else if err.ewgf() { | ||
| 205 | return Some(BusError::BusWarning); | ||
| 206 | } else if let Some(err) = err.lec().into_bus_err() { | ||
| 207 | return Some(err); | ||
| 51 | } | 208 | } |
| 209 | None | ||
| 52 | } | 210 | } |
| 211 | |||
| 212 | unsafe fn receive_fifo(fifo: RxFifo) { | ||
| 213 | let state = T::state(); | ||
| 214 | let regs = T::regs(); | ||
| 215 | let fifo_idx = match fifo { | ||
| 216 | RxFifo::Fifo0 => 0usize, | ||
| 217 | RxFifo::Fifo1 => 1usize, | ||
| 218 | }; | ||
| 219 | let rfr = regs.rfr(fifo_idx); | ||
| 220 | let fifo = regs.rx(fifo_idx); | ||
| 221 | |||
| 222 | loop { | ||
| 223 | // If there are no pending messages, there is nothing to do | ||
| 224 | if rfr.read().fmp() == 0 { | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | |||
| 228 | let rir = fifo.rir().read(); | ||
| 229 | let id = if rir.ide() == RirIde::STANDARD { | ||
| 230 | Id::from(StandardId::new_unchecked(rir.stid())) | ||
| 231 | } else { | ||
| 232 | let stid = (rir.stid() & 0x7FF) as u32; | ||
| 233 | let exid = rir.exid() & 0x3FFFF; | ||
| 234 | let id = (stid << 18) | (exid as u32); | ||
| 235 | Id::from(ExtendedId::new_unchecked(id)) | ||
| 236 | }; | ||
| 237 | let data_len = fifo.rdtr().read().dlc() as usize; | ||
| 238 | let mut data: [u8; 8] = [0; 8]; | ||
| 239 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | ||
| 240 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | ||
| 241 | |||
| 242 | let time = fifo.rdtr().read().time(); | ||
| 243 | let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap()); | ||
| 244 | |||
| 245 | rfr.modify(|v| v.set_rfom(true)); | ||
| 246 | |||
| 247 | /* | ||
| 248 | NOTE: consensus was reached that if rx_queue is full, packets should be dropped | ||
| 249 | */ | ||
| 250 | let _ = state.rx_queue.try_send((time, frame)); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | pub const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { | ||
| 255 | const BS1_MAX: u8 = 16; | ||
| 256 | const BS2_MAX: u8 = 8; | ||
| 257 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; | ||
| 258 | |||
| 259 | let periph_clock = periph_clock.0; | ||
| 260 | |||
| 261 | if can_bitrate < 1000 { | ||
| 262 | return None; | ||
| 263 | } | ||
| 264 | |||
| 265 | // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG | ||
| 266 | // CAN in Automation, 2003 | ||
| 267 | // | ||
| 268 | // According to the source, optimal quanta per bit are: | ||
| 269 | // Bitrate Optimal Maximum | ||
| 270 | // 1000 kbps 8 10 | ||
| 271 | // 500 kbps 16 17 | ||
| 272 | // 250 kbps 16 17 | ||
| 273 | // 125 kbps 16 17 | ||
| 274 | let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 }; | ||
| 275 | |||
| 276 | // Computing (prescaler * BS): | ||
| 277 | // BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual | ||
| 278 | // BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified | ||
| 279 | // let: | ||
| 280 | // BS = 1 + BS1 + BS2 -- Number of time quanta per bit | ||
| 281 | // PRESCALER_BS = PRESCALER * BS | ||
| 282 | // ==> | ||
| 283 | // PRESCALER_BS = PCLK / BITRATE | ||
| 284 | let prescaler_bs = periph_clock / can_bitrate; | ||
| 285 | |||
| 286 | // Searching for such prescaler value so that the number of quanta per bit is highest. | ||
| 287 | let mut bs1_bs2_sum = max_quanta_per_bit - 1; | ||
| 288 | while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { | ||
| 289 | if bs1_bs2_sum <= 2 { | ||
| 290 | return None; // No solution | ||
| 291 | } | ||
| 292 | bs1_bs2_sum -= 1; | ||
| 293 | } | ||
| 294 | |||
| 295 | let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; | ||
| 296 | if (prescaler < 1) || (prescaler > 1024) { | ||
| 297 | return None; // No solution | ||
| 298 | } | ||
| 299 | |||
| 300 | // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. | ||
| 301 | // We need to find such values so that the sample point is as close as possible to the optimal value, | ||
| 302 | // which is 87.5%, which is 7/8. | ||
| 303 | // | ||
| 304 | // Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *) | ||
| 305 | // {{bs2 -> (1 + bs1)/7}} | ||
| 306 | // | ||
| 307 | // Hence: | ||
| 308 | // bs2 = (1 + bs1) / 7 | ||
| 309 | // bs1 = (7 * bs1_bs2_sum - 1) / 8 | ||
| 310 | // | ||
| 311 | // Sample point location can be computed as follows: | ||
| 312 | // Sample point location = (1 + bs1) / (1 + bs1 + bs2) | ||
| 313 | // | ||
| 314 | // Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one: | ||
| 315 | // - With rounding to nearest | ||
| 316 | // - With rounding to zero | ||
| 317 | let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first | ||
| 318 | let mut bs2 = bs1_bs2_sum - bs1; | ||
| 319 | core::assert!(bs1_bs2_sum > bs1); | ||
| 320 | |||
| 321 | let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16; | ||
| 322 | if sample_point_permill > MAX_SAMPLE_POINT_PERMILL { | ||
| 323 | // Nope, too far; now rounding to zero | ||
| 324 | bs1 = (7 * bs1_bs2_sum - 1) / 8; | ||
| 325 | bs2 = bs1_bs2_sum - bs1; | ||
| 326 | } | ||
| 327 | |||
| 328 | // Check is BS1 and BS2 are in range | ||
| 329 | if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { | ||
| 330 | return None; | ||
| 331 | } | ||
| 332 | |||
| 333 | // Check if final bitrate matches the requested | ||
| 334 | if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) { | ||
| 335 | return None; | ||
| 336 | } | ||
| 337 | |||
| 338 | // One is recommended by DS-015, CANOpen, and DeviceNet | ||
| 339 | let sjw = 1; | ||
| 340 | |||
| 341 | // Pack into BTR register values | ||
| 342 | Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler as u32 - 1)) | ||
| 343 | } | ||
| 344 | } | ||
| 345 | |||
| 346 | enum RxFifo { | ||
| 347 | Fifo0, | ||
| 348 | Fifo1, | ||
| 53 | } | 349 | } |
| 54 | 350 | ||
| 55 | impl<'d, T: Instance> Drop for Can<'d, T> { | 351 | impl<'d, T: Instance> Drop for Can<'d, T> { |
| @@ -76,14 +372,52 @@ impl<'d, T: Instance> DerefMut for Can<'d, T> { | |||
| 76 | } | 372 | } |
| 77 | 373 | ||
| 78 | pub(crate) mod sealed { | 374 | pub(crate) mod sealed { |
| 375 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 376 | use embassy_sync::channel::Channel; | ||
| 377 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 378 | |||
| 379 | pub struct State { | ||
| 380 | pub tx_waker: AtomicWaker, | ||
| 381 | pub err_waker: AtomicWaker, | ||
| 382 | pub rx_queue: Channel<CriticalSectionRawMutex, (u16, bxcan::Frame), 32>, | ||
| 383 | } | ||
| 384 | |||
| 385 | impl State { | ||
| 386 | pub const fn new() -> Self { | ||
| 387 | Self { | ||
| 388 | tx_waker: AtomicWaker::new(), | ||
| 389 | err_waker: AtomicWaker::new(), | ||
| 390 | rx_queue: Channel::new(), | ||
| 391 | } | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 79 | pub trait Instance { | 395 | pub trait Instance { |
| 80 | const REGISTERS: *mut bxcan::RegisterBlock; | 396 | const REGISTERS: *mut bxcan::RegisterBlock; |
| 81 | 397 | ||
| 82 | fn regs() -> &'static crate::pac::can::Can; | 398 | fn regs() -> &'static crate::pac::can::Can; |
| 399 | fn state() -> &'static State; | ||
| 83 | } | 400 | } |
| 84 | } | 401 | } |
| 85 | 402 | ||
| 86 | pub trait Instance: sealed::Instance + RccPeripheral {} | 403 | pub trait TXInstance { |
| 404 | type TXInterrupt: crate::interrupt::typelevel::Interrupt; | ||
| 405 | } | ||
| 406 | |||
| 407 | pub trait RX0Instance { | ||
| 408 | type RX0Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 409 | } | ||
| 410 | |||
| 411 | pub trait RX1Instance { | ||
| 412 | type RX1Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 413 | } | ||
| 414 | |||
| 415 | pub trait SCEInstance { | ||
| 416 | type SCEInterrupt: crate::interrupt::typelevel::Interrupt; | ||
| 417 | } | ||
| 418 | |||
| 419 | pub trait InterruptableInstance: TXInstance + RX0Instance + RX1Instance + SCEInstance {} | ||
| 420 | pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {} | ||
| 87 | 421 | ||
| 88 | pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); | 422 | pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); |
| 89 | 423 | ||
| @@ -99,10 +433,39 @@ foreach_peripheral!( | |||
| 99 | fn regs() -> &'static crate::pac::can::Can { | 433 | fn regs() -> &'static crate::pac::can::Can { |
| 100 | &crate::pac::$inst | 434 | &crate::pac::$inst |
| 101 | } | 435 | } |
| 436 | |||
| 437 | fn state() -> &'static sealed::State { | ||
| 438 | static STATE: sealed::State = sealed::State::new(); | ||
| 439 | &STATE | ||
| 440 | } | ||
| 102 | } | 441 | } |
| 103 | 442 | ||
| 104 | impl Instance for peripherals::$inst {} | 443 | impl Instance for peripherals::$inst {} |
| 105 | 444 | ||
| 445 | foreach_interrupt!( | ||
| 446 | ($inst,can,CAN,TX,$irq:ident) => { | ||
| 447 | impl TXInstance for peripherals::$inst { | ||
| 448 | type TXInterrupt = crate::interrupt::typelevel::$irq; | ||
| 449 | } | ||
| 450 | }; | ||
| 451 | ($inst,can,CAN,RX0,$irq:ident) => { | ||
| 452 | impl RX0Instance for peripherals::$inst { | ||
| 453 | type RX0Interrupt = crate::interrupt::typelevel::$irq; | ||
| 454 | } | ||
| 455 | }; | ||
| 456 | ($inst,can,CAN,RX1,$irq:ident) => { | ||
| 457 | impl RX1Instance for peripherals::$inst { | ||
| 458 | type RX1Interrupt = crate::interrupt::typelevel::$irq; | ||
| 459 | } | ||
| 460 | }; | ||
| 461 | ($inst,can,CAN,SCE,$irq:ident) => { | ||
| 462 | impl SCEInstance for peripherals::$inst { | ||
| 463 | type SCEInterrupt = crate::interrupt::typelevel::$irq; | ||
| 464 | } | ||
| 465 | }; | ||
| 466 | ); | ||
| 467 | |||
| 468 | impl InterruptableInstance for peripherals::$inst {} | ||
| 106 | }; | 469 | }; |
| 107 | ); | 470 | ); |
| 108 | 471 | ||
| @@ -143,3 +506,36 @@ foreach_peripheral!( | |||
| 143 | 506 | ||
| 144 | pin_trait!(RxPin, Instance); | 507 | pin_trait!(RxPin, Instance); |
| 145 | pin_trait!(TxPin, Instance); | 508 | pin_trait!(TxPin, Instance); |
| 509 | |||
| 510 | trait Index { | ||
| 511 | fn index(&self) -> usize; | ||
| 512 | } | ||
| 513 | |||
| 514 | impl Index for bxcan::Mailbox { | ||
| 515 | fn index(&self) -> usize { | ||
| 516 | match self { | ||
| 517 | bxcan::Mailbox::Mailbox0 => 0, | ||
| 518 | bxcan::Mailbox::Mailbox1 => 1, | ||
| 519 | bxcan::Mailbox::Mailbox2 => 2, | ||
| 520 | } | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 524 | trait IntoBusError { | ||
| 525 | fn into_bus_err(self) -> Option<BusError>; | ||
| 526 | } | ||
| 527 | |||
| 528 | impl IntoBusError for Lec { | ||
| 529 | fn into_bus_err(self) -> Option<BusError> { | ||
| 530 | match self { | ||
| 531 | Lec::STUFF => Some(BusError::Stuff), | ||
| 532 | Lec::FORM => Some(BusError::Form), | ||
| 533 | Lec::ACK => Some(BusError::Acknowledge), | ||
| 534 | Lec::BITRECESSIVE => Some(BusError::BitRecessive), | ||
| 535 | Lec::BITDOMINANT => Some(BusError::BitDominant), | ||
| 536 | Lec::CRC => Some(BusError::Crc), | ||
| 537 | Lec::CUSTOM => Some(BusError::Software), | ||
| 538 | _ => None, | ||
| 539 | } | ||
| 540 | } | ||
| 541 | } | ||
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 0ad20579a..162ca9adb 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -338,6 +338,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 338 | 338 | ||
| 339 | pub fn blocking_wait(mut self) { | 339 | pub fn blocking_wait(mut self) { |
| 340 | while self.is_running() {} | 340 | while self.is_running() {} |
| 341 | self.request_stop(); | ||
| 341 | 342 | ||
| 342 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." | 343 | // "Subsequent reads and writes cannot be moved ahead of preceding reads." |
| 343 | fence(Ordering::SeqCst); | 344 | fence(Ordering::SeqCst); |
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index c600df92d..b7bcf7795 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs | |||
| @@ -252,6 +252,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 252 | super::dmamux::configure_dmamux(&mut *this.channel, request); | 252 | super::dmamux::configure_dmamux(&mut *this.channel, request); |
| 253 | 253 | ||
| 254 | ch.cr().write(|w| w.set_reset(true)); | 254 | ch.cr().write(|w| w.set_reset(true)); |
| 255 | ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs | ||
| 255 | ch.llr().write(|_| {}); // no linked list | 256 | ch.llr().write(|_| {}); // no linked list |
| 256 | ch.tr1().write(|w| { | 257 | ch.tr1().write(|w| { |
| 257 | w.set_sdw(data_size.into()); | 258 | w.set_sdw(data_size.into()); |
