diff options
| author | Corey Schuhen <[email protected]> | 2024-03-24 07:20:33 +1000 |
|---|---|---|
| committer | Corey Schuhen <[email protected]> | 2024-03-28 09:32:13 +1000 |
| commit | 3bdaad39e8955fe52e55c65a834dfc42dc54d676 (patch) | |
| tree | e69983676ae806ecb092a013a6efdee618615092 | |
| parent | 32065d7719e8dd2f5da7787d4b7edf3109c632ba (diff) | |
BXCAN: Register access into new Registers struct.
| -rw-r--r-- | embassy-stm32/src/can/bx/mod.rs | 727 | ||||
| -rw-r--r-- | embassy-stm32/src/can/bxcan.rs | 76 | ||||
| -rw-r--r-- | embassy-stm32/src/can/common.rs | 12 | ||||
| -rw-r--r-- | embassy-stm32/src/can/fdcan.rs | 4 |
4 files changed, 452 insertions, 367 deletions
diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 5ea0471c9..9b6ebf5a4 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs | |||
| @@ -43,7 +43,35 @@ pub type Data = crate::can::frame::ClassicData; | |||
| 43 | /// CAN Frame | 43 | /// CAN Frame |
| 44 | pub type Frame = crate::can::frame::ClassicFrame; | 44 | pub type Frame = crate::can::frame::ClassicFrame; |
| 45 | 45 | ||
| 46 | use crate::can::_version::Envelope; | ||
| 46 | use crate::can::bx::filter::MasterFilters; | 47 | use crate::can::bx::filter::MasterFilters; |
| 48 | use crate::can::enums::BusError; | ||
| 49 | use crate::pac::can::vals::Lec; | ||
| 50 | |||
| 51 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 52 | pub(crate) enum RxFifo { | ||
| 53 | Fifo0, | ||
| 54 | Fifo1, | ||
| 55 | } | ||
| 56 | |||
| 57 | trait IntoBusError { | ||
| 58 | fn into_bus_err(self) -> Option<BusError>; | ||
| 59 | } | ||
| 60 | |||
| 61 | impl IntoBusError for Lec { | ||
| 62 | fn into_bus_err(self) -> Option<BusError> { | ||
| 63 | match self { | ||
| 64 | Lec::STUFF => Some(BusError::Stuff), | ||
| 65 | Lec::FORM => Some(BusError::Form), | ||
| 66 | Lec::ACK => Some(BusError::Acknowledge), | ||
| 67 | Lec::BITRECESSIVE => Some(BusError::BitRecessive), | ||
| 68 | Lec::BITDOMINANT => Some(BusError::BitDominant), | ||
| 69 | Lec::CRC => Some(BusError::Crc), | ||
| 70 | Lec::CUSTOM => Some(BusError::Software), | ||
| 71 | _ => None, | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 47 | 75 | ||
| 48 | /// A bxCAN peripheral instance. | 76 | /// A bxCAN peripheral instance. |
| 49 | /// | 77 | /// |
| @@ -233,6 +261,376 @@ impl PartialOrd for IdReg { | |||
| 233 | } | 261 | } |
| 234 | } | 262 | } |
| 235 | 263 | ||
| 264 | pub(crate) struct Registers { | ||
| 265 | pub canregs: crate::pac::can::Can, | ||
| 266 | } | ||
| 267 | |||
| 268 | impl Registers { | ||
| 269 | fn enter_init_mode(&mut self) { | ||
| 270 | self.canregs.mcr().modify(|reg| { | ||
| 271 | reg.set_sleep(false); | ||
| 272 | reg.set_inrq(true); | ||
| 273 | }); | ||
| 274 | loop { | ||
| 275 | let msr = self.canregs.msr().read(); | ||
| 276 | if !msr.slak() && msr.inak() { | ||
| 277 | break; | ||
| 278 | } | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | // Leaves initialization mode, enters sleep mode. | ||
| 283 | fn leave_init_mode(&mut self) { | ||
| 284 | self.canregs.mcr().modify(|reg| { | ||
| 285 | reg.set_sleep(true); | ||
| 286 | reg.set_inrq(false); | ||
| 287 | }); | ||
| 288 | loop { | ||
| 289 | let msr = self.canregs.msr().read(); | ||
| 290 | if msr.slak() && !msr.inak() { | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { | ||
| 297 | let prescaler = u16::from(bt.prescaler) & 0x1FF; | ||
| 298 | let seg1 = u8::from(bt.seg1); | ||
| 299 | let seg2 = u8::from(bt.seg2) & 0x7F; | ||
| 300 | let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F; | ||
| 301 | self.canregs.btr().modify(|reg| { | ||
| 302 | reg.set_brp(prescaler - 1); | ||
| 303 | reg.set_ts(0, seg1 - 1); | ||
| 304 | reg.set_ts(1, seg2 - 1); | ||
| 305 | reg.set_sjw(sync_jump_width - 1); | ||
| 306 | }); | ||
| 307 | } | ||
| 308 | |||
| 309 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 310 | pub fn set_silent(&self, enabled: bool) { | ||
| 311 | let mode = match enabled { | ||
| 312 | false => stm32_metapac::can::vals::Silm::NORMAL, | ||
| 313 | true => stm32_metapac::can::vals::Silm::SILENT, | ||
| 314 | }; | ||
| 315 | self.canregs.btr().modify(|reg| reg.set_silm(mode)); | ||
| 316 | } | ||
| 317 | |||
| 318 | /// Enables or disables automatic retransmission of messages. | ||
| 319 | /// | ||
| 320 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 321 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 322 | /// | ||
| 323 | /// Automatic retransmission is enabled by default. | ||
| 324 | pub fn set_automatic_retransmit(&self, enabled: bool) { | ||
| 325 | self.canregs.mcr().modify(|reg| reg.set_nart(enabled)); | ||
| 326 | } | ||
| 327 | |||
| 328 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 329 | /// signals together. | ||
| 330 | pub fn set_loopback(&self, enabled: bool) { | ||
| 331 | self.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); | ||
| 332 | } | ||
| 333 | |||
| 334 | /// Configures the automatic wake-up feature. | ||
| 335 | /// | ||
| 336 | /// This is turned off by default. | ||
| 337 | /// | ||
| 338 | /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and | ||
| 339 | /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming | ||
| 340 | /// frame. | ||
| 341 | #[allow(dead_code)] | ||
| 342 | pub fn set_automatic_wakeup(&mut self, enabled: bool) { | ||
| 343 | self.canregs.mcr().modify(|reg| reg.set_awum(enabled)); | ||
| 344 | } | ||
| 345 | |||
| 346 | /// Leaves initialization mode and enables the peripheral (non-blocking version). | ||
| 347 | /// | ||
| 348 | /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed | ||
| 349 | /// if you want non-blocking initialization. | ||
| 350 | /// | ||
| 351 | /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself | ||
| 352 | /// in the background. The peripheral is enabled and ready to use when this method returns | ||
| 353 | /// successfully. | ||
| 354 | pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { | ||
| 355 | let msr = self.canregs.msr().read(); | ||
| 356 | if msr.slak() { | ||
| 357 | self.canregs.mcr().modify(|reg| { | ||
| 358 | reg.set_abom(true); | ||
| 359 | reg.set_sleep(false); | ||
| 360 | }); | ||
| 361 | Err(nb::Error::WouldBlock) | ||
| 362 | } else { | ||
| 363 | Ok(()) | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | /// Puts the peripheral in a sleep mode to save power. | ||
| 368 | /// | ||
| 369 | /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. | ||
| 370 | #[allow(dead_code)] | ||
| 371 | pub fn sleep(&mut self) { | ||
| 372 | self.canregs.mcr().modify(|reg| { | ||
| 373 | reg.set_sleep(true); | ||
| 374 | reg.set_inrq(false); | ||
| 375 | }); | ||
| 376 | loop { | ||
| 377 | let msr = self.canregs.msr().read(); | ||
| 378 | if msr.slak() && !msr.inak() { | ||
| 379 | break; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | /// Disables the CAN interface. | ||
| 385 | /// | ||
| 386 | /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to | ||
| 387 | /// enter sleep mode. | ||
| 388 | pub fn reset(&self) { | ||
| 389 | self.canregs.mcr().write(|reg| reg.set_reset(true)); | ||
| 390 | } | ||
| 391 | |||
| 392 | /// Wakes up from sleep mode. | ||
| 393 | /// | ||
| 394 | /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN | ||
| 395 | /// frame will cause that interrupt. | ||
| 396 | #[allow(dead_code)] | ||
| 397 | pub fn wakeup(&mut self) { | ||
| 398 | self.canregs.mcr().modify(|reg| { | ||
| 399 | reg.set_sleep(false); | ||
| 400 | reg.set_inrq(false); | ||
| 401 | }); | ||
| 402 | loop { | ||
| 403 | let msr = self.canregs.msr().read(); | ||
| 404 | if !msr.slak() && !msr.inak() { | ||
| 405 | break; | ||
| 406 | } | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | pub fn curr_error(&self) -> Option<BusError> { | ||
| 411 | let err = { self.canregs.esr().read() }; | ||
| 412 | if err.boff() { | ||
| 413 | return Some(BusError::BusOff); | ||
| 414 | } else if err.epvf() { | ||
| 415 | return Some(BusError::BusPassive); | ||
| 416 | } else if err.ewgf() { | ||
| 417 | return Some(BusError::BusWarning); | ||
| 418 | } else if let Some(err) = err.lec().into_bus_err() { | ||
| 419 | return Some(err); | ||
| 420 | } | ||
| 421 | None | ||
| 422 | } | ||
| 423 | |||
| 424 | /// Puts a CAN frame in a transmit mailbox for transmission on the bus. | ||
| 425 | /// | ||
| 426 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). | ||
| 427 | /// Transmit order is preserved for frames with identical priority. | ||
| 428 | /// | ||
| 429 | /// If all transmit mailboxes are full, and `frame` has a higher priority than the | ||
| 430 | /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is | ||
| 431 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as | ||
| 432 | /// [`TransmitStatus::dequeued_frame`]. | ||
| 433 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { | ||
| 434 | // Get the index of the next free mailbox or the one with the lowest priority. | ||
| 435 | let tsr = self.canregs.tsr().read(); | ||
| 436 | let idx = tsr.code() as usize; | ||
| 437 | |||
| 438 | let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2); | ||
| 439 | let pending_frame = if frame_is_pending { | ||
| 440 | // High priority frames are transmitted first by the mailbox system. | ||
| 441 | // Frames with identical identifier shall be transmitted in FIFO order. | ||
| 442 | // The controller schedules pending frames of same priority based on the | ||
| 443 | // mailbox index instead. As a workaround check all pending mailboxes | ||
| 444 | // and only accept higher priority frames. | ||
| 445 | self.check_priority(0, frame.id().into())?; | ||
| 446 | self.check_priority(1, frame.id().into())?; | ||
| 447 | self.check_priority(2, frame.id().into())?; | ||
| 448 | |||
| 449 | let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); | ||
| 450 | if all_frames_are_pending { | ||
| 451 | // No free mailbox is available. This can only happen when three frames with | ||
| 452 | // ascending priority (descending IDs) were requested for transmission and all | ||
| 453 | // of them are blocked by bus traffic with even higher priority. | ||
| 454 | // To prevent a priority inversion abort and replace the lowest priority frame. | ||
| 455 | self.read_pending_mailbox(idx) | ||
| 456 | } else { | ||
| 457 | // There was a free mailbox. | ||
| 458 | None | ||
| 459 | } | ||
| 460 | } else { | ||
| 461 | // All mailboxes are available: Send frame without performing any checks. | ||
| 462 | None | ||
| 463 | }; | ||
| 464 | |||
| 465 | self.write_mailbox(idx, frame); | ||
| 466 | |||
| 467 | let mailbox = match idx { | ||
| 468 | 0 => Mailbox::Mailbox0, | ||
| 469 | 1 => Mailbox::Mailbox1, | ||
| 470 | 2 => Mailbox::Mailbox2, | ||
| 471 | _ => unreachable!(), | ||
| 472 | }; | ||
| 473 | Ok(TransmitStatus { | ||
| 474 | dequeued_frame: pending_frame, | ||
| 475 | mailbox, | ||
| 476 | }) | ||
| 477 | } | ||
| 478 | |||
| 479 | /// Returns `Ok` when the mailbox is free or if it contains pending frame with a | ||
| 480 | /// lower priority (higher ID) than the identifier `id`. | ||
| 481 | fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { | ||
| 482 | // Read the pending frame's id to check its priority. | ||
| 483 | assert!(idx < 3); | ||
| 484 | let tir = &self.canregs.tx(idx).tir().read(); | ||
| 485 | //let tir = &can.tx[idx].tir.read(); | ||
| 486 | |||
| 487 | // Check the priority by comparing the identifiers. But first make sure the | ||
| 488 | // frame has not finished the transmission (`TXRQ` == 0) in the meantime. | ||
| 489 | if tir.txrq() && id <= IdReg::from_register(tir.0) { | ||
| 490 | // There's a mailbox whose priority is higher or equal | ||
| 491 | // the priority of the new frame. | ||
| 492 | return Err(nb::Error::WouldBlock); | ||
| 493 | } | ||
| 494 | |||
| 495 | Ok(()) | ||
| 496 | } | ||
| 497 | |||
| 498 | fn write_mailbox(&mut self, idx: usize, frame: &Frame) { | ||
| 499 | debug_assert!(idx < 3); | ||
| 500 | |||
| 501 | let mb = self.canregs.tx(idx); | ||
| 502 | mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); | ||
| 503 | |||
| 504 | mb.tdlr() | ||
| 505 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap())); | ||
| 506 | mb.tdhr() | ||
| 507 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap())); | ||
| 508 | let id: IdReg = frame.id().into(); | ||
| 509 | mb.tir().write(|w| { | ||
| 510 | w.0 = id.0; | ||
| 511 | w.set_txrq(true); | ||
| 512 | }); | ||
| 513 | } | ||
| 514 | |||
| 515 | fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> { | ||
| 516 | if self.abort_by_index(idx) { | ||
| 517 | debug_assert!(idx < 3); | ||
| 518 | |||
| 519 | let mb = self.canregs.tx(idx); | ||
| 520 | |||
| 521 | let id = IdReg(mb.tir().read().0); | ||
| 522 | let mut data = [0xff; 8]; | ||
| 523 | data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); | ||
| 524 | data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); | ||
| 525 | let len = mb.tdtr().read().dlc(); | ||
| 526 | |||
| 527 | Some(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap()) | ||
| 528 | } else { | ||
| 529 | // Abort request failed because the frame was already sent (or being sent) on | ||
| 530 | // the bus. All mailboxes are now free. This can happen for small prescaler | ||
| 531 | // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR | ||
| 532 | // has preempted the execution. | ||
| 533 | None | ||
| 534 | } | ||
| 535 | } | ||
| 536 | |||
| 537 | /// Tries to abort a pending frame. Returns `true` when aborted. | ||
| 538 | fn abort_by_index(&mut self, idx: usize) -> bool { | ||
| 539 | self.canregs.tsr().write(|reg| reg.set_abrq(idx, true)); | ||
| 540 | |||
| 541 | // Wait for the abort request to be finished. | ||
| 542 | loop { | ||
| 543 | let tsr = self.canregs.tsr().read(); | ||
| 544 | if false == tsr.abrq(idx) { | ||
| 545 | break tsr.txok(idx) == false; | ||
| 546 | } | ||
| 547 | } | ||
| 548 | } | ||
| 549 | |||
| 550 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 551 | /// | ||
| 552 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 553 | /// aborted, this function has no effect and returns `false`. | ||
| 554 | /// | ||
| 555 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 556 | /// returns `true`. | ||
| 557 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 558 | // If the mailbox is empty, the value of TXOKx depends on what happened with the previous | ||
| 559 | // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. | ||
| 560 | let tsr = self.canregs.tsr().read(); | ||
| 561 | let mailbox_empty = match mailbox { | ||
| 562 | Mailbox::Mailbox0 => tsr.tme(0), | ||
| 563 | Mailbox::Mailbox1 => tsr.tme(1), | ||
| 564 | Mailbox::Mailbox2 => tsr.tme(2), | ||
| 565 | }; | ||
| 566 | if mailbox_empty { | ||
| 567 | false | ||
| 568 | } else { | ||
| 569 | self.abort_by_index(mailbox as usize) | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | /// Returns `true` if no frame is pending for transmission. | ||
| 574 | pub fn is_idle(&self) -> bool { | ||
| 575 | let tsr = self.canregs.tsr().read(); | ||
| 576 | tsr.tme(0) && tsr.tme(1) && tsr.tme(2) | ||
| 577 | } | ||
| 578 | |||
| 579 | /// Clears the request complete flag for all mailboxes. | ||
| 580 | pub fn clear_interrupt_flags(&mut self) { | ||
| 581 | self.canregs.tsr().write(|reg| { | ||
| 582 | reg.set_rqcp(0, true); | ||
| 583 | reg.set_rqcp(1, true); | ||
| 584 | reg.set_rqcp(2, true); | ||
| 585 | }); | ||
| 586 | } | ||
| 587 | |||
| 588 | pub fn receive_fifo(&self, fifo: crate::can::_version::bx::RxFifo) -> Option<Envelope> { | ||
| 589 | // Generate timestamp as early as possible | ||
| 590 | #[cfg(feature = "time")] | ||
| 591 | let ts = embassy_time::Instant::now(); | ||
| 592 | |||
| 593 | use crate::pac::can::vals::Ide; | ||
| 594 | |||
| 595 | let fifo_idx = match fifo { | ||
| 596 | crate::can::_version::bx::RxFifo::Fifo0 => 0usize, | ||
| 597 | crate::can::_version::bx::RxFifo::Fifo1 => 1usize, | ||
| 598 | }; | ||
| 599 | let rfr = self.canregs.rfr(fifo_idx); | ||
| 600 | let fifo = self.canregs.rx(fifo_idx); | ||
| 601 | |||
| 602 | // If there are no pending messages, there is nothing to do | ||
| 603 | if rfr.read().fmp() == 0 { | ||
| 604 | return None; | ||
| 605 | } | ||
| 606 | |||
| 607 | let rir = fifo.rir().read(); | ||
| 608 | let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { | ||
| 609 | embedded_can::StandardId::new(rir.stid()).unwrap().into() | ||
| 610 | } else { | ||
| 611 | let stid = (rir.stid() & 0x7FF) as u32; | ||
| 612 | let exid = rir.exid() & 0x3FFFF; | ||
| 613 | let id = (stid << 18) | (exid); | ||
| 614 | embedded_can::ExtendedId::new(id).unwrap().into() | ||
| 615 | }; | ||
| 616 | let data_len = fifo.rdtr().read().dlc(); | ||
| 617 | let mut data: [u8; 8] = [0; 8]; | ||
| 618 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | ||
| 619 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | ||
| 620 | |||
| 621 | let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap(); | ||
| 622 | let envelope = Envelope { | ||
| 623 | #[cfg(feature = "time")] | ||
| 624 | ts, | ||
| 625 | frame, | ||
| 626 | }; | ||
| 627 | |||
| 628 | rfr.modify(|v| v.set_rfom(true)); | ||
| 629 | |||
| 630 | Some(envelope) | ||
| 631 | } | ||
| 632 | } | ||
| 633 | |||
| 236 | /// Configuration proxy returned by [`Can::modify_config`]. | 634 | /// Configuration proxy returned by [`Can::modify_config`]. |
| 237 | #[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"] | 635 | #[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"] |
| 238 | pub struct CanConfig<'a, I: Instance> { | 636 | pub struct CanConfig<'a, I: Instance> { |
| @@ -253,24 +651,20 @@ impl<I: Instance> CanConfig<'_, I> { | |||
| 253 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | 651 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` |
| 254 | /// parameter to this method. | 652 | /// parameter to this method. |
| 255 | pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { | 653 | pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { |
| 256 | self.can.set_bit_timing(bt); | 654 | self.can.registers.set_bit_timing(bt); |
| 257 | self | 655 | self |
| 258 | } | 656 | } |
| 259 | 657 | ||
| 260 | /// Enables or disables loopback mode: Internally connects the TX and RX | 658 | /// Enables or disables loopback mode: Internally connects the TX and RX |
| 261 | /// signals together. | 659 | /// signals together. |
| 262 | pub fn set_loopback(self, enabled: bool) -> Self { | 660 | pub fn set_loopback(self, enabled: bool) -> Self { |
| 263 | self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); | 661 | self.can.registers.set_loopback(enabled); |
| 264 | self | 662 | self |
| 265 | } | 663 | } |
| 266 | 664 | ||
| 267 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | 665 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. |
| 268 | pub fn set_silent(self, enabled: bool) -> Self { | 666 | pub fn set_silent(self, enabled: bool) -> Self { |
| 269 | let mode = match enabled { | 667 | self.can.registers.set_silent(enabled); |
| 270 | false => stm32_metapac::can::vals::Silm::NORMAL, | ||
| 271 | true => stm32_metapac::can::vals::Silm::SILENT, | ||
| 272 | }; | ||
| 273 | self.can.canregs.btr().modify(|reg| reg.set_silm(mode)); | ||
| 274 | self | 668 | self |
| 275 | } | 669 | } |
| 276 | 670 | ||
| @@ -281,7 +675,7 @@ impl<I: Instance> CanConfig<'_, I> { | |||
| 281 | /// | 675 | /// |
| 282 | /// Automatic retransmission is enabled by default. | 676 | /// Automatic retransmission is enabled by default. |
| 283 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { | 677 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { |
| 284 | self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled)); | 678 | self.can.registers.set_automatic_retransmit(enabled); |
| 285 | self | 679 | self |
| 286 | } | 680 | } |
| 287 | 681 | ||
| @@ -292,10 +686,10 @@ impl<I: Instance> CanConfig<'_, I> { | |||
| 292 | /// | 686 | /// |
| 293 | /// If you want to finish configuration without enabling the peripheral, you can call | 687 | /// If you want to finish configuration without enabling the peripheral, you can call |
| 294 | /// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead. | 688 | /// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead. |
| 295 | pub fn enable(mut self) { | 689 | pub fn enable(self) { |
| 296 | self.leave_init_mode(); | 690 | self.can.registers.leave_init_mode(); |
| 297 | 691 | ||
| 298 | match nb::block!(self.can.enable_non_blocking()) { | 692 | match nb::block!(self.can.registers.enable_non_blocking()) { |
| 299 | Ok(()) => {} | 693 | Ok(()) => {} |
| 300 | Err(void) => match void {}, | 694 | Err(void) => match void {}, |
| 301 | } | 695 | } |
| @@ -308,29 +702,15 @@ impl<I: Instance> CanConfig<'_, I> { | |||
| 308 | /// | 702 | /// |
| 309 | /// Before the [`Can`] instance can be used, you have to enable it by calling | 703 | /// Before the [`Can`] instance can be used, you have to enable it by calling |
| 310 | /// [`Can::enable_non_blocking`]. | 704 | /// [`Can::enable_non_blocking`]. |
| 311 | pub fn leave_disabled(mut self) { | 705 | pub fn leave_disabled(self) { |
| 312 | self.leave_init_mode(); | 706 | self.can.registers.leave_init_mode(); |
| 313 | } | ||
| 314 | |||
| 315 | /// Leaves initialization mode, enters sleep mode. | ||
| 316 | fn leave_init_mode(&mut self) { | ||
| 317 | self.can.canregs.mcr().modify(|reg| { | ||
| 318 | reg.set_sleep(true); | ||
| 319 | reg.set_inrq(false); | ||
| 320 | }); | ||
| 321 | loop { | ||
| 322 | let msr = self.can.canregs.msr().read(); | ||
| 323 | if msr.slak() && !msr.inak() { | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | } | 707 | } |
| 328 | } | 708 | } |
| 329 | 709 | ||
| 330 | impl<I: Instance> Drop for CanConfig<'_, I> { | 710 | impl<I: Instance> Drop for CanConfig<'_, I> { |
| 331 | #[inline] | 711 | #[inline] |
| 332 | fn drop(&mut self) { | 712 | fn drop(&mut self) { |
| 333 | self.leave_init_mode(); | 713 | self.can.registers.leave_init_mode(); |
| 334 | } | 714 | } |
| 335 | } | 715 | } |
| 336 | 716 | ||
| @@ -354,23 +734,19 @@ impl<I: Instance> CanBuilder<I> { | |||
| 354 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | 734 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` |
| 355 | /// parameter to this method. | 735 | /// parameter to this method. |
| 356 | pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self { | 736 | pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self { |
| 357 | self.can.set_bit_timing(bt); | 737 | self.can.registers.set_bit_timing(bt); |
| 358 | self | 738 | self |
| 359 | } | 739 | } |
| 360 | /// Enables or disables loopback mode: Internally connects the TX and RX | 740 | /// Enables or disables loopback mode: Internally connects the TX and RX |
| 361 | /// signals together. | 741 | /// signals together. |
| 362 | pub fn set_loopback(self, enabled: bool) -> Self { | 742 | pub fn set_loopback(self, enabled: bool) -> Self { |
| 363 | self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); | 743 | self.can.registers.set_loopback(enabled); |
| 364 | self | 744 | self |
| 365 | } | 745 | } |
| 366 | 746 | ||
| 367 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | 747 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. |
| 368 | pub fn set_silent(self, enabled: bool) -> Self { | 748 | pub fn set_silent(self, enabled: bool) -> Self { |
| 369 | let mode = match enabled { | 749 | self.can.registers.set_silent(enabled); |
| 370 | false => stm32_metapac::can::vals::Silm::NORMAL, | ||
| 371 | true => stm32_metapac::can::vals::Silm::SILENT, | ||
| 372 | }; | ||
| 373 | self.can.canregs.btr().modify(|reg| reg.set_silm(mode)); | ||
| 374 | self | 750 | self |
| 375 | } | 751 | } |
| 376 | 752 | ||
| @@ -381,7 +757,7 @@ impl<I: Instance> CanBuilder<I> { | |||
| 381 | /// | 757 | /// |
| 382 | /// Automatic retransmission is enabled by default. | 758 | /// Automatic retransmission is enabled by default. |
| 383 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { | 759 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { |
| 384 | self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled)); | 760 | self.can.registers.set_automatic_retransmit(enabled); |
| 385 | self | 761 | self |
| 386 | } | 762 | } |
| 387 | 763 | ||
| @@ -395,7 +771,7 @@ impl<I: Instance> CanBuilder<I> { | |||
| 395 | pub fn enable(mut self) -> Can<I> { | 771 | pub fn enable(mut self) -> Can<I> { |
| 396 | self.leave_init_mode(); | 772 | self.leave_init_mode(); |
| 397 | 773 | ||
| 398 | match nb::block!(self.can.enable_non_blocking()) { | 774 | match nb::block!(self.can.registers.enable_non_blocking()) { |
| 399 | Ok(()) => self.can, | 775 | Ok(()) => self.can, |
| 400 | Err(void) => match void {}, | 776 | Err(void) => match void {}, |
| 401 | } | 777 | } |
| @@ -415,16 +791,7 @@ impl<I: Instance> CanBuilder<I> { | |||
| 415 | 791 | ||
| 416 | /// Leaves initialization mode, enters sleep mode. | 792 | /// Leaves initialization mode, enters sleep mode. |
| 417 | fn leave_init_mode(&mut self) { | 793 | fn leave_init_mode(&mut self) { |
| 418 | self.can.canregs.mcr().modify(|reg| { | 794 | self.can.registers.leave_init_mode(); |
| 419 | reg.set_sleep(true); | ||
| 420 | reg.set_inrq(false); | ||
| 421 | }); | ||
| 422 | loop { | ||
| 423 | let msr = self.can.canregs.msr().read(); | ||
| 424 | if msr.slak() && !msr.inak() { | ||
| 425 | break; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | } | 795 | } |
| 429 | } | 796 | } |
| 430 | 797 | ||
| @@ -432,6 +799,7 @@ impl<I: Instance> CanBuilder<I> { | |||
| 432 | pub struct Can<I: Instance> { | 799 | pub struct Can<I: Instance> { |
| 433 | instance: I, | 800 | instance: I, |
| 434 | canregs: crate::pac::can::Can, | 801 | canregs: crate::pac::can::Can, |
| 802 | pub(crate) registers: Registers, | ||
| 435 | } | 803 | } |
| 436 | 804 | ||
| 437 | impl<I> Can<I> | 805 | impl<I> Can<I> |
| @@ -440,50 +808,25 @@ where | |||
| 440 | { | 808 | { |
| 441 | /// Creates a [`CanBuilder`] for constructing a CAN interface. | 809 | /// Creates a [`CanBuilder`] for constructing a CAN interface. |
| 442 | pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder<I> { | 810 | pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder<I> { |
| 443 | let can_builder = CanBuilder { | 811 | let mut can_builder = CanBuilder { |
| 444 | can: Can { instance, canregs }, | 812 | can: Can { |
| 813 | instance, | ||
| 814 | canregs, | ||
| 815 | registers: Registers { canregs }, | ||
| 816 | }, | ||
| 445 | }; | 817 | }; |
| 446 | 818 | ||
| 447 | canregs.mcr().modify(|reg| { | 819 | can_builder.can.registers.enter_init_mode(); |
| 448 | reg.set_sleep(false); | ||
| 449 | reg.set_inrq(true); | ||
| 450 | }); | ||
| 451 | loop { | ||
| 452 | let msr = canregs.msr().read(); | ||
| 453 | if !msr.slak() && msr.inak() { | ||
| 454 | break; | ||
| 455 | } | ||
| 456 | } | ||
| 457 | 820 | ||
| 458 | can_builder | 821 | can_builder |
| 459 | } | 822 | } |
| 460 | 823 | ||
| 461 | fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { | ||
| 462 | let prescaler = u16::from(bt.prescaler) & 0x1FF; | ||
| 463 | let seg1 = u8::from(bt.seg1); | ||
| 464 | let seg2 = u8::from(bt.seg2) & 0x7F; | ||
| 465 | let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F; | ||
| 466 | self.canregs.btr().modify(|reg| { | ||
| 467 | reg.set_brp(prescaler - 1); | ||
| 468 | reg.set_ts(0, seg1 - 1); | ||
| 469 | reg.set_ts(1, seg2 - 1); | ||
| 470 | reg.set_sjw(sync_jump_width - 1); | ||
| 471 | }); | ||
| 472 | } | ||
| 473 | |||
| 474 | /// Returns a reference to the peripheral instance. | ||
| 475 | /// | ||
| 476 | /// This allows accessing HAL-specific data stored in the instance type. | ||
| 477 | pub fn instance(&mut self) -> &mut I { | ||
| 478 | &mut self.instance | ||
| 479 | } | ||
| 480 | |||
| 481 | /// Disables the CAN interface and returns back the raw peripheral it was created from. | 824 | /// Disables the CAN interface and returns back the raw peripheral it was created from. |
| 482 | /// | 825 | /// |
| 483 | /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to | 826 | /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to |
| 484 | /// enter sleep mode. | 827 | /// enter sleep mode. |
| 485 | pub fn free(self) -> I { | 828 | pub fn free(self) -> I { |
| 486 | self.canregs.mcr().write(|reg| reg.set_reset(true)); | 829 | self.registers.reset(); |
| 487 | self.instance | 830 | self.instance |
| 488 | } | 831 | } |
| 489 | 832 | ||
| @@ -491,85 +834,11 @@ where | |||
| 491 | /// | 834 | /// |
| 492 | /// Calling this method will enter initialization mode. | 835 | /// Calling this method will enter initialization mode. |
| 493 | pub fn modify_config(&mut self) -> CanConfig<'_, I> { | 836 | pub fn modify_config(&mut self) -> CanConfig<'_, I> { |
| 494 | self.canregs.mcr().modify(|reg| { | 837 | self.registers.enter_init_mode(); |
| 495 | reg.set_sleep(false); | ||
| 496 | reg.set_inrq(true); | ||
| 497 | }); | ||
| 498 | loop { | ||
| 499 | let msr = self.canregs.msr().read(); | ||
| 500 | if !msr.slak() && msr.inak() { | ||
| 501 | break; | ||
| 502 | } | ||
| 503 | } | ||
| 504 | 838 | ||
| 505 | CanConfig { can: self } | 839 | CanConfig { can: self } |
| 506 | } | 840 | } |
| 507 | 841 | ||
| 508 | /// Configures the automatic wake-up feature. | ||
| 509 | /// | ||
| 510 | /// This is turned off by default. | ||
| 511 | /// | ||
| 512 | /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and | ||
| 513 | /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming | ||
| 514 | /// frame. | ||
| 515 | pub fn set_automatic_wakeup(&mut self, enabled: bool) { | ||
| 516 | self.canregs.mcr().modify(|reg| reg.set_awum(enabled)); | ||
| 517 | } | ||
| 518 | |||
| 519 | /// Leaves initialization mode and enables the peripheral (non-blocking version). | ||
| 520 | /// | ||
| 521 | /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed | ||
| 522 | /// if you want non-blocking initialization. | ||
| 523 | /// | ||
| 524 | /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself | ||
| 525 | /// in the background. The peripheral is enabled and ready to use when this method returns | ||
| 526 | /// successfully. | ||
| 527 | pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { | ||
| 528 | let msr = self.canregs.msr().read(); | ||
| 529 | if msr.slak() { | ||
| 530 | self.canregs.mcr().modify(|reg| { | ||
| 531 | reg.set_abom(true); | ||
| 532 | reg.set_sleep(false); | ||
| 533 | }); | ||
| 534 | Err(nb::Error::WouldBlock) | ||
| 535 | } else { | ||
| 536 | Ok(()) | ||
| 537 | } | ||
| 538 | } | ||
| 539 | |||
| 540 | /// Puts the peripheral in a sleep mode to save power. | ||
| 541 | /// | ||
| 542 | /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. | ||
| 543 | pub fn sleep(&mut self) { | ||
| 544 | self.canregs.mcr().modify(|reg| { | ||
| 545 | reg.set_sleep(true); | ||
| 546 | reg.set_inrq(false); | ||
| 547 | }); | ||
| 548 | loop { | ||
| 549 | let msr = self.canregs.msr().read(); | ||
| 550 | if msr.slak() && !msr.inak() { | ||
| 551 | break; | ||
| 552 | } | ||
| 553 | } | ||
| 554 | } | ||
| 555 | |||
| 556 | /// Wakes up from sleep mode. | ||
| 557 | /// | ||
| 558 | /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN | ||
| 559 | /// frame will cause that interrupt. | ||
| 560 | pub fn wakeup(&mut self) { | ||
| 561 | self.canregs.mcr().modify(|reg| { | ||
| 562 | reg.set_sleep(false); | ||
| 563 | reg.set_inrq(false); | ||
| 564 | }); | ||
| 565 | loop { | ||
| 566 | let msr = self.canregs.msr().read(); | ||
| 567 | if !msr.slak() && !msr.inak() { | ||
| 568 | break; | ||
| 569 | } | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. | 842 | /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. |
| 574 | /// | 843 | /// |
| 575 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). | 844 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). |
| @@ -602,14 +871,12 @@ where | |||
| 602 | unsafe { Tx::<I>::conjure(self.canregs).abort(mailbox) } | 871 | unsafe { Tx::<I>::conjure(self.canregs).abort(mailbox) } |
| 603 | } | 872 | } |
| 604 | 873 | ||
| 605 | |||
| 606 | pub(crate) fn split_by_ref(&mut self) -> (Tx<I>, Rx<I>) { | 874 | pub(crate) fn split_by_ref(&mut self) -> (Tx<I>, Rx<I>) { |
| 607 | // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. | 875 | // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. |
| 608 | let tx = unsafe { Tx::conjure(self.canregs) }; | 876 | let tx = unsafe { Tx::conjure(self.canregs) }; |
| 609 | let rx0 = unsafe { Rx::conjure() }; | 877 | let rx0 = unsafe { Rx::conjure() }; |
| 610 | (tx, rx0) | 878 | (tx, rx0) |
| 611 | } | 879 | } |
| 612 | |||
| 613 | } | 880 | } |
| 614 | 881 | ||
| 615 | impl<I: FilterOwner> Can<I> { | 882 | impl<I: FilterOwner> Can<I> { |
| @@ -625,7 +892,7 @@ impl<I: FilterOwner> Can<I> { | |||
| 625 | /// Marker for Tx half | 892 | /// Marker for Tx half |
| 626 | pub struct Tx<I> { | 893 | pub struct Tx<I> { |
| 627 | _can: PhantomData<I>, | 894 | _can: PhantomData<I>, |
| 628 | canregs: crate::pac::can::Can, | 895 | pub(crate) registers: Registers, |
| 629 | } | 896 | } |
| 630 | 897 | ||
| 631 | impl<I> Tx<I> | 898 | impl<I> Tx<I> |
| @@ -635,7 +902,7 @@ where | |||
| 635 | unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { | 902 | unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { |
| 636 | Self { | 903 | Self { |
| 637 | _can: PhantomData, | 904 | _can: PhantomData, |
| 638 | canregs, | 905 | registers: Registers { canregs }, //canregs, |
| 639 | } | 906 | } |
| 640 | } | 907 | } |
| 641 | 908 | ||
| @@ -649,120 +916,7 @@ where | |||
| 649 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as | 916 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as |
| 650 | /// [`TransmitStatus::dequeued_frame`]. | 917 | /// [`TransmitStatus::dequeued_frame`]. |
| 651 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { | 918 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { |
| 652 | // Get the index of the next free mailbox or the one with the lowest priority. | 919 | self.registers.transmit(frame) |
| 653 | let tsr = self.canregs.tsr().read(); | ||
| 654 | let idx = tsr.code() as usize; | ||
| 655 | |||
| 656 | let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2); | ||
| 657 | let pending_frame = if frame_is_pending { | ||
| 658 | // High priority frames are transmitted first by the mailbox system. | ||
| 659 | // Frames with identical identifier shall be transmitted in FIFO order. | ||
| 660 | // The controller schedules pending frames of same priority based on the | ||
| 661 | // mailbox index instead. As a workaround check all pending mailboxes | ||
| 662 | // and only accept higher priority frames. | ||
| 663 | self.check_priority(0, frame.id().into())?; | ||
| 664 | self.check_priority(1, frame.id().into())?; | ||
| 665 | self.check_priority(2, frame.id().into())?; | ||
| 666 | |||
| 667 | let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); | ||
| 668 | if all_frames_are_pending { | ||
| 669 | // No free mailbox is available. This can only happen when three frames with | ||
| 670 | // ascending priority (descending IDs) were requested for transmission and all | ||
| 671 | // of them are blocked by bus traffic with even higher priority. | ||
| 672 | // To prevent a priority inversion abort and replace the lowest priority frame. | ||
| 673 | self.read_pending_mailbox(idx) | ||
| 674 | } else { | ||
| 675 | // There was a free mailbox. | ||
| 676 | None | ||
| 677 | } | ||
| 678 | } else { | ||
| 679 | // All mailboxes are available: Send frame without performing any checks. | ||
| 680 | None | ||
| 681 | }; | ||
| 682 | |||
| 683 | self.write_mailbox(idx, frame); | ||
| 684 | |||
| 685 | let mailbox = match idx { | ||
| 686 | 0 => Mailbox::Mailbox0, | ||
| 687 | 1 => Mailbox::Mailbox1, | ||
| 688 | 2 => Mailbox::Mailbox2, | ||
| 689 | _ => unreachable!(), | ||
| 690 | }; | ||
| 691 | Ok(TransmitStatus { | ||
| 692 | dequeued_frame: pending_frame, | ||
| 693 | mailbox, | ||
| 694 | }) | ||
| 695 | } | ||
| 696 | |||
| 697 | /// Returns `Ok` when the mailbox is free or if it contains pending frame with a | ||
| 698 | /// lower priority (higher ID) than the identifier `id`. | ||
| 699 | fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { | ||
| 700 | // Read the pending frame's id to check its priority. | ||
| 701 | assert!(idx < 3); | ||
| 702 | let tir = &self.canregs.tx(idx).tir().read(); | ||
| 703 | //let tir = &can.tx[idx].tir.read(); | ||
| 704 | |||
| 705 | // Check the priority by comparing the identifiers. But first make sure the | ||
| 706 | // frame has not finished the transmission (`TXRQ` == 0) in the meantime. | ||
| 707 | if tir.txrq() && id <= IdReg::from_register(tir.0) { | ||
| 708 | // There's a mailbox whose priority is higher or equal | ||
| 709 | // the priority of the new frame. | ||
| 710 | return Err(nb::Error::WouldBlock); | ||
| 711 | } | ||
| 712 | |||
| 713 | Ok(()) | ||
| 714 | } | ||
| 715 | |||
| 716 | fn write_mailbox(&mut self, idx: usize, frame: &Frame) { | ||
| 717 | debug_assert!(idx < 3); | ||
| 718 | |||
| 719 | let mb = self.canregs.tx(idx); | ||
| 720 | mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); | ||
| 721 | |||
| 722 | mb.tdlr() | ||
| 723 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap())); | ||
| 724 | mb.tdhr() | ||
| 725 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap())); | ||
| 726 | let id: IdReg = frame.id().into(); | ||
| 727 | mb.tir().write(|w| { | ||
| 728 | w.0 = id.0; | ||
| 729 | w.set_txrq(true); | ||
| 730 | }); | ||
| 731 | } | ||
| 732 | |||
| 733 | fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> { | ||
| 734 | if self.abort_by_index(idx) { | ||
| 735 | debug_assert!(idx < 3); | ||
| 736 | |||
| 737 | let mb = self.canregs.tx(idx); | ||
| 738 | |||
| 739 | let id = IdReg(mb.tir().read().0); | ||
| 740 | let mut data = [0xff; 8]; | ||
| 741 | data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); | ||
| 742 | data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); | ||
| 743 | let len = mb.tdtr().read().dlc(); | ||
| 744 | |||
| 745 | Some(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap()) | ||
| 746 | } else { | ||
| 747 | // Abort request failed because the frame was already sent (or being sent) on | ||
| 748 | // the bus. All mailboxes are now free. This can happen for small prescaler | ||
| 749 | // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR | ||
| 750 | // has preempted the execution. | ||
| 751 | None | ||
| 752 | } | ||
| 753 | } | ||
| 754 | |||
| 755 | /// Tries to abort a pending frame. Returns `true` when aborted. | ||
| 756 | fn abort_by_index(&mut self, idx: usize) -> bool { | ||
| 757 | self.canregs.tsr().write(|reg| reg.set_abrq(idx, true)); | ||
| 758 | |||
| 759 | // Wait for the abort request to be finished. | ||
| 760 | loop { | ||
| 761 | let tsr = self.canregs.tsr().read(); | ||
| 762 | if false == tsr.abrq(idx) { | ||
| 763 | break tsr.txok(idx) == false; | ||
| 764 | } | ||
| 765 | } | ||
| 766 | } | 920 | } |
| 767 | 921 | ||
| 768 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | 922 | /// Attempts to abort the sending of a frame that is pending in a mailbox. |
| @@ -773,34 +927,17 @@ where | |||
| 773 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | 927 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function |
| 774 | /// returns `true`. | 928 | /// returns `true`. |
| 775 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | 929 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { |
| 776 | // If the mailbox is empty, the value of TXOKx depends on what happened with the previous | 930 | self.registers.abort(mailbox) |
| 777 | // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. | ||
| 778 | let tsr = self.canregs.tsr().read(); | ||
| 779 | let mailbox_empty = match mailbox { | ||
| 780 | Mailbox::Mailbox0 => tsr.tme(0), | ||
| 781 | Mailbox::Mailbox1 => tsr.tme(1), | ||
| 782 | Mailbox::Mailbox2 => tsr.tme(2), | ||
| 783 | }; | ||
| 784 | if mailbox_empty { | ||
| 785 | false | ||
| 786 | } else { | ||
| 787 | self.abort_by_index(mailbox as usize) | ||
| 788 | } | ||
| 789 | } | 931 | } |
| 790 | 932 | ||
| 791 | /// Returns `true` if no frame is pending for transmission. | 933 | /// Returns `true` if no frame is pending for transmission. |
| 792 | pub fn is_idle(&self) -> bool { | 934 | pub fn is_idle(&self) -> bool { |
| 793 | let tsr = self.canregs.tsr().read(); | 935 | self.registers.is_idle() |
| 794 | tsr.tme(0) && tsr.tme(1) && tsr.tme(2) | ||
| 795 | } | 936 | } |
| 796 | 937 | ||
| 797 | /// Clears the request complete flag for all mailboxes. | 938 | /// Clears the request complete flag for all mailboxes. |
| 798 | pub fn clear_interrupt_flags(&mut self) { | 939 | pub fn clear_interrupt_flags(&mut self) { |
| 799 | self.canregs.tsr().write(|reg| { | 940 | self.registers.clear_interrupt_flags() |
| 800 | reg.set_rqcp(0, true); | ||
| 801 | reg.set_rqcp(1, true); | ||
| 802 | reg.set_rqcp(2, true); | ||
| 803 | }); | ||
| 804 | } | 941 | } |
| 805 | } | 942 | } |
| 806 | 943 | ||
| @@ -814,9 +951,7 @@ where | |||
| 814 | I: Instance, | 951 | I: Instance, |
| 815 | { | 952 | { |
| 816 | unsafe fn conjure() -> Self { | 953 | unsafe fn conjure() -> Self { |
| 817 | Self { | 954 | Self { _can: PhantomData } |
| 818 | _can: PhantomData, | ||
| 819 | } | ||
| 820 | } | 955 | } |
| 821 | } | 956 | } |
| 822 | 957 | ||
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 9d2b8797e..d865bbe7d 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -14,7 +14,6 @@ use futures::FutureExt; | |||
| 14 | 14 | ||
| 15 | use crate::gpio::AFType; | 15 | use crate::gpio::AFType; |
| 16 | use crate::interrupt::typelevel::Interrupt; | 16 | use crate::interrupt::typelevel::Interrupt; |
| 17 | use crate::pac::can::vals::{Ide, Lec}; | ||
| 18 | use crate::rcc::RccPeripheral; | 17 | use crate::rcc::RccPeripheral; |
| 19 | use crate::{interrupt, peripherals, Peripheral}; | 18 | use crate::{interrupt, peripherals, Peripheral}; |
| 20 | 19 | ||
| @@ -185,7 +184,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 185 | /// This will wait for 11 consecutive recessive bits (bus idle state). | 184 | /// This will wait for 11 consecutive recessive bits (bus idle state). |
| 186 | /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. | 185 | /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. |
| 187 | pub async fn enable(&mut self) { | 186 | pub async fn enable(&mut self) { |
| 188 | while self.enable_non_blocking().is_err() { | 187 | while self.registers.enable_non_blocking().is_err() { |
| 189 | // SCE interrupt is only generated for entering sleep mode, but not leaving. | 188 | // SCE interrupt is only generated for entering sleep mode, but not leaving. |
| 190 | // Yield to allow other tasks to execute while can bus is initializing. | 189 | // Yield to allow other tasks to execute while can bus is initializing. |
| 191 | embassy_futures::yield_now().await; | 190 | embassy_futures::yield_now().await; |
| @@ -243,52 +242,17 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 243 | } | 242 | } |
| 244 | 243 | ||
| 245 | unsafe fn receive_fifo(fifo: RxFifo) { | 244 | unsafe fn receive_fifo(fifo: RxFifo) { |
| 246 | // Generate timestamp as early as possible | ||
| 247 | #[cfg(feature = "time")] | ||
| 248 | let ts = embassy_time::Instant::now(); | ||
| 249 | |||
| 250 | let state = T::state(); | 245 | let state = T::state(); |
| 251 | let regs = T::regs(); | 246 | let regsisters = crate::can::bx::Registers { canregs: T::regs() }; |
| 252 | let fifo_idx = match fifo { | ||
| 253 | RxFifo::Fifo0 => 0usize, | ||
| 254 | RxFifo::Fifo1 => 1usize, | ||
| 255 | }; | ||
| 256 | let rfr = regs.rfr(fifo_idx); | ||
| 257 | let fifo = regs.rx(fifo_idx); | ||
| 258 | 247 | ||
| 259 | loop { | 248 | loop { |
| 260 | // If there are no pending messages, there is nothing to do | 249 | match regsisters.receive_fifo(fifo) { |
| 261 | if rfr.read().fmp() == 0 { | 250 | Some(envelope) => { |
| 262 | return; | 251 | // NOTE: consensus was reached that if rx_queue is full, packets should be dropped |
| 263 | } | 252 | let _ = state.rx_queue.try_send(envelope); |
| 264 | 253 | } | |
| 265 | let rir = fifo.rir().read(); | 254 | None => return, |
| 266 | let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { | ||
| 267 | embedded_can::StandardId::new(rir.stid()).unwrap().into() | ||
| 268 | } else { | ||
| 269 | let stid = (rir.stid() & 0x7FF) as u32; | ||
| 270 | let exid = rir.exid() & 0x3FFFF; | ||
| 271 | let id = (stid << 18) | (exid); | ||
| 272 | embedded_can::ExtendedId::new(id).unwrap().into() | ||
| 273 | }; | ||
| 274 | let data_len = fifo.rdtr().read().dlc(); | ||
| 275 | let mut data: [u8; 8] = [0; 8]; | ||
| 276 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | ||
| 277 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | ||
| 278 | |||
| 279 | let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap(); | ||
| 280 | let envelope = Envelope { | ||
| 281 | #[cfg(feature = "time")] | ||
| 282 | ts, | ||
| 283 | frame, | ||
| 284 | }; | 255 | }; |
| 285 | |||
| 286 | rfr.modify(|v| v.set_rfom(true)); | ||
| 287 | |||
| 288 | /* | ||
| 289 | NOTE: consensus was reached that if rx_queue is full, packets should be dropped | ||
| 290 | */ | ||
| 291 | let _ = state.rx_queue.try_send(envelope); | ||
| 292 | } | 256 | } |
| 293 | } | 257 | } |
| 294 | 258 | ||
| @@ -297,7 +261,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 297 | /// Useful for doing separate transmit/receive tasks. | 261 | /// Useful for doing separate transmit/receive tasks. |
| 298 | pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { | 262 | pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { |
| 299 | let (tx, rx) = self.can.split_by_ref(); | 263 | let (tx, rx) = self.can.split_by_ref(); |
| 300 | (CanTx { tx }, CanRx { rx}) | 264 | (CanTx { tx }, CanRx { rx }) |
| 301 | } | 265 | } |
| 302 | } | 266 | } |
| 303 | 267 | ||
| @@ -459,10 +423,7 @@ impl<'d, T: Instance> CanRx<'d, T> { | |||
| 459 | } | 423 | } |
| 460 | } | 424 | } |
| 461 | 425 | ||
| 462 | enum RxFifo { | 426 | use crate::can::bx::RxFifo; |
| 463 | Fifo0, | ||
| 464 | Fifo1, | ||
| 465 | } | ||
| 466 | 427 | ||
| 467 | impl<'d, T: Instance> Drop for Can<'d, T> { | 428 | impl<'d, T: Instance> Drop for Can<'d, T> { |
| 468 | fn drop(&mut self) { | 429 | fn drop(&mut self) { |
| @@ -601,21 +562,4 @@ impl Index for crate::can::bx::Mailbox { | |||
| 601 | } | 562 | } |
| 602 | } | 563 | } |
| 603 | 564 | ||
| 604 | trait IntoBusError { | ||
| 605 | fn into_bus_err(self) -> Option<BusError>; | ||
| 606 | } | ||
| 607 | 565 | ||
| 608 | impl IntoBusError for Lec { | ||
| 609 | fn into_bus_err(self) -> Option<BusError> { | ||
| 610 | match self { | ||
| 611 | Lec::STUFF => Some(BusError::Stuff), | ||
| 612 | Lec::FORM => Some(BusError::Form), | ||
| 613 | Lec::ACK => Some(BusError::Acknowledge), | ||
| 614 | Lec::BITRECESSIVE => Some(BusError::BitRecessive), | ||
| 615 | Lec::BITDOMINANT => Some(BusError::BitDominant), | ||
| 616 | Lec::CRC => Some(BusError::Crc), | ||
| 617 | Lec::CUSTOM => Some(BusError::Software), | ||
| 618 | _ => None, | ||
| 619 | } | ||
| 620 | } | ||
| 621 | } | ||
diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index 1de54e5a1..8c9990798 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs | |||
| @@ -1,8 +1,15 @@ | |||
| 1 | use embassy_sync::channel::{DynamicReceiver, DynamicSender}; | 1 | use embassy_sync::channel::{DynamicReceiver, DynamicSender}; |
| 2 | 2 | ||
| 3 | use crate::can::_version::frame::*; | ||
| 4 | use crate::can::_version::Timestamp; | ||
| 5 | use crate::can::_version::enums::*; | 3 | use crate::can::_version::enums::*; |
| 4 | use crate::can::_version::frame::*; | ||
| 5 | |||
| 6 | /// Timestamp for incoming packets. Use Embassy time when enabled. | ||
| 7 | #[cfg(feature = "time")] | ||
| 8 | pub type Timestamp = embassy_time::Instant; | ||
| 9 | |||
| 10 | /// Timestamp for incoming packets. | ||
| 11 | #[cfg(not(feature = "time"))] | ||
| 12 | pub type Timestamp = u16; | ||
| 6 | 13 | ||
| 7 | pub(crate) struct ClassicBufferedRxInner { | 14 | pub(crate) struct ClassicBufferedRxInner { |
| 8 | pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, | 15 | pub rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, |
| @@ -48,4 +55,3 @@ impl BufferedCanSender { | |||
| 48 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | 55 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. |
| 49 | pub type BufferedCanReceiver = | 56 | pub type BufferedCanReceiver = |
| 50 | embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>; | 57 | embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>; |
| 51 | |||
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index c42c42853..42c9bd9f6 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs | |||
| @@ -25,7 +25,8 @@ use fd::config::*; | |||
| 25 | use fd::filter::*; | 25 | use fd::filter::*; |
| 26 | pub use fd::{config, filter}; | 26 | pub use fd::{config, filter}; |
| 27 | use frame::*; | 27 | use frame::*; |
| 28 | pub use self::common::{BufferedCanSender, BufferedCanReceiver}; | 28 | |
| 29 | pub use self::common::{BufferedCanReceiver, BufferedCanSender}; | ||
| 29 | 30 | ||
| 30 | /// Timestamp for incoming packets. Use Embassy time when enabled. | 31 | /// Timestamp for incoming packets. Use Embassy time when enabled. |
| 31 | #[cfg(feature = "time")] | 32 | #[cfg(feature = "time")] |
| @@ -416,7 +417,6 @@ pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_S | |||
| 416 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | 417 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, |
| 417 | } | 418 | } |
| 418 | 419 | ||
| 419 | |||
| 420 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | 420 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> |
| 421 | BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> | 421 | BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> |
| 422 | { | 422 | { |
