diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-04-02 01:29:52 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2024-04-02 11:08:03 +0200 |
| commit | c8936edb6c13eb099dfb31a4a51be2dd3bb4661e (patch) | |
| tree | 0dd904e9264bc0e15ab54490cf2caa91717d9d1f | |
| parent | e0f0430e2cb04f373f3e93e7abd27eba39d3eb7f (diff) | |
stm32/can: simplify bxcan api, merging bx::* into the main structs.
The bx::* separate structs (Can, Rx, Tx) and separate `Instance` trait
are a relic from the `bxcan` crate. Remove them, move the functionality
into the main structs.
| -rw-r--r-- | embassy-stm32/src/can/bx/mod.rs | 1010 | ||||
| -rw-r--r-- | embassy-stm32/src/can/bxcan/filter.rs (renamed from embassy-stm32/src/can/bx/filter.rs) | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/can/bxcan/mod.rs (renamed from embassy-stm32/src/can/bxcan.rs) | 342 | ||||
| -rw-r--r-- | embassy-stm32/src/can/bxcan/registers.rs | 510 | ||||
| -rw-r--r-- | embassy-stm32/src/can/common.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/can/fdcan.rs | 34 | ||||
| -rw-r--r-- | embassy-stm32/src/can/mod.rs | 9 | ||||
| -rw-r--r-- | examples/stm32f1/src/bin/can.rs | 13 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/can.rs | 11 | ||||
| -rw-r--r-- | examples/stm32f7/src/bin/can.rs | 12 | ||||
| -rw-r--r-- | tests/stm32/src/bin/can.rs | 19 |
11 files changed, 807 insertions, 1159 deletions
diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs deleted file mode 100644 index cd82148ba..000000000 --- a/embassy-stm32/src/can/bx/mod.rs +++ /dev/null | |||
| @@ -1,1010 +0,0 @@ | |||
| 1 | //! Driver for the STM32 bxCAN peripheral. | ||
| 2 | //! | ||
| 3 | //! This crate provides a reusable driver for the bxCAN peripheral found in many low- to middle-end | ||
| 4 | //! STM32 microcontrollers. HALs for compatible chips can reexport this crate and implement its | ||
| 5 | //! traits to easily expose a featureful CAN driver. | ||
| 6 | //! | ||
| 7 | //! # Features | ||
| 8 | //! | ||
| 9 | //! - Supports both single- and dual-peripheral configurations (where one bxCAN instance manages the | ||
| 10 | //! filters of a secondary instance). | ||
| 11 | //! - Handles standard and extended frames, and data and remote frames. | ||
| 12 | //! - Support for interrupts emitted by the bxCAN peripheral. | ||
| 13 | //! - Transmission respects CAN IDs and protects against priority inversion (a lower-priority frame | ||
| 14 | //! may be dequeued when enqueueing a higher-priority one). | ||
| 15 | //! - Implements the [`embedded-hal`] traits for interoperability. | ||
| 16 | //! - Support for both RX FIFOs (as [`Rx0`] and [`Rx1`]). | ||
| 17 | //! | ||
| 18 | //! # Limitations | ||
| 19 | //! | ||
| 20 | //! - Support for querying error states and handling error interrupts is incomplete. | ||
| 21 | //! | ||
| 22 | |||
| 23 | // Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default | ||
| 24 | #![allow(clippy::unnecessary_operation)] // lint is bugged | ||
| 25 | |||
| 26 | //mod embedded_hal; | ||
| 27 | pub mod filter; | ||
| 28 | |||
| 29 | #[allow(clippy::all)] // generated code | ||
| 30 | use core::cmp::{Ord, Ordering}; | ||
| 31 | use core::convert::Infallible; | ||
| 32 | use core::marker::PhantomData; | ||
| 33 | use core::mem; | ||
| 34 | |||
| 35 | pub use embedded_can::{ExtendedId, Id, StandardId}; | ||
| 36 | |||
| 37 | /// CAN Header: includes ID and length | ||
| 38 | pub type Header = crate::can::frame::Header; | ||
| 39 | |||
| 40 | /// Data for a CAN Frame | ||
| 41 | pub type Data = crate::can::frame::ClassicData; | ||
| 42 | |||
| 43 | use crate::can::_version::Envelope; | ||
| 44 | use crate::can::bx::filter::MasterFilters; | ||
| 45 | use crate::can::enums::BusError; | ||
| 46 | /// CAN Frame | ||
| 47 | pub use crate::can::frame::Frame; | ||
| 48 | use crate::pac::can::vals::Lec; | ||
| 49 | |||
| 50 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 51 | pub(crate) enum RxFifo { | ||
| 52 | Fifo0, | ||
| 53 | Fifo1, | ||
| 54 | } | ||
| 55 | |||
| 56 | trait IntoBusError { | ||
| 57 | fn into_bus_err(self) -> Option<BusError>; | ||
| 58 | } | ||
| 59 | |||
| 60 | impl IntoBusError for Lec { | ||
| 61 | fn into_bus_err(self) -> Option<BusError> { | ||
| 62 | match self { | ||
| 63 | Lec::STUFF => Some(BusError::Stuff), | ||
| 64 | Lec::FORM => Some(BusError::Form), | ||
| 65 | Lec::ACK => Some(BusError::Acknowledge), | ||
| 66 | Lec::BITRECESSIVE => Some(BusError::BitRecessive), | ||
| 67 | Lec::BITDOMINANT => Some(BusError::BitDominant), | ||
| 68 | Lec::CRC => Some(BusError::Crc), | ||
| 69 | Lec::CUSTOM => Some(BusError::Software), | ||
| 70 | _ => None, | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | /// A bxCAN peripheral instance. | ||
| 76 | /// | ||
| 77 | /// This trait is meant to be implemented for a HAL-specific type that represent ownership of | ||
| 78 | /// the CAN peripheral (and any pins required by it, although that is entirely up to the HAL). | ||
| 79 | /// | ||
| 80 | /// # Safety | ||
| 81 | /// | ||
| 82 | /// It is only safe to implement this trait, when: | ||
| 83 | /// | ||
| 84 | /// * The implementing type has ownership of the peripheral, preventing any other accesses to the | ||
| 85 | /// register block. | ||
| 86 | /// * `REGISTERS` is a pointer to that peripheral's register block and can be safely accessed for as | ||
| 87 | /// long as ownership or a borrow of the implementing type is present. | ||
| 88 | pub unsafe trait Instance {} | ||
| 89 | |||
| 90 | /// A bxCAN instance that owns filter banks. | ||
| 91 | /// | ||
| 92 | /// In master-slave-instance setups, only the master instance owns the filter banks, and needs to | ||
| 93 | /// split some of them off for use by the slave instance. In that case, the master instance should | ||
| 94 | /// implement [`FilterOwner`] and [`MasterInstance`], while the slave instance should only implement | ||
| 95 | /// [`Instance`]. | ||
| 96 | /// | ||
| 97 | /// In single-instance configurations, the instance owns all filter banks and they can not be split | ||
| 98 | /// off. In that case, the instance should implement [`Instance`] and [`FilterOwner`]. | ||
| 99 | /// | ||
| 100 | /// # Safety | ||
| 101 | /// | ||
| 102 | /// This trait must only be implemented if the instance does, in fact, own its associated filter | ||
| 103 | /// banks, and `NUM_FILTER_BANKS` must be correct. | ||
| 104 | pub unsafe trait FilterOwner: Instance { | ||
| 105 | /// The total number of filter banks available to the instance. | ||
| 106 | /// | ||
| 107 | /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet. | ||
| 108 | const NUM_FILTER_BANKS: u8; | ||
| 109 | } | ||
| 110 | |||
| 111 | /// A bxCAN master instance that shares filter banks with a slave instance. | ||
| 112 | /// | ||
| 113 | /// In master-slave-instance setups, this trait should be implemented for the master instance. | ||
| 114 | /// | ||
| 115 | /// # Safety | ||
| 116 | /// | ||
| 117 | /// This trait must only be implemented when there is actually an associated slave instance. | ||
| 118 | pub unsafe trait MasterInstance: FilterOwner {} | ||
| 119 | |||
| 120 | // TODO: what to do with these? | ||
| 121 | /* | ||
| 122 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Format)] | ||
| 123 | pub enum Error { | ||
| 124 | Stuff, | ||
| 125 | Form, | ||
| 126 | Acknowledgement, | ||
| 127 | BitRecessive, | ||
| 128 | BitDominant, | ||
| 129 | Crc, | ||
| 130 | Software, | ||
| 131 | }*/ | ||
| 132 | |||
| 133 | /// Error that indicates that an incoming message has been lost due to buffer overrun. | ||
| 134 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 135 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 136 | pub struct OverrunError { | ||
| 137 | _priv: (), | ||
| 138 | } | ||
| 139 | |||
| 140 | /// Identifier of a CAN message. | ||
| 141 | /// | ||
| 142 | /// Can be either a standard identifier (11bit, Range: 0..0x3FF) or a | ||
| 143 | /// extendended identifier (29bit , Range: 0..0x1FFFFFFF). | ||
| 144 | /// | ||
| 145 | /// The `Ord` trait can be used to determine the frame’s priority this ID | ||
| 146 | /// belongs to. | ||
| 147 | /// Lower identifier values have a higher priority. Additionally standard frames | ||
| 148 | /// have a higher priority than extended frames and data frames have a higher | ||
| 149 | /// priority than remote frames. | ||
| 150 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 151 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 152 | pub(crate) struct IdReg(u32); | ||
| 153 | |||
| 154 | impl IdReg { | ||
| 155 | const STANDARD_SHIFT: u32 = 21; | ||
| 156 | |||
| 157 | const EXTENDED_SHIFT: u32 = 3; | ||
| 158 | |||
| 159 | const IDE_MASK: u32 = 0x0000_0004; | ||
| 160 | |||
| 161 | const RTR_MASK: u32 = 0x0000_0002; | ||
| 162 | |||
| 163 | /// Creates a new standard identifier (11bit, Range: 0..0x7FF) | ||
| 164 | /// | ||
| 165 | /// Panics for IDs outside the allowed range. | ||
| 166 | fn new_standard(id: StandardId) -> Self { | ||
| 167 | Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT) | ||
| 168 | } | ||
| 169 | |||
| 170 | /// Creates a new extendended identifier (29bit , Range: 0..0x1FFFFFFF). | ||
| 171 | /// | ||
| 172 | /// Panics for IDs outside the allowed range. | ||
| 173 | fn new_extended(id: ExtendedId) -> IdReg { | ||
| 174 | Self(id.as_raw() << Self::EXTENDED_SHIFT | Self::IDE_MASK) | ||
| 175 | } | ||
| 176 | |||
| 177 | fn from_register(reg: u32) -> IdReg { | ||
| 178 | Self(reg & 0xFFFF_FFFE) | ||
| 179 | } | ||
| 180 | |||
| 181 | /// Returns the identifier. | ||
| 182 | fn to_id(self) -> Id { | ||
| 183 | if self.is_extended() { | ||
| 184 | Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) }) | ||
| 185 | } else { | ||
| 186 | Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) }) | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | /// Returns the identifier. | ||
| 191 | fn id(self) -> embedded_can::Id { | ||
| 192 | if self.is_extended() { | ||
| 193 | embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT) | ||
| 194 | .unwrap() | ||
| 195 | .into() | ||
| 196 | } else { | ||
| 197 | embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16) | ||
| 198 | .unwrap() | ||
| 199 | .into() | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | /// Returns `true` if the identifier is an extended identifier. | ||
| 204 | fn is_extended(self) -> bool { | ||
| 205 | self.0 & Self::IDE_MASK != 0 | ||
| 206 | } | ||
| 207 | |||
| 208 | /// Returns `true` if the identifer is part of a remote frame (RTR bit set). | ||
| 209 | fn rtr(self) -> bool { | ||
| 210 | self.0 & Self::RTR_MASK != 0 | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | impl From<&embedded_can::Id> for IdReg { | ||
| 215 | fn from(eid: &embedded_can::Id) -> Self { | ||
| 216 | match eid { | ||
| 217 | embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()), | ||
| 218 | embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()), | ||
| 219 | } | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | impl From<IdReg> for embedded_can::Id { | ||
| 224 | fn from(idr: IdReg) -> Self { | ||
| 225 | idr.id() | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | /// `IdReg` is ordered by priority. | ||
| 230 | impl Ord for IdReg { | ||
| 231 | fn cmp(&self, other: &Self) -> Ordering { | ||
| 232 | // When the IDs match, data frames have priority over remote frames. | ||
| 233 | let rtr = self.rtr().cmp(&other.rtr()).reverse(); | ||
| 234 | |||
| 235 | let id_a = self.to_id(); | ||
| 236 | let id_b = other.to_id(); | ||
| 237 | match (id_a, id_b) { | ||
| 238 | (Id::Standard(a), Id::Standard(b)) => { | ||
| 239 | // Lower IDs have priority over higher IDs. | ||
| 240 | a.as_raw().cmp(&b.as_raw()).reverse().then(rtr) | ||
| 241 | } | ||
| 242 | (Id::Extended(a), Id::Extended(b)) => a.as_raw().cmp(&b.as_raw()).reverse().then(rtr), | ||
| 243 | (Id::Standard(a), Id::Extended(b)) => { | ||
| 244 | // Standard frames have priority over extended frames if their Base IDs match. | ||
| 245 | a.as_raw() | ||
| 246 | .cmp(&b.standard_id().as_raw()) | ||
| 247 | .reverse() | ||
| 248 | .then(Ordering::Greater) | ||
| 249 | } | ||
| 250 | (Id::Extended(a), Id::Standard(b)) => { | ||
| 251 | a.standard_id().as_raw().cmp(&b.as_raw()).reverse().then(Ordering::Less) | ||
| 252 | } | ||
| 253 | } | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | impl PartialOrd for IdReg { | ||
| 258 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
| 259 | Some(self.cmp(other)) | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | pub(crate) struct Registers { | ||
| 264 | pub canregs: crate::pac::can::Can, | ||
| 265 | } | ||
| 266 | |||
| 267 | impl Registers { | ||
| 268 | fn enter_init_mode(&mut self) { | ||
| 269 | self.canregs.mcr().modify(|reg| { | ||
| 270 | reg.set_sleep(false); | ||
| 271 | reg.set_inrq(true); | ||
| 272 | }); | ||
| 273 | loop { | ||
| 274 | let msr = self.canregs.msr().read(); | ||
| 275 | if !msr.slak() && msr.inak() { | ||
| 276 | break; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | // Leaves initialization mode, enters sleep mode. | ||
| 282 | fn leave_init_mode(&mut self) { | ||
| 283 | self.canregs.mcr().modify(|reg| { | ||
| 284 | reg.set_sleep(true); | ||
| 285 | reg.set_inrq(false); | ||
| 286 | }); | ||
| 287 | loop { | ||
| 288 | let msr = self.canregs.msr().read(); | ||
| 289 | if msr.slak() && !msr.inak() { | ||
| 290 | break; | ||
| 291 | } | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { | ||
| 296 | let prescaler = u16::from(bt.prescaler) & 0x1FF; | ||
| 297 | let seg1 = u8::from(bt.seg1); | ||
| 298 | let seg2 = u8::from(bt.seg2) & 0x7F; | ||
| 299 | let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F; | ||
| 300 | self.canregs.btr().modify(|reg| { | ||
| 301 | reg.set_brp(prescaler - 1); | ||
| 302 | reg.set_ts(0, seg1 - 1); | ||
| 303 | reg.set_ts(1, seg2 - 1); | ||
| 304 | reg.set_sjw(sync_jump_width - 1); | ||
| 305 | }); | ||
| 306 | } | ||
| 307 | |||
| 308 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 309 | pub fn set_silent(&self, enabled: bool) { | ||
| 310 | let mode = match enabled { | ||
| 311 | false => stm32_metapac::can::vals::Silm::NORMAL, | ||
| 312 | true => stm32_metapac::can::vals::Silm::SILENT, | ||
| 313 | }; | ||
| 314 | self.canregs.btr().modify(|reg| reg.set_silm(mode)); | ||
| 315 | } | ||
| 316 | |||
| 317 | /// Enables or disables automatic retransmission of messages. | ||
| 318 | /// | ||
| 319 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 320 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 321 | /// | ||
| 322 | /// Automatic retransmission is enabled by default. | ||
| 323 | pub fn set_automatic_retransmit(&self, enabled: bool) { | ||
| 324 | self.canregs.mcr().modify(|reg| reg.set_nart(enabled)); | ||
| 325 | } | ||
| 326 | |||
| 327 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 328 | /// signals together. | ||
| 329 | pub fn set_loopback(&self, enabled: bool) { | ||
| 330 | self.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); | ||
| 331 | } | ||
| 332 | |||
| 333 | /// Configures the automatic wake-up feature. | ||
| 334 | /// | ||
| 335 | /// This is turned off by default. | ||
| 336 | /// | ||
| 337 | /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and | ||
| 338 | /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming | ||
| 339 | /// frame. | ||
| 340 | #[allow(dead_code)] | ||
| 341 | pub fn set_automatic_wakeup(&mut self, enabled: bool) { | ||
| 342 | self.canregs.mcr().modify(|reg| reg.set_awum(enabled)); | ||
| 343 | } | ||
| 344 | |||
| 345 | /// Leaves initialization mode and enables the peripheral (non-blocking version). | ||
| 346 | /// | ||
| 347 | /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed | ||
| 348 | /// if you want non-blocking initialization. | ||
| 349 | /// | ||
| 350 | /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself | ||
| 351 | /// in the background. The peripheral is enabled and ready to use when this method returns | ||
| 352 | /// successfully. | ||
| 353 | pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { | ||
| 354 | let msr = self.canregs.msr().read(); | ||
| 355 | if msr.slak() { | ||
| 356 | self.canregs.mcr().modify(|reg| { | ||
| 357 | reg.set_abom(true); | ||
| 358 | reg.set_sleep(false); | ||
| 359 | }); | ||
| 360 | Err(nb::Error::WouldBlock) | ||
| 361 | } else { | ||
| 362 | Ok(()) | ||
| 363 | } | ||
| 364 | } | ||
| 365 | |||
| 366 | /// Puts the peripheral in a sleep mode to save power. | ||
| 367 | /// | ||
| 368 | /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. | ||
| 369 | #[allow(dead_code)] | ||
| 370 | pub fn sleep(&mut self) { | ||
| 371 | self.canregs.mcr().modify(|reg| { | ||
| 372 | reg.set_sleep(true); | ||
| 373 | reg.set_inrq(false); | ||
| 374 | }); | ||
| 375 | loop { | ||
| 376 | let msr = self.canregs.msr().read(); | ||
| 377 | if msr.slak() && !msr.inak() { | ||
| 378 | break; | ||
| 379 | } | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | /// Disables the CAN interface. | ||
| 384 | /// | ||
| 385 | /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to | ||
| 386 | /// enter sleep mode. | ||
| 387 | pub fn reset(&self) { | ||
| 388 | self.canregs.mcr().write(|reg| reg.set_reset(true)); | ||
| 389 | } | ||
| 390 | |||
| 391 | /// Wakes up from sleep mode. | ||
| 392 | /// | ||
| 393 | /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN | ||
| 394 | /// frame will cause that interrupt. | ||
| 395 | #[allow(dead_code)] | ||
| 396 | pub fn wakeup(&mut self) { | ||
| 397 | self.canregs.mcr().modify(|reg| { | ||
| 398 | reg.set_sleep(false); | ||
| 399 | reg.set_inrq(false); | ||
| 400 | }); | ||
| 401 | loop { | ||
| 402 | let msr = self.canregs.msr().read(); | ||
| 403 | if !msr.slak() && !msr.inak() { | ||
| 404 | break; | ||
| 405 | } | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | pub fn curr_error(&self) -> Option<BusError> { | ||
| 410 | let err = { self.canregs.esr().read() }; | ||
| 411 | if err.boff() { | ||
| 412 | return Some(BusError::BusOff); | ||
| 413 | } else if err.epvf() { | ||
| 414 | return Some(BusError::BusPassive); | ||
| 415 | } else if err.ewgf() { | ||
| 416 | return Some(BusError::BusWarning); | ||
| 417 | } else if let Some(err) = err.lec().into_bus_err() { | ||
| 418 | return Some(err); | ||
| 419 | } | ||
| 420 | None | ||
| 421 | } | ||
| 422 | |||
| 423 | /// Puts a CAN frame in a transmit mailbox for transmission on the bus. | ||
| 424 | /// | ||
| 425 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). | ||
| 426 | /// Transmit order is preserved for frames with identical priority. | ||
| 427 | /// | ||
| 428 | /// If all transmit mailboxes are full, and `frame` has a higher priority than the | ||
| 429 | /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is | ||
| 430 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as | ||
| 431 | /// [`TransmitStatus::dequeued_frame`]. | ||
| 432 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { | ||
| 433 | // Get the index of the next free mailbox or the one with the lowest priority. | ||
| 434 | let tsr = self.canregs.tsr().read(); | ||
| 435 | let idx = tsr.code() as usize; | ||
| 436 | |||
| 437 | let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2); | ||
| 438 | let pending_frame = if frame_is_pending { | ||
| 439 | // High priority frames are transmitted first by the mailbox system. | ||
| 440 | // Frames with identical identifier shall be transmitted in FIFO order. | ||
| 441 | // The controller schedules pending frames of same priority based on the | ||
| 442 | // mailbox index instead. As a workaround check all pending mailboxes | ||
| 443 | // and only accept higher priority frames. | ||
| 444 | self.check_priority(0, frame.id().into())?; | ||
| 445 | self.check_priority(1, frame.id().into())?; | ||
| 446 | self.check_priority(2, frame.id().into())?; | ||
| 447 | |||
| 448 | let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); | ||
| 449 | if all_frames_are_pending { | ||
| 450 | // No free mailbox is available. This can only happen when three frames with | ||
| 451 | // ascending priority (descending IDs) were requested for transmission and all | ||
| 452 | // of them are blocked by bus traffic with even higher priority. | ||
| 453 | // To prevent a priority inversion abort and replace the lowest priority frame. | ||
| 454 | self.read_pending_mailbox(idx) | ||
| 455 | } else { | ||
| 456 | // There was a free mailbox. | ||
| 457 | None | ||
| 458 | } | ||
| 459 | } else { | ||
| 460 | // All mailboxes are available: Send frame without performing any checks. | ||
| 461 | None | ||
| 462 | }; | ||
| 463 | |||
| 464 | self.write_mailbox(idx, frame); | ||
| 465 | |||
| 466 | let mailbox = match idx { | ||
| 467 | 0 => Mailbox::Mailbox0, | ||
| 468 | 1 => Mailbox::Mailbox1, | ||
| 469 | 2 => Mailbox::Mailbox2, | ||
| 470 | _ => unreachable!(), | ||
| 471 | }; | ||
| 472 | Ok(TransmitStatus { | ||
| 473 | dequeued_frame: pending_frame, | ||
| 474 | mailbox, | ||
| 475 | }) | ||
| 476 | } | ||
| 477 | |||
| 478 | /// Returns `Ok` when the mailbox is free or if it contains pending frame with a | ||
| 479 | /// lower priority (higher ID) than the identifier `id`. | ||
| 480 | fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { | ||
| 481 | // Read the pending frame's id to check its priority. | ||
| 482 | assert!(idx < 3); | ||
| 483 | let tir = &self.canregs.tx(idx).tir().read(); | ||
| 484 | //let tir = &can.tx[idx].tir.read(); | ||
| 485 | |||
| 486 | // Check the priority by comparing the identifiers. But first make sure the | ||
| 487 | // frame has not finished the transmission (`TXRQ` == 0) in the meantime. | ||
| 488 | if tir.txrq() && id <= IdReg::from_register(tir.0) { | ||
| 489 | // There's a mailbox whose priority is higher or equal | ||
| 490 | // the priority of the new frame. | ||
| 491 | return Err(nb::Error::WouldBlock); | ||
| 492 | } | ||
| 493 | |||
| 494 | Ok(()) | ||
| 495 | } | ||
| 496 | |||
| 497 | fn write_mailbox(&mut self, idx: usize, frame: &Frame) { | ||
| 498 | debug_assert!(idx < 3); | ||
| 499 | |||
| 500 | let mb = self.canregs.tx(idx); | ||
| 501 | mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); | ||
| 502 | |||
| 503 | mb.tdlr() | ||
| 504 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap())); | ||
| 505 | mb.tdhr() | ||
| 506 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap())); | ||
| 507 | let id: IdReg = frame.id().into(); | ||
| 508 | mb.tir().write(|w| { | ||
| 509 | w.0 = id.0; | ||
| 510 | w.set_txrq(true); | ||
| 511 | }); | ||
| 512 | } | ||
| 513 | |||
| 514 | fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> { | ||
| 515 | if self.abort_by_index(idx) { | ||
| 516 | debug_assert!(idx < 3); | ||
| 517 | |||
| 518 | let mb = self.canregs.tx(idx); | ||
| 519 | |||
| 520 | let id = IdReg(mb.tir().read().0); | ||
| 521 | let mut data = [0xff; 8]; | ||
| 522 | data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); | ||
| 523 | data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); | ||
| 524 | let len = mb.tdtr().read().dlc(); | ||
| 525 | |||
| 526 | Some(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap()) | ||
| 527 | } else { | ||
| 528 | // Abort request failed because the frame was already sent (or being sent) on | ||
| 529 | // the bus. All mailboxes are now free. This can happen for small prescaler | ||
| 530 | // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR | ||
| 531 | // has preempted the execution. | ||
| 532 | None | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 | /// Tries to abort a pending frame. Returns `true` when aborted. | ||
| 537 | fn abort_by_index(&mut self, idx: usize) -> bool { | ||
| 538 | self.canregs.tsr().write(|reg| reg.set_abrq(idx, true)); | ||
| 539 | |||
| 540 | // Wait for the abort request to be finished. | ||
| 541 | loop { | ||
| 542 | let tsr = self.canregs.tsr().read(); | ||
| 543 | if false == tsr.abrq(idx) { | ||
| 544 | break tsr.txok(idx) == false; | ||
| 545 | } | ||
| 546 | } | ||
| 547 | } | ||
| 548 | |||
| 549 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 550 | /// | ||
| 551 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 552 | /// aborted, this function has no effect and returns `false`. | ||
| 553 | /// | ||
| 554 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 555 | /// returns `true`. | ||
| 556 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 557 | // If the mailbox is empty, the value of TXOKx depends on what happened with the previous | ||
| 558 | // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. | ||
| 559 | let tsr = self.canregs.tsr().read(); | ||
| 560 | let mailbox_empty = match mailbox { | ||
| 561 | Mailbox::Mailbox0 => tsr.tme(0), | ||
| 562 | Mailbox::Mailbox1 => tsr.tme(1), | ||
| 563 | Mailbox::Mailbox2 => tsr.tme(2), | ||
| 564 | }; | ||
| 565 | if mailbox_empty { | ||
| 566 | false | ||
| 567 | } else { | ||
| 568 | self.abort_by_index(mailbox as usize) | ||
| 569 | } | ||
| 570 | } | ||
| 571 | |||
| 572 | /// Returns `true` if no frame is pending for transmission. | ||
| 573 | pub fn is_idle(&self) -> bool { | ||
| 574 | let tsr = self.canregs.tsr().read(); | ||
| 575 | tsr.tme(0) && tsr.tme(1) && tsr.tme(2) | ||
| 576 | } | ||
| 577 | |||
| 578 | /// Clears the request complete flag for all mailboxes. | ||
| 579 | pub fn clear_interrupt_flags(&mut self) { | ||
| 580 | self.canregs.tsr().write(|reg| { | ||
| 581 | reg.set_rqcp(0, true); | ||
| 582 | reg.set_rqcp(1, true); | ||
| 583 | reg.set_rqcp(2, true); | ||
| 584 | }); | ||
| 585 | } | ||
| 586 | |||
| 587 | pub fn receive_frame_available(&self) -> bool { | ||
| 588 | if self.canregs.rfr(0).read().fmp() != 0 { | ||
| 589 | true | ||
| 590 | } else if self.canregs.rfr(1).read().fmp() != 0 { | ||
| 591 | true | ||
| 592 | } else { | ||
| 593 | false | ||
| 594 | } | ||
| 595 | } | ||
| 596 | |||
| 597 | pub fn receive_fifo(&self, fifo: crate::can::_version::bx::RxFifo) -> Option<Envelope> { | ||
| 598 | // Generate timestamp as early as possible | ||
| 599 | #[cfg(feature = "time")] | ||
| 600 | let ts = embassy_time::Instant::now(); | ||
| 601 | |||
| 602 | use crate::pac::can::vals::Ide; | ||
| 603 | |||
| 604 | let fifo_idx = match fifo { | ||
| 605 | crate::can::_version::bx::RxFifo::Fifo0 => 0usize, | ||
| 606 | crate::can::_version::bx::RxFifo::Fifo1 => 1usize, | ||
| 607 | }; | ||
| 608 | let rfr = self.canregs.rfr(fifo_idx); | ||
| 609 | let fifo = self.canregs.rx(fifo_idx); | ||
| 610 | |||
| 611 | // If there are no pending messages, there is nothing to do | ||
| 612 | if rfr.read().fmp() == 0 { | ||
| 613 | return None; | ||
| 614 | } | ||
| 615 | |||
| 616 | let rir = fifo.rir().read(); | ||
| 617 | let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { | ||
| 618 | embedded_can::StandardId::new(rir.stid()).unwrap().into() | ||
| 619 | } else { | ||
| 620 | let stid = (rir.stid() & 0x7FF) as u32; | ||
| 621 | let exid = rir.exid() & 0x3FFFF; | ||
| 622 | let id = (stid << 18) | (exid); | ||
| 623 | embedded_can::ExtendedId::new(id).unwrap().into() | ||
| 624 | }; | ||
| 625 | let rdtr = fifo.rdtr().read(); | ||
| 626 | let data_len = rdtr.dlc(); | ||
| 627 | let rtr = rir.rtr() == stm32_metapac::can::vals::Rtr::REMOTE; | ||
| 628 | |||
| 629 | #[cfg(not(feature = "time"))] | ||
| 630 | let ts = rdtr.time(); | ||
| 631 | |||
| 632 | let mut data: [u8; 8] = [0; 8]; | ||
| 633 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | ||
| 634 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | ||
| 635 | |||
| 636 | let frame = Frame::new(Header::new(id, data_len, rtr), &data).unwrap(); | ||
| 637 | let envelope = Envelope { ts, frame }; | ||
| 638 | |||
| 639 | rfr.modify(|v| v.set_rfom(true)); | ||
| 640 | |||
| 641 | Some(envelope) | ||
| 642 | } | ||
| 643 | } | ||
| 644 | |||
| 645 | /// Configuration proxy returned by [`Can::modify_config`]. | ||
| 646 | #[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"] | ||
| 647 | pub struct CanConfig<'a, I: Instance> { | ||
| 648 | can: &'a mut Can<I>, | ||
| 649 | } | ||
| 650 | |||
| 651 | impl<I: Instance> CanConfig<'_, I> { | ||
| 652 | /// Configures the bit timings. | ||
| 653 | /// | ||
| 654 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | ||
| 655 | /// parameters as follows: | ||
| 656 | /// | ||
| 657 | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). | ||
| 658 | /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). | ||
| 659 | /// - *Sample Point*: Should normally be left at the default value of 87.5%. | ||
| 660 | /// - *SJW*: Should normally be left at the default value of 1. | ||
| 661 | /// | ||
| 662 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | ||
| 663 | /// parameter to this method. | ||
| 664 | pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { | ||
| 665 | self.can.registers.set_bit_timing(bt); | ||
| 666 | self | ||
| 667 | } | ||
| 668 | |||
| 669 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 670 | /// signals together. | ||
| 671 | pub fn set_loopback(self, enabled: bool) -> Self { | ||
| 672 | self.can.registers.set_loopback(enabled); | ||
| 673 | self | ||
| 674 | } | ||
| 675 | |||
| 676 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 677 | pub fn set_silent(self, enabled: bool) -> Self { | ||
| 678 | self.can.registers.set_silent(enabled); | ||
| 679 | self | ||
| 680 | } | ||
| 681 | |||
| 682 | /// Enables or disables automatic retransmission of messages. | ||
| 683 | /// | ||
| 684 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 685 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 686 | /// | ||
| 687 | /// Automatic retransmission is enabled by default. | ||
| 688 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { | ||
| 689 | self.can.registers.set_automatic_retransmit(enabled); | ||
| 690 | self | ||
| 691 | } | ||
| 692 | |||
| 693 | /// Leaves initialization mode and enables the peripheral. | ||
| 694 | /// | ||
| 695 | /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected | ||
| 696 | /// on the bus. | ||
| 697 | /// | ||
| 698 | /// If you want to finish configuration without enabling the peripheral, you can call | ||
| 699 | /// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead. | ||
| 700 | pub fn enable(self) { | ||
| 701 | self.can.registers.leave_init_mode(); | ||
| 702 | |||
| 703 | match nb::block!(self.can.registers.enable_non_blocking()) { | ||
| 704 | Ok(()) => {} | ||
| 705 | Err(void) => match void {}, | ||
| 706 | } | ||
| 707 | |||
| 708 | // Don't run the destructor. | ||
| 709 | mem::forget(self); | ||
| 710 | } | ||
| 711 | |||
| 712 | /// Leaves initialization mode, but keeps the peripheral in sleep mode. | ||
| 713 | /// | ||
| 714 | /// Before the [`Can`] instance can be used, you have to enable it by calling | ||
| 715 | /// [`Can::enable_non_blocking`]. | ||
| 716 | pub fn leave_disabled(self) { | ||
| 717 | self.can.registers.leave_init_mode(); | ||
| 718 | } | ||
| 719 | } | ||
| 720 | |||
| 721 | impl<I: Instance> Drop for CanConfig<'_, I> { | ||
| 722 | #[inline] | ||
| 723 | fn drop(&mut self) { | ||
| 724 | self.can.registers.leave_init_mode(); | ||
| 725 | } | ||
| 726 | } | ||
| 727 | |||
| 728 | /// Builder returned by [`Can::builder`]. | ||
| 729 | #[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"] | ||
| 730 | pub struct CanBuilder<I: Instance> { | ||
| 731 | can: Can<I>, | ||
| 732 | } | ||
| 733 | |||
| 734 | impl<I: Instance> CanBuilder<I> { | ||
| 735 | /// Configures the bit timings. | ||
| 736 | /// | ||
| 737 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | ||
| 738 | /// parameters as follows: | ||
| 739 | /// | ||
| 740 | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). | ||
| 741 | /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). | ||
| 742 | /// - *Sample Point*: Should normally be left at the default value of 87.5%. | ||
| 743 | /// - *SJW*: Should normally be left at the default value of 1. | ||
| 744 | /// | ||
| 745 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | ||
| 746 | /// parameter to this method. | ||
| 747 | pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self { | ||
| 748 | self.can.registers.set_bit_timing(bt); | ||
| 749 | self | ||
| 750 | } | ||
| 751 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 752 | /// signals together. | ||
| 753 | pub fn set_loopback(self, enabled: bool) -> Self { | ||
| 754 | self.can.registers.set_loopback(enabled); | ||
| 755 | self | ||
| 756 | } | ||
| 757 | |||
| 758 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 759 | pub fn set_silent(self, enabled: bool) -> Self { | ||
| 760 | self.can.registers.set_silent(enabled); | ||
| 761 | self | ||
| 762 | } | ||
| 763 | |||
| 764 | /// Enables or disables automatic retransmission of messages. | ||
| 765 | /// | ||
| 766 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 767 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 768 | /// | ||
| 769 | /// Automatic retransmission is enabled by default. | ||
| 770 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { | ||
| 771 | self.can.registers.set_automatic_retransmit(enabled); | ||
| 772 | self | ||
| 773 | } | ||
| 774 | |||
| 775 | /// Leaves initialization mode and enables the peripheral. | ||
| 776 | /// | ||
| 777 | /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected | ||
| 778 | /// on the bus. | ||
| 779 | /// | ||
| 780 | /// If you want to finish configuration without enabling the peripheral, you can call | ||
| 781 | /// [`CanBuilder::leave_disabled`] instead. | ||
| 782 | pub fn enable(mut self) -> Can<I> { | ||
| 783 | self.leave_init_mode(); | ||
| 784 | |||
| 785 | match nb::block!(self.can.registers.enable_non_blocking()) { | ||
| 786 | Ok(()) => self.can, | ||
| 787 | Err(void) => match void {}, | ||
| 788 | } | ||
| 789 | } | ||
| 790 | |||
| 791 | /// Returns the [`Can`] interface without enabling it. | ||
| 792 | /// | ||
| 793 | /// This leaves initialization mode, but keeps the peripheral in sleep mode instead of enabling | ||
| 794 | /// it. | ||
| 795 | /// | ||
| 796 | /// Before the [`Can`] instance can be used, you have to enable it by calling | ||
| 797 | /// [`Can::enable_non_blocking`]. | ||
| 798 | pub fn leave_disabled(mut self) -> Can<I> { | ||
| 799 | self.leave_init_mode(); | ||
| 800 | self.can | ||
| 801 | } | ||
| 802 | |||
| 803 | /// Leaves initialization mode, enters sleep mode. | ||
| 804 | fn leave_init_mode(&mut self) { | ||
| 805 | self.can.registers.leave_init_mode(); | ||
| 806 | } | ||
| 807 | } | ||
| 808 | |||
| 809 | /// Interface to a bxCAN peripheral. | ||
| 810 | pub struct Can<I: Instance> { | ||
| 811 | instance: I, | ||
| 812 | canregs: crate::pac::can::Can, | ||
| 813 | pub(crate) registers: Registers, | ||
| 814 | } | ||
| 815 | |||
| 816 | impl<I> Can<I> | ||
| 817 | where | ||
| 818 | I: Instance, | ||
| 819 | { | ||
| 820 | /// Creates a [`CanBuilder`] for constructing a CAN interface. | ||
| 821 | pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder<I> { | ||
| 822 | let mut can_builder = CanBuilder { | ||
| 823 | can: Can { | ||
| 824 | instance, | ||
| 825 | canregs, | ||
| 826 | registers: Registers { canregs }, | ||
| 827 | }, | ||
| 828 | }; | ||
| 829 | |||
| 830 | can_builder.can.registers.enter_init_mode(); | ||
| 831 | |||
| 832 | can_builder | ||
| 833 | } | ||
| 834 | |||
| 835 | /// Disables the CAN interface and returns back the raw peripheral it was created from. | ||
| 836 | /// | ||
| 837 | /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to | ||
| 838 | /// enter sleep mode. | ||
| 839 | pub fn free(self) -> I { | ||
| 840 | self.registers.reset(); | ||
| 841 | self.instance | ||
| 842 | } | ||
| 843 | |||
| 844 | /// Configure bit timings and silent/loop-back mode. | ||
| 845 | /// | ||
| 846 | /// Calling this method will enter initialization mode. | ||
| 847 | pub fn modify_config(&mut self) -> CanConfig<'_, I> { | ||
| 848 | self.registers.enter_init_mode(); | ||
| 849 | |||
| 850 | CanConfig { can: self } | ||
| 851 | } | ||
| 852 | |||
| 853 | /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. | ||
| 854 | /// | ||
| 855 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). | ||
| 856 | /// Transmit order is preserved for frames with identical priority. | ||
| 857 | /// | ||
| 858 | /// If all transmit mailboxes are full, and `frame` has a higher priority than the | ||
| 859 | /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is | ||
| 860 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as | ||
| 861 | /// [`TransmitStatus::dequeued_frame`]. | ||
| 862 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { | ||
| 863 | // Safety: We have a `&mut self` and have unique access to the peripheral. | ||
| 864 | unsafe { Tx::<I>::conjure(self.canregs).transmit(frame) } | ||
| 865 | } | ||
| 866 | |||
| 867 | /// Returns `true` if no frame is pending for transmission. | ||
| 868 | pub fn is_transmitter_idle(&self) -> bool { | ||
| 869 | // Safety: Read-only operation. | ||
| 870 | unsafe { Tx::<I>::conjure(self.canregs).is_idle() } | ||
| 871 | } | ||
| 872 | |||
| 873 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 874 | /// | ||
| 875 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 876 | /// aborted, this function has no effect and returns `false`. | ||
| 877 | /// | ||
| 878 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 879 | /// returns `true`. | ||
| 880 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 881 | // Safety: We have a `&mut self` and have unique access to the peripheral. | ||
| 882 | unsafe { Tx::<I>::conjure(self.canregs).abort(mailbox) } | ||
| 883 | } | ||
| 884 | |||
| 885 | pub(crate) fn split_by_ref(&mut self) -> (Tx<I>, Rx<I>) { | ||
| 886 | // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. | ||
| 887 | let tx = unsafe { Tx::conjure(self.canregs) }; | ||
| 888 | let rx0 = unsafe { Rx::conjure() }; | ||
| 889 | (tx, rx0) | ||
| 890 | } | ||
| 891 | } | ||
| 892 | |||
| 893 | impl<I: FilterOwner> Can<I> { | ||
| 894 | /// Accesses the filter banks owned by this CAN peripheral. | ||
| 895 | /// | ||
| 896 | /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master | ||
| 897 | /// peripheral instead. | ||
| 898 | pub fn modify_filters(&mut self) -> MasterFilters<'_, I> { | ||
| 899 | unsafe { MasterFilters::new(self.canregs) } | ||
| 900 | } | ||
| 901 | } | ||
| 902 | |||
| 903 | /// Marker for Tx half | ||
| 904 | pub struct Tx<I> { | ||
| 905 | _can: PhantomData<I>, | ||
| 906 | pub(crate) registers: Registers, | ||
| 907 | } | ||
| 908 | |||
| 909 | impl<I> Tx<I> | ||
| 910 | where | ||
| 911 | I: Instance, | ||
| 912 | { | ||
| 913 | unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { | ||
| 914 | Self { | ||
| 915 | _can: PhantomData, | ||
| 916 | registers: Registers { canregs }, //canregs, | ||
| 917 | } | ||
| 918 | } | ||
| 919 | |||
| 920 | /// Puts a CAN frame in a transmit mailbox for transmission on the bus. | ||
| 921 | /// | ||
| 922 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). | ||
| 923 | /// Transmit order is preserved for frames with identical priority. | ||
| 924 | /// | ||
| 925 | /// If all transmit mailboxes are full, and `frame` has a higher priority than the | ||
| 926 | /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is | ||
| 927 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as | ||
| 928 | /// [`TransmitStatus::dequeued_frame`]. | ||
| 929 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { | ||
| 930 | self.registers.transmit(frame) | ||
| 931 | } | ||
| 932 | |||
| 933 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 934 | /// | ||
| 935 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 936 | /// aborted, this function has no effect and returns `false`. | ||
| 937 | /// | ||
| 938 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 939 | /// returns `true`. | ||
| 940 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 941 | self.registers.abort(mailbox) | ||
| 942 | } | ||
| 943 | |||
| 944 | /// Returns `true` if no frame is pending for transmission. | ||
| 945 | pub fn is_idle(&self) -> bool { | ||
| 946 | self.registers.is_idle() | ||
| 947 | } | ||
| 948 | |||
| 949 | /// Clears the request complete flag for all mailboxes. | ||
| 950 | pub fn clear_interrupt_flags(&mut self) { | ||
| 951 | self.registers.clear_interrupt_flags() | ||
| 952 | } | ||
| 953 | } | ||
| 954 | |||
| 955 | /// Marker for Rx half | ||
| 956 | pub struct Rx<I> { | ||
| 957 | _can: PhantomData<I>, | ||
| 958 | } | ||
| 959 | |||
| 960 | impl<I> Rx<I> | ||
| 961 | where | ||
| 962 | I: Instance, | ||
| 963 | { | ||
| 964 | unsafe fn conjure() -> Self { | ||
| 965 | Self { _can: PhantomData } | ||
| 966 | } | ||
| 967 | } | ||
| 968 | |||
| 969 | /// Identifies one of the two receive FIFOs. | ||
| 970 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||
| 971 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 972 | pub enum Fifo { | ||
| 973 | /// First receive FIFO | ||
| 974 | Fifo0 = 0, | ||
| 975 | /// Second receive FIFO | ||
| 976 | Fifo1 = 1, | ||
| 977 | } | ||
| 978 | |||
| 979 | /// Identifies one of the three transmit mailboxes. | ||
| 980 | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] | ||
| 981 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 982 | pub enum Mailbox { | ||
| 983 | /// Transmit mailbox 0 | ||
| 984 | Mailbox0 = 0, | ||
| 985 | /// Transmit mailbox 1 | ||
| 986 | Mailbox1 = 1, | ||
| 987 | /// Transmit mailbox 2 | ||
| 988 | Mailbox2 = 2, | ||
| 989 | } | ||
| 990 | |||
| 991 | /// Contains information about a frame enqueued for transmission via [`Can::transmit`] or | ||
| 992 | /// [`Tx::transmit`]. | ||
| 993 | pub struct TransmitStatus { | ||
| 994 | dequeued_frame: Option<Frame>, | ||
| 995 | mailbox: Mailbox, | ||
| 996 | } | ||
| 997 | |||
| 998 | impl TransmitStatus { | ||
| 999 | /// Returns the lower-priority frame that was dequeued to make space for the new frame. | ||
| 1000 | #[inline] | ||
| 1001 | pub fn dequeued_frame(&self) -> Option<&Frame> { | ||
| 1002 | self.dequeued_frame.as_ref() | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | /// Returns the [`Mailbox`] the frame was enqueued in. | ||
| 1006 | #[inline] | ||
| 1007 | pub fn mailbox(&self) -> Mailbox { | ||
| 1008 | self.mailbox | ||
| 1009 | } | ||
| 1010 | } | ||
diff --git a/embassy-stm32/src/can/bx/filter.rs b/embassy-stm32/src/can/bxcan/filter.rs index 51766aa31..9940c7f50 100644 --- a/embassy-stm32/src/can/bx/filter.rs +++ b/embassy-stm32/src/can/bxcan/filter.rs | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | 4 | ||
| 5 | use crate::can::bx::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; | 5 | use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; |
| 6 | 6 | ||
| 7 | const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames | 7 | const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames |
| 8 | const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers | 8 | const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers |
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan/mod.rs index fd6a79092..65fd0e9c2 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs | |||
| @@ -1,29 +1,27 @@ | |||
| 1 | pub mod filter; | ||
| 2 | mod registers; | ||
| 3 | |||
| 1 | use core::future::poll_fn; | 4 | use core::future::poll_fn; |
| 2 | use core::marker::PhantomData; | 5 | use core::marker::PhantomData; |
| 3 | use core::ops::{Deref, DerefMut}; | ||
| 4 | use core::task::Poll; | 6 | use core::task::Poll; |
| 5 | 7 | ||
| 6 | pub mod bx; | ||
| 7 | |||
| 8 | pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Header, Id, StandardId}; | ||
| 9 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 10 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 9 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 11 | use embassy_sync::channel::Channel; | 10 | use embassy_sync::channel::Channel; |
| 12 | use embassy_sync::waitqueue::AtomicWaker; | 11 | use embassy_sync::waitqueue::AtomicWaker; |
| 12 | pub use embedded_can::{ExtendedId, Id, StandardId}; | ||
| 13 | 13 | ||
| 14 | use self::filter::MasterFilters; | ||
| 15 | use self::registers::{Registers, RxFifo}; | ||
| 16 | pub use super::common::{BufferedCanReceiver, BufferedCanSender}; | ||
| 17 | use super::frame::{Envelope, Frame}; | ||
| 18 | use super::util; | ||
| 19 | use crate::can::enums::{BusError, TryReadError}; | ||
| 14 | use crate::gpio::AFType; | 20 | use crate::gpio::AFType; |
| 15 | use crate::interrupt::typelevel::Interrupt; | 21 | use crate::interrupt::typelevel::Interrupt; |
| 16 | use crate::rcc::RccPeripheral; | 22 | use crate::rcc::RccPeripheral; |
| 17 | use crate::{interrupt, peripherals, Peripheral}; | 23 | use crate::{interrupt, peripherals, Peripheral}; |
| 18 | 24 | ||
| 19 | pub mod enums; | ||
| 20 | pub mod frame; | ||
| 21 | pub mod util; | ||
| 22 | pub use frame::Envelope; | ||
| 23 | |||
| 24 | mod common; | ||
| 25 | pub use self::common::{BufferedCanReceiver, BufferedCanSender}; | ||
| 26 | |||
| 27 | /// Interrupt handler. | 25 | /// Interrupt handler. |
| 28 | pub struct TxInterruptHandler<T: Instance> { | 26 | pub struct TxInterruptHandler<T: Instance> { |
| 29 | _phantom: PhantomData<T>, | 27 | _phantom: PhantomData<T>, |
| @@ -80,9 +78,72 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup | |||
| 80 | } | 78 | } |
| 81 | } | 79 | } |
| 82 | 80 | ||
| 81 | /// Configuration proxy returned by [`Can::modify_config`]. | ||
| 82 | pub struct CanConfig<'a, T: Instance> { | ||
| 83 | can: PhantomData<&'a mut T>, | ||
| 84 | } | ||
| 85 | |||
| 86 | impl<T: Instance> CanConfig<'_, T> { | ||
| 87 | /// Configures the bit timings. | ||
| 88 | /// | ||
| 89 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | ||
| 90 | /// parameters as follows: | ||
| 91 | /// | ||
| 92 | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). | ||
| 93 | /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). | ||
| 94 | /// - *Sample Point*: Should normally be left at the default value of 87.5%. | ||
| 95 | /// - *SJW*: Should normally be left at the default value of 1. | ||
| 96 | /// | ||
| 97 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | ||
| 98 | /// parameter to this method. | ||
| 99 | pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { | ||
| 100 | Registers(T::regs()).set_bit_timing(bt); | ||
| 101 | self | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Configure the CAN bit rate. | ||
| 105 | /// | ||
| 106 | /// This is a helper that internally calls `set_bit_timing()`[Self::set_bit_timing]. | ||
| 107 | pub fn set_bitrate(self, bitrate: u32) -> Self { | ||
| 108 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); | ||
| 109 | self.set_bit_timing(bit_timing) | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 113 | /// signals together. | ||
| 114 | pub fn set_loopback(self, enabled: bool) -> Self { | ||
| 115 | Registers(T::regs()).set_loopback(enabled); | ||
| 116 | self | ||
| 117 | } | ||
| 118 | |||
| 119 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 120 | pub fn set_silent(self, enabled: bool) -> Self { | ||
| 121 | Registers(T::regs()).set_silent(enabled); | ||
| 122 | self | ||
| 123 | } | ||
| 124 | |||
| 125 | /// Enables or disables automatic retransmission of messages. | ||
| 126 | /// | ||
| 127 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 128 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 129 | /// | ||
| 130 | /// Automatic retransmission is enabled by default. | ||
| 131 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { | ||
| 132 | Registers(T::regs()).set_automatic_retransmit(enabled); | ||
| 133 | self | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | impl<T: Instance> Drop for CanConfig<'_, T> { | ||
| 138 | #[inline] | ||
| 139 | fn drop(&mut self) { | ||
| 140 | Registers(T::regs()).leave_init_mode(); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 83 | /// CAN driver | 144 | /// CAN driver |
| 84 | pub struct Can<'d, T: Instance> { | 145 | pub struct Can<'d, T: Instance> { |
| 85 | can: crate::can::bx::Can<BxcanInstance<'d, T>>, | 146 | peri: PeripheralRef<'d, T>, |
| 86 | } | 147 | } |
| 87 | 148 | ||
| 88 | /// Error returned by `try_write` | 149 | /// Error returned by `try_write` |
| @@ -145,14 +206,25 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 145 | rx.set_as_af(rx.af_num(), AFType::Input); | 206 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 146 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | 207 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 147 | 208 | ||
| 148 | let can = crate::can::bx::Can::builder(BxcanInstance(peri), T::regs()).leave_disabled(); | 209 | Registers(T::regs()).leave_init_mode(); |
| 149 | Self { can } | 210 | |
| 211 | Self { peri } | ||
| 150 | } | 212 | } |
| 151 | 213 | ||
| 152 | /// Set CAN bit rate. | 214 | /// Set CAN bit rate. |
| 153 | pub fn set_bitrate(&mut self, bitrate: u32) { | 215 | pub fn set_bitrate(&mut self, bitrate: u32) { |
| 154 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); | 216 | let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); |
| 155 | self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); | 217 | self.modify_config().set_bit_timing(bit_timing); |
| 218 | } | ||
| 219 | |||
| 220 | /// Configure bit timings and silent/loop-back mode. | ||
| 221 | /// | ||
| 222 | /// Calling this method will enter initialization mode. You must enable the peripheral | ||
| 223 | /// again afterwards with [`enable`](Self::enable). | ||
| 224 | pub fn modify_config(&mut self) -> CanConfig<'_, T> { | ||
| 225 | Registers(T::regs()).enter_init_mode(); | ||
| 226 | |||
| 227 | CanConfig { can: PhantomData } | ||
| 156 | } | 228 | } |
| 157 | 229 | ||
| 158 | /// Enables the peripheral and synchronizes with the bus. | 230 | /// Enables the peripheral and synchronizes with the bus. |
| @@ -160,7 +232,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 160 | /// This will wait for 11 consecutive recessive bits (bus idle state). | 232 | /// This will wait for 11 consecutive recessive bits (bus idle state). |
| 161 | /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. | 233 | /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. |
| 162 | pub async fn enable(&mut self) { | 234 | pub async fn enable(&mut self) { |
| 163 | while self.registers.enable_non_blocking().is_err() { | 235 | while Registers(T::regs()).enable_non_blocking().is_err() { |
| 164 | // SCE interrupt is only generated for entering sleep mode, but not leaving. | 236 | // SCE interrupt is only generated for entering sleep mode, but not leaving. |
| 165 | // Yield to allow other tasks to execute while can bus is initializing. | 237 | // Yield to allow other tasks to execute while can bus is initializing. |
| 166 | embassy_futures::yield_now().await; | 238 | embassy_futures::yield_now().await; |
| @@ -170,19 +242,19 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 170 | /// Queues the message to be sent. | 242 | /// Queues the message to be sent. |
| 171 | /// | 243 | /// |
| 172 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | 244 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. |
| 173 | pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { | 245 | pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { |
| 174 | self.split().0.write(frame).await | 246 | self.split().0.write(frame).await |
| 175 | } | 247 | } |
| 176 | 248 | ||
| 177 | /// Attempts to transmit a frame without blocking. | 249 | /// Attempts to transmit a frame without blocking. |
| 178 | /// | 250 | /// |
| 179 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | 251 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. |
| 180 | pub fn try_write(&mut self, frame: &Frame) -> Result<crate::can::bx::TransmitStatus, TryWriteError> { | 252 | pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> { |
| 181 | self.split().0.try_write(frame) | 253 | self.split().0.try_write(frame) |
| 182 | } | 254 | } |
| 183 | 255 | ||
| 184 | /// Waits for a specific transmit mailbox to become empty | 256 | /// Waits for a specific transmit mailbox to become empty |
| 185 | pub async fn flush(&self, mb: crate::can::bx::Mailbox) { | 257 | pub async fn flush(&self, mb: Mailbox) { |
| 186 | CanTx::<T>::flush_inner(mb).await | 258 | CanTx::<T>::flush_inner(mb).await |
| 187 | } | 259 | } |
| 188 | 260 | ||
| @@ -196,6 +268,22 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 196 | CanTx::<T>::flush_all_inner().await | 268 | CanTx::<T>::flush_all_inner().await |
| 197 | } | 269 | } |
| 198 | 270 | ||
| 271 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 272 | /// | ||
| 273 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 274 | /// aborted, this function has no effect and returns `false`. | ||
| 275 | /// | ||
| 276 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 277 | /// returns `true`. | ||
| 278 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 279 | Registers(T::regs()).abort(mailbox) | ||
| 280 | } | ||
| 281 | |||
| 282 | /// Returns `true` if no frame is pending for transmission. | ||
| 283 | pub fn is_transmitter_idle(&self) -> bool { | ||
| 284 | Registers(T::regs()).is_idle() | ||
| 285 | } | ||
| 286 | |||
| 199 | /// Read a CAN frame. | 287 | /// Read a CAN frame. |
| 200 | /// | 288 | /// |
| 201 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | 289 | /// If no CAN frame is in the RX buffer, this will wait until there is one. |
| @@ -221,8 +309,14 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 221 | /// | 309 | /// |
| 222 | /// Useful for doing separate transmit/receive tasks. | 310 | /// Useful for doing separate transmit/receive tasks. |
| 223 | pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { | 311 | pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { |
| 224 | let (tx, rx) = self.can.split_by_ref(); | 312 | ( |
| 225 | (CanTx { tx }, CanRx { rx }) | 313 | CanTx { |
| 314 | _peri: unsafe { self.peri.clone_unchecked() }, | ||
| 315 | }, | ||
| 316 | CanRx { | ||
| 317 | peri: unsafe { self.peri.clone_unchecked() }, | ||
| 318 | }, | ||
| 319 | ) | ||
| 226 | } | 320 | } |
| 227 | 321 | ||
| 228 | /// Return a buffered instance of driver. User must supply Buffers | 322 | /// Return a buffered instance of driver. User must supply Buffers |
| @@ -239,10 +333,13 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 239 | } | 333 | } |
| 240 | } | 334 | } |
| 241 | 335 | ||
| 242 | impl<'d, T: Instance> AsMut<crate::can::bx::Can<BxcanInstance<'d, T>>> for Can<'d, T> { | 336 | impl<'d, T: FilterOwner> Can<'d, T> { |
| 243 | /// Get mutable access to the lower-level driver from the `bxcan` crate. | 337 | /// Accesses the filter banks owned by this CAN peripheral. |
| 244 | fn as_mut(&mut self) -> &mut crate::can::bx::Can<BxcanInstance<'d, T>> { | 338 | /// |
| 245 | &mut self.can | 339 | /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master |
| 340 | /// peripheral instead. | ||
| 341 | pub fn modify_filters(&mut self) -> MasterFilters<'_, T> { | ||
| 342 | unsafe { MasterFilters::new(T::regs()) } | ||
| 246 | } | 343 | } |
| 247 | } | 344 | } |
| 248 | 345 | ||
| @@ -288,17 +385,17 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Buffer | |||
| 288 | 385 | ||
| 289 | /// CAN driver, transmit half. | 386 | /// CAN driver, transmit half. |
| 290 | pub struct CanTx<'d, T: Instance> { | 387 | pub struct CanTx<'d, T: Instance> { |
| 291 | tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, | 388 | _peri: PeripheralRef<'d, T>, |
| 292 | } | 389 | } |
| 293 | 390 | ||
| 294 | impl<'d, T: Instance> CanTx<'d, T> { | 391 | impl<'d, T: Instance> CanTx<'d, T> { |
| 295 | /// Queues the message to be sent. | 392 | /// Queues the message to be sent. |
| 296 | /// | 393 | /// |
| 297 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | 394 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. |
| 298 | pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { | 395 | pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { |
| 299 | poll_fn(|cx| { | 396 | poll_fn(|cx| { |
| 300 | T::state().tx_mode.register(cx.waker()); | 397 | T::state().tx_mode.register(cx.waker()); |
| 301 | if let Ok(status) = self.tx.transmit(frame) { | 398 | if let Ok(status) = Registers(T::regs()).transmit(frame) { |
| 302 | return Poll::Ready(status); | 399 | return Poll::Ready(status); |
| 303 | } | 400 | } |
| 304 | 401 | ||
| @@ -310,11 +407,11 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 310 | /// Attempts to transmit a frame without blocking. | 407 | /// Attempts to transmit a frame without blocking. |
| 311 | /// | 408 | /// |
| 312 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | 409 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. |
| 313 | pub fn try_write(&mut self, frame: &Frame) -> Result<crate::can::bx::TransmitStatus, TryWriteError> { | 410 | pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> { |
| 314 | self.tx.transmit(frame).map_err(|_| TryWriteError::Full) | 411 | Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full) |
| 315 | } | 412 | } |
| 316 | 413 | ||
| 317 | async fn flush_inner(mb: crate::can::bx::Mailbox) { | 414 | async fn flush_inner(mb: Mailbox) { |
| 318 | poll_fn(|cx| { | 415 | poll_fn(|cx| { |
| 319 | T::state().tx_mode.register(cx.waker()); | 416 | T::state().tx_mode.register(cx.waker()); |
| 320 | if T::regs().tsr().read().tme(mb.index()) { | 417 | if T::regs().tsr().read().tme(mb.index()) { |
| @@ -327,7 +424,7 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 327 | } | 424 | } |
| 328 | 425 | ||
| 329 | /// Waits for a specific transmit mailbox to become empty | 426 | /// Waits for a specific transmit mailbox to become empty |
| 330 | pub async fn flush(&self, mb: crate::can::bx::Mailbox) { | 427 | pub async fn flush(&self, mb: Mailbox) { |
| 331 | Self::flush_inner(mb).await | 428 | Self::flush_inner(mb).await |
| 332 | } | 429 | } |
| 333 | 430 | ||
| @@ -336,9 +433,9 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 336 | T::state().tx_mode.register(cx.waker()); | 433 | T::state().tx_mode.register(cx.waker()); |
| 337 | 434 | ||
| 338 | let tsr = T::regs().tsr().read(); | 435 | let tsr = T::regs().tsr().read(); |
| 339 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | 436 | if tsr.tme(Mailbox::Mailbox0.index()) |
| 340 | || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) | 437 | || tsr.tme(Mailbox::Mailbox1.index()) |
| 341 | || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) | 438 | || tsr.tme(Mailbox::Mailbox2.index()) |
| 342 | { | 439 | { |
| 343 | return Poll::Ready(()); | 440 | return Poll::Ready(()); |
| 344 | } | 441 | } |
| @@ -358,9 +455,9 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 358 | T::state().tx_mode.register(cx.waker()); | 455 | T::state().tx_mode.register(cx.waker()); |
| 359 | 456 | ||
| 360 | let tsr = T::regs().tsr().read(); | 457 | let tsr = T::regs().tsr().read(); |
| 361 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | 458 | if tsr.tme(Mailbox::Mailbox0.index()) |
| 362 | && tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) | 459 | && tsr.tme(Mailbox::Mailbox1.index()) |
| 363 | && tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) | 460 | && tsr.tme(Mailbox::Mailbox2.index()) |
| 364 | { | 461 | { |
| 365 | return Poll::Ready(()); | 462 | return Poll::Ready(()); |
| 366 | } | 463 | } |
| @@ -375,12 +472,28 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 375 | Self::flush_all_inner().await | 472 | Self::flush_all_inner().await |
| 376 | } | 473 | } |
| 377 | 474 | ||
| 475 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 476 | /// | ||
| 477 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 478 | /// aborted, this function has no effect and returns `false`. | ||
| 479 | /// | ||
| 480 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 481 | /// returns `true`. | ||
| 482 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 483 | Registers(T::regs()).abort(mailbox) | ||
| 484 | } | ||
| 485 | |||
| 486 | /// Returns `true` if no frame is pending for transmission. | ||
| 487 | pub fn is_idle(&self) -> bool { | ||
| 488 | Registers(T::regs()).is_idle() | ||
| 489 | } | ||
| 490 | |||
| 378 | /// Return a buffered instance of driver. User must supply Buffers | 491 | /// Return a buffered instance of driver. User must supply Buffers |
| 379 | pub fn buffered<const TX_BUF_SIZE: usize>( | 492 | pub fn buffered<const TX_BUF_SIZE: usize>( |
| 380 | self, | 493 | self, |
| 381 | txb: &'static mut TxBuf<TX_BUF_SIZE>, | 494 | txb: &'static mut TxBuf<TX_BUF_SIZE>, |
| 382 | ) -> BufferedCanTx<'d, T, TX_BUF_SIZE> { | 495 | ) -> BufferedCanTx<'d, T, TX_BUF_SIZE> { |
| 383 | BufferedCanTx::new(self.tx, txb) | 496 | BufferedCanTx::new(self, txb) |
| 384 | } | 497 | } |
| 385 | } | 498 | } |
| 386 | 499 | ||
| @@ -389,19 +502,19 @@ pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, | |||
| 389 | 502 | ||
| 390 | /// Buffered CAN driver, transmit half. | 503 | /// Buffered CAN driver, transmit half. |
| 391 | pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { | 504 | pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { |
| 392 | _tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, | 505 | _tx: CanTx<'d, T>, |
| 393 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | 506 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, |
| 394 | } | 507 | } |
| 395 | 508 | ||
| 396 | impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> { | 509 | impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> { |
| 397 | fn new(_tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self { | 510 | fn new(_tx: CanTx<'d, T>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self { |
| 398 | Self { _tx, tx_buf }.setup() | 511 | Self { _tx, tx_buf }.setup() |
| 399 | } | 512 | } |
| 400 | 513 | ||
| 401 | fn setup(self) -> Self { | 514 | fn setup(self) -> Self { |
| 402 | // We don't want interrupts being processed while we change modes. | 515 | // We don't want interrupts being processed while we change modes. |
| 403 | critical_section::with(|_| unsafe { | 516 | critical_section::with(|_| unsafe { |
| 404 | let tx_inner = self::common::ClassicBufferedTxInner { | 517 | let tx_inner = super::common::ClassicBufferedTxInner { |
| 405 | tx_receiver: self.tx_buf.receiver().into(), | 518 | tx_receiver: self.tx_buf.receiver().into(), |
| 406 | }; | 519 | }; |
| 407 | T::mut_state().tx_mode = TxMode::Buffered(tx_inner); | 520 | T::mut_state().tx_mode = TxMode::Buffered(tx_inner); |
| @@ -435,7 +548,7 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX | |||
| 435 | /// CAN driver, receive half. | 548 | /// CAN driver, receive half. |
| 436 | #[allow(dead_code)] | 549 | #[allow(dead_code)] |
| 437 | pub struct CanRx<'d, T: Instance> { | 550 | pub struct CanRx<'d, T: Instance> { |
| 438 | rx: crate::can::bx::Rx<BxcanInstance<'d, T>>, | 551 | peri: PeripheralRef<'d, T>, |
| 439 | } | 552 | } |
| 440 | 553 | ||
| 441 | impl<'d, T: Instance> CanRx<'d, T> { | 554 | impl<'d, T: Instance> CanRx<'d, T> { |
| @@ -465,7 +578,7 @@ impl<'d, T: Instance> CanRx<'d, T> { | |||
| 465 | self, | 578 | self, |
| 466 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, | 579 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, |
| 467 | ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { | 580 | ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { |
| 468 | BufferedCanRx::new(self.rx, rxb) | 581 | BufferedCanRx::new(self, rxb) |
| 469 | } | 582 | } |
| 470 | } | 583 | } |
| 471 | 584 | ||
| @@ -474,19 +587,19 @@ pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result< | |||
| 474 | 587 | ||
| 475 | /// CAN driver, receive half in Buffered mode. | 588 | /// CAN driver, receive half in Buffered mode. |
| 476 | pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { | 589 | pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { |
| 477 | _rx: crate::can::bx::Rx<BxcanInstance<'d, T>>, | 590 | _rx: CanRx<'d, T>, |
| 478 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | 591 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, |
| 479 | } | 592 | } |
| 480 | 593 | ||
| 481 | impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> { | 594 | impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> { |
| 482 | fn new(_rx: crate::can::bx::Rx<BxcanInstance<'d, T>>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self { | 595 | fn new(_rx: CanRx<'d, T>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self { |
| 483 | BufferedCanRx { _rx, rx_buf }.setup() | 596 | BufferedCanRx { _rx, rx_buf }.setup() |
| 484 | } | 597 | } |
| 485 | 598 | ||
| 486 | fn setup(self) -> Self { | 599 | fn setup(self) -> Self { |
| 487 | // We don't want interrupts being processed while we change modes. | 600 | // We don't want interrupts being processed while we change modes. |
| 488 | critical_section::with(|_| unsafe { | 601 | critical_section::with(|_| unsafe { |
| 489 | let rx_inner = self::common::ClassicBufferedRxInner { | 602 | let rx_inner = super::common::ClassicBufferedRxInner { |
| 490 | rx_sender: self.rx_buf.sender().into(), | 603 | rx_sender: self.rx_buf.sender().into(), |
| 491 | }; | 604 | }; |
| 492 | T::mut_state().rx_mode = RxMode::Buffered(rx_inner); | 605 | T::mut_state().rx_mode = RxMode::Buffered(rx_inner); |
| @@ -511,8 +624,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE | |||
| 511 | Err(e) => Err(TryReadError::BusError(e)), | 624 | Err(e) => Err(TryReadError::BusError(e)), |
| 512 | } | 625 | } |
| 513 | } else { | 626 | } else { |
| 514 | let registers = crate::can::bx::Registers { canregs: T::regs() }; | 627 | if let Some(err) = Registers(T::regs()).curr_error() { |
| 515 | if let Some(err) = registers.curr_error() { | ||
| 516 | return Err(TryReadError::BusError(err)); | 628 | return Err(TryReadError::BusError(err)); |
| 517 | } else { | 629 | } else { |
| 518 | Err(TryReadError::Empty) | 630 | Err(TryReadError::Empty) |
| @@ -544,8 +656,6 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX | |||
| 544 | } | 656 | } |
| 545 | } | 657 | } |
| 546 | 658 | ||
| 547 | use crate::can::bx::RxFifo; | ||
| 548 | |||
| 549 | impl<'d, T: Instance> Drop for Can<'d, T> { | 659 | impl<'d, T: Instance> Drop for Can<'d, T> { |
| 550 | fn drop(&mut self) { | 660 | fn drop(&mut self) { |
| 551 | // Cannot call `free()` because it moves the instance. | 661 | // Cannot call `free()` because it moves the instance. |
| @@ -555,35 +665,62 @@ impl<'d, T: Instance> Drop for Can<'d, T> { | |||
| 555 | } | 665 | } |
| 556 | } | 666 | } |
| 557 | 667 | ||
| 558 | impl<'d, T: Instance> Deref for Can<'d, T> { | 668 | /// Identifies one of the two receive FIFOs. |
| 559 | type Target = crate::can::bx::Can<BxcanInstance<'d, T>>; | 669 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] |
| 670 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 671 | pub enum Fifo { | ||
| 672 | /// First receive FIFO | ||
| 673 | Fifo0 = 0, | ||
| 674 | /// Second receive FIFO | ||
| 675 | Fifo1 = 1, | ||
| 676 | } | ||
| 560 | 677 | ||
| 561 | fn deref(&self) -> &Self::Target { | 678 | /// Identifies one of the three transmit mailboxes. |
| 562 | &self.can | 679 | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] |
| 563 | } | 680 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 681 | pub enum Mailbox { | ||
| 682 | /// Transmit mailbox 0 | ||
| 683 | Mailbox0 = 0, | ||
| 684 | /// Transmit mailbox 1 | ||
| 685 | Mailbox1 = 1, | ||
| 686 | /// Transmit mailbox 2 | ||
| 687 | Mailbox2 = 2, | ||
| 564 | } | 688 | } |
| 565 | 689 | ||
| 566 | impl<'d, T: Instance> DerefMut for Can<'d, T> { | 690 | /// Contains information about a frame enqueued for transmission via [`Can::transmit`] or |
| 567 | fn deref_mut(&mut self) -> &mut Self::Target { | 691 | /// [`Tx::transmit`]. |
| 568 | &mut self.can | 692 | pub struct TransmitStatus { |
| 569 | } | 693 | dequeued_frame: Option<Frame>, |
| 694 | mailbox: Mailbox, | ||
| 570 | } | 695 | } |
| 571 | 696 | ||
| 572 | use crate::can::enums::{BusError, TryReadError}; | 697 | impl TransmitStatus { |
| 698 | /// Returns the lower-priority frame that was dequeued to make space for the new frame. | ||
| 699 | #[inline] | ||
| 700 | pub fn dequeued_frame(&self) -> Option<&Frame> { | ||
| 701 | self.dequeued_frame.as_ref() | ||
| 702 | } | ||
| 703 | |||
| 704 | /// Returns the [`Mailbox`] the frame was enqueued in. | ||
| 705 | #[inline] | ||
| 706 | pub fn mailbox(&self) -> Mailbox { | ||
| 707 | self.mailbox | ||
| 708 | } | ||
| 709 | } | ||
| 573 | 710 | ||
| 574 | pub(crate) enum RxMode { | 711 | pub(crate) enum RxMode { |
| 575 | NonBuffered(AtomicWaker), | 712 | NonBuffered(AtomicWaker), |
| 576 | Buffered(crate::can::_version::common::ClassicBufferedRxInner), | 713 | Buffered(super::common::ClassicBufferedRxInner), |
| 577 | } | 714 | } |
| 578 | 715 | ||
| 579 | impl RxMode { | 716 | impl RxMode { |
| 580 | pub fn on_interrupt<T: Instance>(&self, fifo: crate::can::_version::bx::RxFifo) { | 717 | pub fn on_interrupt<T: Instance>(&self, fifo: RxFifo) { |
| 581 | match self { | 718 | match self { |
| 582 | Self::NonBuffered(waker) => { | 719 | Self::NonBuffered(waker) => { |
| 583 | // Disable interrupts until read | 720 | // Disable interrupts until read |
| 584 | let fifo_idx = match fifo { | 721 | let fifo_idx = match fifo { |
| 585 | crate::can::_version::bx::RxFifo::Fifo0 => 0usize, | 722 | RxFifo::Fifo0 => 0usize, |
| 586 | crate::can::_version::bx::RxFifo::Fifo1 => 1usize, | 723 | RxFifo::Fifo1 => 1usize, |
| 587 | }; | 724 | }; |
| 588 | T::regs().ier().write(|w| { | 725 | T::regs().ier().write(|w| { |
| 589 | w.set_fmpie(fifo_idx, false); | 726 | w.set_fmpie(fifo_idx, false); |
| @@ -591,10 +728,8 @@ impl RxMode { | |||
| 591 | waker.wake(); | 728 | waker.wake(); |
| 592 | } | 729 | } |
| 593 | Self::Buffered(buf) => { | 730 | Self::Buffered(buf) => { |
| 594 | let regsisters = crate::can::bx::Registers { canregs: T::regs() }; | ||
| 595 | |||
| 596 | loop { | 731 | loop { |
| 597 | match regsisters.receive_fifo(fifo) { | 732 | match Registers(T::regs()).receive_fifo(fifo) { |
| 598 | Some(envelope) => { | 733 | Some(envelope) => { |
| 599 | // NOTE: consensus was reached that if rx_queue is full, packets should be dropped | 734 | // NOTE: consensus was reached that if rx_queue is full, packets should be dropped |
| 600 | let _ = buf.rx_sender.try_send(Ok(envelope)); | 735 | let _ = buf.rx_sender.try_send(Ok(envelope)); |
| @@ -628,13 +763,13 @@ impl RxMode { | |||
| 628 | pub fn try_read<T: Instance>(&self) -> Result<Envelope, TryReadError> { | 763 | pub fn try_read<T: Instance>(&self) -> Result<Envelope, TryReadError> { |
| 629 | match self { | 764 | match self { |
| 630 | Self::NonBuffered(_) => { | 765 | Self::NonBuffered(_) => { |
| 631 | let registers = crate::can::bx::Registers { canregs: T::regs() }; | 766 | let registers = Registers(T::regs()); |
| 632 | if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo0) { | 767 | if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) { |
| 633 | T::regs().ier().write(|w| { | 768 | T::regs().ier().write(|w| { |
| 634 | w.set_fmpie(0, true); | 769 | w.set_fmpie(0, true); |
| 635 | }); | 770 | }); |
| 636 | Ok(msg) | 771 | Ok(msg) |
| 637 | } else if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo1) { | 772 | } else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) { |
| 638 | T::regs().ier().write(|w| { | 773 | T::regs().ier().write(|w| { |
| 639 | w.set_fmpie(1, true); | 774 | w.set_fmpie(1, true); |
| 640 | }); | 775 | }); |
| @@ -655,8 +790,7 @@ impl RxMode { | |||
| 655 | Self::NonBuffered(waker) => { | 790 | Self::NonBuffered(waker) => { |
| 656 | poll_fn(|cx| { | 791 | poll_fn(|cx| { |
| 657 | waker.register(cx.waker()); | 792 | waker.register(cx.waker()); |
| 658 | let registers = crate::can::bx::Registers { canregs: T::regs() }; | 793 | if Registers(T::regs()).receive_frame_available() { |
| 659 | if registers.receive_frame_available() { | ||
| 660 | Poll::Ready(()) | 794 | Poll::Ready(()) |
| 661 | } else { | 795 | } else { |
| 662 | Poll::Pending | 796 | Poll::Pending |
| @@ -673,15 +807,13 @@ impl RxMode { | |||
| 673 | 807 | ||
| 674 | enum TxMode { | 808 | enum TxMode { |
| 675 | NonBuffered(AtomicWaker), | 809 | NonBuffered(AtomicWaker), |
| 676 | Buffered(self::common::ClassicBufferedTxInner), | 810 | Buffered(super::common::ClassicBufferedTxInner), |
| 677 | } | 811 | } |
| 678 | 812 | ||
| 679 | impl TxMode { | 813 | impl TxMode { |
| 680 | pub fn buffer_free<T: Instance>(&self) -> bool { | 814 | pub fn buffer_free<T: Instance>(&self) -> bool { |
| 681 | let tsr = T::regs().tsr().read(); | 815 | let tsr = T::regs().tsr().read(); |
| 682 | tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | 816 | tsr.tme(Mailbox::Mailbox0.index()) || tsr.tme(Mailbox::Mailbox1.index()) || tsr.tme(Mailbox::Mailbox2.index()) |
| 683 | || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) | ||
| 684 | || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) | ||
| 685 | } | 817 | } |
| 686 | pub fn on_interrupt<T: Instance>(&self) { | 818 | pub fn on_interrupt<T: Instance>(&self) { |
| 687 | match &T::state().tx_mode { | 819 | match &T::state().tx_mode { |
| @@ -690,8 +822,7 @@ impl TxMode { | |||
| 690 | while self.buffer_free::<T>() { | 822 | while self.buffer_free::<T>() { |
| 691 | match buf.tx_receiver.try_receive() { | 823 | match buf.tx_receiver.try_receive() { |
| 692 | Ok(frame) => { | 824 | Ok(frame) => { |
| 693 | let mut registers = crate::can::bx::Registers { canregs: T::regs() }; | 825 | _ = Registers(T::regs()).transmit(&frame); |
| 694 | _ = registers.transmit(&frame); | ||
| 695 | } | 826 | } |
| 696 | Err(_) => { | 827 | Err(_) => { |
| 697 | break; | 828 | break; |
| @@ -738,7 +869,7 @@ trait SealedInstance { | |||
| 738 | 869 | ||
| 739 | /// CAN instance trait. | 870 | /// CAN instance trait. |
| 740 | #[allow(private_bounds)] | 871 | #[allow(private_bounds)] |
| 741 | pub trait Instance: SealedInstance + RccPeripheral + 'static { | 872 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral + 'static { |
| 742 | /// TX interrupt for this instance. | 873 | /// TX interrupt for this instance. |
| 743 | type TXInterrupt: crate::interrupt::typelevel::Interrupt; | 874 | type TXInterrupt: crate::interrupt::typelevel::Interrupt; |
| 744 | /// RX0 interrupt for this instance. | 875 | /// RX0 interrupt for this instance. |
| @@ -749,10 +880,35 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static { | |||
| 749 | type SCEInterrupt: crate::interrupt::typelevel::Interrupt; | 880 | type SCEInterrupt: crate::interrupt::typelevel::Interrupt; |
| 750 | } | 881 | } |
| 751 | 882 | ||
| 752 | /// BXCAN instance newtype. | 883 | /// A bxCAN instance that owns filter banks. |
| 753 | pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); | 884 | /// |
| 885 | /// In master-slave-instance setups, only the master instance owns the filter banks, and needs to | ||
| 886 | /// split some of them off for use by the slave instance. In that case, the master instance should | ||
| 887 | /// implement [`FilterOwner`] and [`MasterInstance`], while the slave instance should only implement | ||
| 888 | /// [`Instance`]. | ||
| 889 | /// | ||
| 890 | /// In single-instance configurations, the instance owns all filter banks and they can not be split | ||
| 891 | /// off. In that case, the instance should implement [`Instance`] and [`FilterOwner`]. | ||
| 892 | /// | ||
| 893 | /// # Safety | ||
| 894 | /// | ||
| 895 | /// This trait must only be implemented if the instance does, in fact, own its associated filter | ||
| 896 | /// banks, and `NUM_FILTER_BANKS` must be correct. | ||
| 897 | pub unsafe trait FilterOwner: Instance { | ||
| 898 | /// The total number of filter banks available to the instance. | ||
| 899 | /// | ||
| 900 | /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet. | ||
| 901 | const NUM_FILTER_BANKS: u8; | ||
| 902 | } | ||
| 754 | 903 | ||
| 755 | unsafe impl<'d, T: Instance> crate::can::bx::Instance for BxcanInstance<'d, T> {} | 904 | /// A bxCAN master instance that shares filter banks with a slave instance. |
| 905 | /// | ||
| 906 | /// In master-slave-instance setups, this trait should be implemented for the master instance. | ||
| 907 | /// | ||
| 908 | /// # Safety | ||
| 909 | /// | ||
| 910 | /// This trait must only be implemented when there is actually an associated slave instance. | ||
| 911 | pub unsafe trait MasterInstance: FilterOwner {} | ||
| 756 | 912 | ||
| 757 | foreach_peripheral!( | 913 | foreach_peripheral!( |
| 758 | (can, $inst:ident) => { | 914 | (can, $inst:ident) => { |
| @@ -782,7 +938,7 @@ foreach_peripheral!( | |||
| 782 | 938 | ||
| 783 | foreach_peripheral!( | 939 | foreach_peripheral!( |
| 784 | (can, CAN) => { | 940 | (can, CAN) => { |
| 785 | unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN> { | 941 | unsafe impl FilterOwner for peripherals::CAN { |
| 786 | const NUM_FILTER_BANKS: u8 = 14; | 942 | const NUM_FILTER_BANKS: u8 = 14; |
| 787 | } | 943 | } |
| 788 | }; | 944 | }; |
| @@ -797,19 +953,19 @@ foreach_peripheral!( | |||
| 797 | ))] { | 953 | ))] { |
| 798 | // Most L4 devices and some F7 devices use the name "CAN1" | 954 | // Most L4 devices and some F7 devices use the name "CAN1" |
| 799 | // even if there is no "CAN2" peripheral. | 955 | // even if there is no "CAN2" peripheral. |
| 800 | unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { | 956 | unsafe impl FilterOwner for peripherals::CAN1 { |
| 801 | const NUM_FILTER_BANKS: u8 = 14; | 957 | const NUM_FILTER_BANKS: u8 = 14; |
| 802 | } | 958 | } |
| 803 | } else { | 959 | } else { |
| 804 | unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN1> { | 960 | unsafe impl FilterOwner for peripherals::CAN1 { |
| 805 | const NUM_FILTER_BANKS: u8 = 28; | 961 | const NUM_FILTER_BANKS: u8 = 28; |
| 806 | } | 962 | } |
| 807 | unsafe impl<'d> crate::can::bx::MasterInstance for BxcanInstance<'d, peripherals::CAN1> {} | 963 | unsafe impl MasterInstance for peripherals::CAN1 {} |
| 808 | } | 964 | } |
| 809 | } | 965 | } |
| 810 | }; | 966 | }; |
| 811 | (can, CAN3) => { | 967 | (can, CAN3) => { |
| 812 | unsafe impl<'d> crate::can::bx::FilterOwner for BxcanInstance<'d, peripherals::CAN3> { | 968 | unsafe impl FilterOwner for peripherals::CAN3 { |
| 813 | const NUM_FILTER_BANKS: u8 = 14; | 969 | const NUM_FILTER_BANKS: u8 = 14; |
| 814 | } | 970 | } |
| 815 | }; | 971 | }; |
| @@ -822,12 +978,12 @@ trait Index { | |||
| 822 | fn index(&self) -> usize; | 978 | fn index(&self) -> usize; |
| 823 | } | 979 | } |
| 824 | 980 | ||
| 825 | impl Index for crate::can::bx::Mailbox { | 981 | impl Index for Mailbox { |
| 826 | fn index(&self) -> usize { | 982 | fn index(&self) -> usize { |
| 827 | match self { | 983 | match self { |
| 828 | crate::can::bx::Mailbox::Mailbox0 => 0, | 984 | Mailbox::Mailbox0 => 0, |
| 829 | crate::can::bx::Mailbox::Mailbox1 => 1, | 985 | Mailbox::Mailbox1 => 1, |
| 830 | crate::can::bx::Mailbox::Mailbox2 => 2, | 986 | Mailbox::Mailbox2 => 2, |
| 831 | } | 987 | } |
| 832 | } | 988 | } |
| 833 | } | 989 | } |
diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs new file mode 100644 index 000000000..732567797 --- /dev/null +++ b/embassy-stm32/src/can/bxcan/registers.rs | |||
| @@ -0,0 +1,510 @@ | |||
| 1 | use core::cmp::Ordering; | ||
| 2 | use core::convert::Infallible; | ||
| 3 | |||
| 4 | pub use embedded_can::{ExtendedId, Id, StandardId}; | ||
| 5 | use stm32_metapac::can::vals::Lec; | ||
| 6 | |||
| 7 | use super::{Mailbox, TransmitStatus}; | ||
| 8 | use crate::can::enums::BusError; | ||
| 9 | use crate::can::frame::{Envelope, Frame, Header}; | ||
| 10 | |||
| 11 | pub(crate) struct Registers(pub crate::pac::can::Can); | ||
| 12 | |||
| 13 | impl Registers { | ||
| 14 | pub fn enter_init_mode(&mut self) { | ||
| 15 | self.0.mcr().modify(|reg| { | ||
| 16 | reg.set_sleep(false); | ||
| 17 | reg.set_inrq(true); | ||
| 18 | }); | ||
| 19 | loop { | ||
| 20 | let msr = self.0.msr().read(); | ||
| 21 | if !msr.slak() && msr.inak() { | ||
| 22 | break; | ||
| 23 | } | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | // Leaves initialization mode, enters sleep mode. | ||
| 28 | pub fn leave_init_mode(&mut self) { | ||
| 29 | self.0.mcr().modify(|reg| { | ||
| 30 | reg.set_sleep(true); | ||
| 31 | reg.set_inrq(false); | ||
| 32 | }); | ||
| 33 | loop { | ||
| 34 | let msr = self.0.msr().read(); | ||
| 35 | if msr.slak() && !msr.inak() { | ||
| 36 | break; | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | pub fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { | ||
| 42 | let prescaler = u16::from(bt.prescaler) & 0x1FF; | ||
| 43 | let seg1 = u8::from(bt.seg1); | ||
| 44 | let seg2 = u8::from(bt.seg2) & 0x7F; | ||
| 45 | let sync_jump_width = u8::from(bt.sync_jump_width) & 0x7F; | ||
| 46 | self.0.btr().modify(|reg| { | ||
| 47 | reg.set_brp(prescaler - 1); | ||
| 48 | reg.set_ts(0, seg1 - 1); | ||
| 49 | reg.set_ts(1, seg2 - 1); | ||
| 50 | reg.set_sjw(sync_jump_width - 1); | ||
| 51 | }); | ||
| 52 | } | ||
| 53 | |||
| 54 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 55 | pub fn set_silent(&self, enabled: bool) { | ||
| 56 | let mode = match enabled { | ||
| 57 | false => stm32_metapac::can::vals::Silm::NORMAL, | ||
| 58 | true => stm32_metapac::can::vals::Silm::SILENT, | ||
| 59 | }; | ||
| 60 | self.0.btr().modify(|reg| reg.set_silm(mode)); | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Enables or disables automatic retransmission of messages. | ||
| 64 | /// | ||
| 65 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 66 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 67 | /// | ||
| 68 | /// Automatic retransmission is enabled by default. | ||
| 69 | pub fn set_automatic_retransmit(&self, enabled: bool) { | ||
| 70 | self.0.mcr().modify(|reg| reg.set_nart(enabled)); | ||
| 71 | } | ||
| 72 | |||
| 73 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 74 | /// signals together. | ||
| 75 | pub fn set_loopback(&self, enabled: bool) { | ||
| 76 | self.0.btr().modify(|reg| reg.set_lbkm(enabled)); | ||
| 77 | } | ||
| 78 | |||
| 79 | /// Configures the automatic wake-up feature. | ||
| 80 | /// | ||
| 81 | /// This is turned off by default. | ||
| 82 | /// | ||
| 83 | /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and | ||
| 84 | /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming | ||
| 85 | /// frame. | ||
| 86 | #[allow(dead_code)] | ||
| 87 | pub fn set_automatic_wakeup(&mut self, enabled: bool) { | ||
| 88 | self.0.mcr().modify(|reg| reg.set_awum(enabled)); | ||
| 89 | } | ||
| 90 | |||
| 91 | /// Leaves initialization mode and enables the peripheral (non-blocking version). | ||
| 92 | /// | ||
| 93 | /// Usually, it is recommended to call [`CanConfig::enable`] instead. This method is only needed | ||
| 94 | /// if you want non-blocking initialization. | ||
| 95 | /// | ||
| 96 | /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself | ||
| 97 | /// in the background. The peripheral is enabled and ready to use when this method returns | ||
| 98 | /// successfully. | ||
| 99 | pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { | ||
| 100 | let msr = self.0.msr().read(); | ||
| 101 | if msr.slak() { | ||
| 102 | self.0.mcr().modify(|reg| { | ||
| 103 | reg.set_abom(true); | ||
| 104 | reg.set_sleep(false); | ||
| 105 | }); | ||
| 106 | Err(nb::Error::WouldBlock) | ||
| 107 | } else { | ||
| 108 | Ok(()) | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Puts the peripheral in a sleep mode to save power. | ||
| 113 | /// | ||
| 114 | /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. | ||
| 115 | #[allow(dead_code)] | ||
| 116 | pub fn sleep(&mut self) { | ||
| 117 | self.0.mcr().modify(|reg| { | ||
| 118 | reg.set_sleep(true); | ||
| 119 | reg.set_inrq(false); | ||
| 120 | }); | ||
| 121 | loop { | ||
| 122 | let msr = self.0.msr().read(); | ||
| 123 | if msr.slak() && !msr.inak() { | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | /// Wakes up from sleep mode. | ||
| 130 | /// | ||
| 131 | /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN | ||
| 132 | /// frame will cause that interrupt. | ||
| 133 | #[allow(dead_code)] | ||
| 134 | pub fn wakeup(&mut self) { | ||
| 135 | self.0.mcr().modify(|reg| { | ||
| 136 | reg.set_sleep(false); | ||
| 137 | reg.set_inrq(false); | ||
| 138 | }); | ||
| 139 | loop { | ||
| 140 | let msr = self.0.msr().read(); | ||
| 141 | if !msr.slak() && !msr.inak() { | ||
| 142 | break; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | pub fn curr_error(&self) -> Option<BusError> { | ||
| 148 | let err = { self.0.esr().read() }; | ||
| 149 | if err.boff() { | ||
| 150 | return Some(BusError::BusOff); | ||
| 151 | } else if err.epvf() { | ||
| 152 | return Some(BusError::BusPassive); | ||
| 153 | } else if err.ewgf() { | ||
| 154 | return Some(BusError::BusWarning); | ||
| 155 | } else if err.lec() != Lec::NOERROR { | ||
| 156 | return Some(match err.lec() { | ||
| 157 | Lec::STUFF => BusError::Stuff, | ||
| 158 | Lec::FORM => BusError::Form, | ||
| 159 | Lec::ACK => BusError::Acknowledge, | ||
| 160 | Lec::BITRECESSIVE => BusError::BitRecessive, | ||
| 161 | Lec::BITDOMINANT => BusError::BitDominant, | ||
| 162 | Lec::CRC => BusError::Crc, | ||
| 163 | Lec::CUSTOM => BusError::Software, | ||
| 164 | Lec::NOERROR => unreachable!(), | ||
| 165 | }); | ||
| 166 | } | ||
| 167 | None | ||
| 168 | } | ||
| 169 | |||
| 170 | /// Puts a CAN frame in a transmit mailbox for transmission on the bus. | ||
| 171 | /// | ||
| 172 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). | ||
| 173 | /// Transmit order is preserved for frames with identical priority. | ||
| 174 | /// | ||
| 175 | /// If all transmit mailboxes are full, and `frame` has a higher priority than the | ||
| 176 | /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is | ||
| 177 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as | ||
| 178 | /// [`TransmitStatus::dequeued_frame`]. | ||
| 179 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { | ||
| 180 | // Get the index of the next free mailbox or the one with the lowest priority. | ||
| 181 | let tsr = self.0.tsr().read(); | ||
| 182 | let idx = tsr.code() as usize; | ||
| 183 | |||
| 184 | let frame_is_pending = !tsr.tme(0) || !tsr.tme(1) || !tsr.tme(2); | ||
| 185 | let pending_frame = if frame_is_pending { | ||
| 186 | // High priority frames are transmitted first by the mailbox system. | ||
| 187 | // Frames with identical identifier shall be transmitted in FIFO order. | ||
| 188 | // The controller schedules pending frames of same priority based on the | ||
| 189 | // mailbox index instead. As a workaround check all pending mailboxes | ||
| 190 | // and only accept higher priority frames. | ||
| 191 | self.check_priority(0, frame.id().into())?; | ||
| 192 | self.check_priority(1, frame.id().into())?; | ||
| 193 | self.check_priority(2, frame.id().into())?; | ||
| 194 | |||
| 195 | let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); | ||
| 196 | if all_frames_are_pending { | ||
| 197 | // No free mailbox is available. This can only happen when three frames with | ||
| 198 | // ascending priority (descending IDs) were requested for transmission and all | ||
| 199 | // of them are blocked by bus traffic with even higher priority. | ||
| 200 | // To prevent a priority inversion abort and replace the lowest priority frame. | ||
| 201 | self.read_pending_mailbox(idx) | ||
| 202 | } else { | ||
| 203 | // There was a free mailbox. | ||
| 204 | None | ||
| 205 | } | ||
| 206 | } else { | ||
| 207 | // All mailboxes are available: Send frame without performing any checks. | ||
| 208 | None | ||
| 209 | }; | ||
| 210 | |||
| 211 | self.write_mailbox(idx, frame); | ||
| 212 | |||
| 213 | let mailbox = match idx { | ||
| 214 | 0 => Mailbox::Mailbox0, | ||
| 215 | 1 => Mailbox::Mailbox1, | ||
| 216 | 2 => Mailbox::Mailbox2, | ||
| 217 | _ => unreachable!(), | ||
| 218 | }; | ||
| 219 | Ok(TransmitStatus { | ||
| 220 | dequeued_frame: pending_frame, | ||
| 221 | mailbox, | ||
| 222 | }) | ||
| 223 | } | ||
| 224 | |||
| 225 | /// Returns `Ok` when the mailbox is free or if it contains pending frame with a | ||
| 226 | /// lower priority (higher ID) than the identifier `id`. | ||
| 227 | fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { | ||
| 228 | // Read the pending frame's id to check its priority. | ||
| 229 | assert!(idx < 3); | ||
| 230 | let tir = &self.0.tx(idx).tir().read(); | ||
| 231 | //let tir = &can.tx[idx].tir.read(); | ||
| 232 | |||
| 233 | // Check the priority by comparing the identifiers. But first make sure the | ||
| 234 | // frame has not finished the transmission (`TXRQ` == 0) in the meantime. | ||
| 235 | if tir.txrq() && id <= IdReg::from_register(tir.0) { | ||
| 236 | // There's a mailbox whose priority is higher or equal | ||
| 237 | // the priority of the new frame. | ||
| 238 | return Err(nb::Error::WouldBlock); | ||
| 239 | } | ||
| 240 | |||
| 241 | Ok(()) | ||
| 242 | } | ||
| 243 | |||
| 244 | fn write_mailbox(&mut self, idx: usize, frame: &Frame) { | ||
| 245 | debug_assert!(idx < 3); | ||
| 246 | |||
| 247 | let mb = self.0.tx(idx); | ||
| 248 | mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); | ||
| 249 | |||
| 250 | mb.tdlr() | ||
| 251 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap())); | ||
| 252 | mb.tdhr() | ||
| 253 | .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap())); | ||
| 254 | let id: IdReg = frame.id().into(); | ||
| 255 | mb.tir().write(|w| { | ||
| 256 | w.0 = id.0; | ||
| 257 | w.set_txrq(true); | ||
| 258 | }); | ||
| 259 | } | ||
| 260 | |||
| 261 | fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> { | ||
| 262 | if self.abort_by_index(idx) { | ||
| 263 | debug_assert!(idx < 3); | ||
| 264 | |||
| 265 | let mb = self.0.tx(idx); | ||
| 266 | |||
| 267 | let id = IdReg(mb.tir().read().0); | ||
| 268 | let mut data = [0xff; 8]; | ||
| 269 | data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); | ||
| 270 | data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); | ||
| 271 | let len = mb.tdtr().read().dlc(); | ||
| 272 | |||
| 273 | Some(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap()) | ||
| 274 | } else { | ||
| 275 | // Abort request failed because the frame was already sent (or being sent) on | ||
| 276 | // the bus. All mailboxes are now free. This can happen for small prescaler | ||
| 277 | // values (e.g. 1MBit/s bit timing with a source clock of 8MHz) or when an ISR | ||
| 278 | // has preempted the execution. | ||
| 279 | None | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | /// Tries to abort a pending frame. Returns `true` when aborted. | ||
| 284 | fn abort_by_index(&mut self, idx: usize) -> bool { | ||
| 285 | self.0.tsr().write(|reg| reg.set_abrq(idx, true)); | ||
| 286 | |||
| 287 | // Wait for the abort request to be finished. | ||
| 288 | loop { | ||
| 289 | let tsr = self.0.tsr().read(); | ||
| 290 | if false == tsr.abrq(idx) { | ||
| 291 | break tsr.txok(idx) == false; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 297 | /// | ||
| 298 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 299 | /// aborted, this function has no effect and returns `false`. | ||
| 300 | /// | ||
| 301 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 302 | /// returns `true`. | ||
| 303 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 304 | // If the mailbox is empty, the value of TXOKx depends on what happened with the previous | ||
| 305 | // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. | ||
| 306 | let tsr = self.0.tsr().read(); | ||
| 307 | let mailbox_empty = match mailbox { | ||
| 308 | Mailbox::Mailbox0 => tsr.tme(0), | ||
| 309 | Mailbox::Mailbox1 => tsr.tme(1), | ||
| 310 | Mailbox::Mailbox2 => tsr.tme(2), | ||
| 311 | }; | ||
| 312 | if mailbox_empty { | ||
| 313 | false | ||
| 314 | } else { | ||
| 315 | self.abort_by_index(mailbox as usize) | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | /// Returns `true` if no frame is pending for transmission. | ||
| 320 | pub fn is_idle(&self) -> bool { | ||
| 321 | let tsr = self.0.tsr().read(); | ||
| 322 | tsr.tme(0) && tsr.tme(1) && tsr.tme(2) | ||
| 323 | } | ||
| 324 | |||
| 325 | pub fn receive_frame_available(&self) -> bool { | ||
| 326 | if self.0.rfr(0).read().fmp() != 0 { | ||
| 327 | true | ||
| 328 | } else if self.0.rfr(1).read().fmp() != 0 { | ||
| 329 | true | ||
| 330 | } else { | ||
| 331 | false | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | pub fn receive_fifo(&self, fifo: RxFifo) -> Option<Envelope> { | ||
| 336 | // Generate timestamp as early as possible | ||
| 337 | #[cfg(feature = "time")] | ||
| 338 | let ts = embassy_time::Instant::now(); | ||
| 339 | |||
| 340 | use crate::pac::can::vals::Ide; | ||
| 341 | |||
| 342 | let fifo_idx = match fifo { | ||
| 343 | RxFifo::Fifo0 => 0usize, | ||
| 344 | RxFifo::Fifo1 => 1usize, | ||
| 345 | }; | ||
| 346 | let rfr = self.0.rfr(fifo_idx); | ||
| 347 | let fifo = self.0.rx(fifo_idx); | ||
| 348 | |||
| 349 | // If there are no pending messages, there is nothing to do | ||
| 350 | if rfr.read().fmp() == 0 { | ||
| 351 | return None; | ||
| 352 | } | ||
| 353 | |||
| 354 | let rir = fifo.rir().read(); | ||
| 355 | let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { | ||
| 356 | embedded_can::StandardId::new(rir.stid()).unwrap().into() | ||
| 357 | } else { | ||
| 358 | let stid = (rir.stid() & 0x7FF) as u32; | ||
| 359 | let exid = rir.exid() & 0x3FFFF; | ||
| 360 | let id = (stid << 18) | (exid); | ||
| 361 | embedded_can::ExtendedId::new(id).unwrap().into() | ||
| 362 | }; | ||
| 363 | let rdtr = fifo.rdtr().read(); | ||
| 364 | let data_len = rdtr.dlc(); | ||
| 365 | let rtr = rir.rtr() == stm32_metapac::can::vals::Rtr::REMOTE; | ||
| 366 | |||
| 367 | #[cfg(not(feature = "time"))] | ||
| 368 | let ts = rdtr.time(); | ||
| 369 | |||
| 370 | let mut data: [u8; 8] = [0; 8]; | ||
| 371 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | ||
| 372 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | ||
| 373 | |||
| 374 | let frame = Frame::new(Header::new(id, data_len, rtr), &data).unwrap(); | ||
| 375 | let envelope = Envelope { ts, frame }; | ||
| 376 | |||
| 377 | rfr.modify(|v| v.set_rfom(true)); | ||
| 378 | |||
| 379 | Some(envelope) | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | /// Identifier of a CAN message. | ||
| 384 | /// | ||
| 385 | /// Can be either a standard identifier (11bit, Range: 0..0x3FF) or a | ||
| 386 | /// extendended identifier (29bit , Range: 0..0x1FFFFFFF). | ||
| 387 | /// | ||
| 388 | /// The `Ord` trait can be used to determine the frame’s priority this ID | ||
| 389 | /// belongs to. | ||
| 390 | /// Lower identifier values have a higher priority. Additionally standard frames | ||
| 391 | /// have a higher priority than extended frames and data frames have a higher | ||
| 392 | /// priority than remote frames. | ||
| 393 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 394 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 395 | pub(crate) struct IdReg(u32); | ||
| 396 | |||
| 397 | impl IdReg { | ||
| 398 | const STANDARD_SHIFT: u32 = 21; | ||
| 399 | |||
| 400 | const EXTENDED_SHIFT: u32 = 3; | ||
| 401 | |||
| 402 | const IDE_MASK: u32 = 0x0000_0004; | ||
| 403 | |||
| 404 | const RTR_MASK: u32 = 0x0000_0002; | ||
| 405 | |||
| 406 | /// Creates a new standard identifier (11bit, Range: 0..0x7FF) | ||
| 407 | /// | ||
| 408 | /// Panics for IDs outside the allowed range. | ||
| 409 | fn new_standard(id: StandardId) -> Self { | ||
| 410 | Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT) | ||
| 411 | } | ||
| 412 | |||
| 413 | /// Creates a new extendended identifier (29bit , Range: 0..0x1FFFFFFF). | ||
| 414 | /// | ||
| 415 | /// Panics for IDs outside the allowed range. | ||
| 416 | fn new_extended(id: ExtendedId) -> IdReg { | ||
| 417 | Self(id.as_raw() << Self::EXTENDED_SHIFT | Self::IDE_MASK) | ||
| 418 | } | ||
| 419 | |||
| 420 | fn from_register(reg: u32) -> IdReg { | ||
| 421 | Self(reg & 0xFFFF_FFFE) | ||
| 422 | } | ||
| 423 | |||
| 424 | /// Returns the identifier. | ||
| 425 | fn to_id(self) -> Id { | ||
| 426 | if self.is_extended() { | ||
| 427 | Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) }) | ||
| 428 | } else { | ||
| 429 | Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) }) | ||
| 430 | } | ||
| 431 | } | ||
| 432 | |||
| 433 | /// Returns the identifier. | ||
| 434 | fn id(self) -> embedded_can::Id { | ||
| 435 | if self.is_extended() { | ||
| 436 | embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT) | ||
| 437 | .unwrap() | ||
| 438 | .into() | ||
| 439 | } else { | ||
| 440 | embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16) | ||
| 441 | .unwrap() | ||
| 442 | .into() | ||
| 443 | } | ||
| 444 | } | ||
| 445 | |||
| 446 | /// Returns `true` if the identifier is an extended identifier. | ||
| 447 | fn is_extended(self) -> bool { | ||
| 448 | self.0 & Self::IDE_MASK != 0 | ||
| 449 | } | ||
| 450 | |||
| 451 | /// Returns `true` if the identifer is part of a remote frame (RTR bit set). | ||
| 452 | fn rtr(self) -> bool { | ||
| 453 | self.0 & Self::RTR_MASK != 0 | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | impl From<&embedded_can::Id> for IdReg { | ||
| 458 | fn from(eid: &embedded_can::Id) -> Self { | ||
| 459 | match eid { | ||
| 460 | embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()), | ||
| 461 | embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()), | ||
| 462 | } | ||
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 466 | impl From<IdReg> for embedded_can::Id { | ||
| 467 | fn from(idr: IdReg) -> Self { | ||
| 468 | idr.id() | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | /// `IdReg` is ordered by priority. | ||
| 473 | impl Ord for IdReg { | ||
| 474 | fn cmp(&self, other: &Self) -> Ordering { | ||
| 475 | // When the IDs match, data frames have priority over remote frames. | ||
| 476 | let rtr = self.rtr().cmp(&other.rtr()).reverse(); | ||
| 477 | |||
| 478 | let id_a = self.to_id(); | ||
| 479 | let id_b = other.to_id(); | ||
| 480 | match (id_a, id_b) { | ||
| 481 | (Id::Standard(a), Id::Standard(b)) => { | ||
| 482 | // Lower IDs have priority over higher IDs. | ||
| 483 | a.as_raw().cmp(&b.as_raw()).reverse().then(rtr) | ||
| 484 | } | ||
| 485 | (Id::Extended(a), Id::Extended(b)) => a.as_raw().cmp(&b.as_raw()).reverse().then(rtr), | ||
| 486 | (Id::Standard(a), Id::Extended(b)) => { | ||
| 487 | // Standard frames have priority over extended frames if their Base IDs match. | ||
| 488 | a.as_raw() | ||
| 489 | .cmp(&b.standard_id().as_raw()) | ||
| 490 | .reverse() | ||
| 491 | .then(Ordering::Greater) | ||
| 492 | } | ||
| 493 | (Id::Extended(a), Id::Standard(b)) => { | ||
| 494 | a.standard_id().as_raw().cmp(&b.as_raw()).reverse().then(Ordering::Less) | ||
| 495 | } | ||
| 496 | } | ||
| 497 | } | ||
| 498 | } | ||
| 499 | |||
| 500 | impl PartialOrd for IdReg { | ||
| 501 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
| 502 | Some(self.cmp(other)) | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 506 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 507 | pub(crate) enum RxFifo { | ||
| 508 | Fifo0, | ||
| 509 | Fifo1, | ||
| 510 | } | ||
diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index 570761b19..a54b54f6e 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | use embassy_sync::channel::{DynamicReceiver, DynamicSender}; | 1 | use embassy_sync::channel::{DynamicReceiver, DynamicSender}; |
| 2 | 2 | ||
| 3 | use crate::can::_version::enums::*; | 3 | use super::enums::*; |
| 4 | use crate::can::_version::frame::*; | 4 | use super::frame::*; |
| 5 | 5 | ||
| 6 | pub(crate) struct ClassicBufferedRxInner { | 6 | pub(crate) struct ClassicBufferedRxInner { |
| 7 | pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>, | 7 | pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>, |
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 2ccf4b093..e31821ca2 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs | |||
| @@ -14,19 +14,15 @@ use crate::interrupt::typelevel::Interrupt; | |||
| 14 | use crate::rcc::RccPeripheral; | 14 | use crate::rcc::RccPeripheral; |
| 15 | use crate::{interrupt, peripherals, Peripheral}; | 15 | use crate::{interrupt, peripherals, Peripheral}; |
| 16 | 16 | ||
| 17 | mod common; | ||
| 18 | pub mod enums; | ||
| 19 | pub(crate) mod fd; | 17 | pub(crate) mod fd; |
| 20 | pub mod frame; | ||
| 21 | mod util; | ||
| 22 | 18 | ||
| 23 | use enums::*; | 19 | use self::fd::config::*; |
| 24 | use fd::config::*; | 20 | use self::fd::filter::*; |
| 25 | use fd::filter::*; | 21 | pub use self::fd::{config, filter}; |
| 26 | pub use fd::{config, filter}; | 22 | pub use super::common::{BufferedCanReceiver, BufferedCanSender}; |
| 27 | use frame::*; | 23 | use super::enums::*; |
| 28 | 24 | use super::frame::*; | |
| 29 | pub use self::common::{BufferedCanReceiver, BufferedCanSender}; | 25 | use super::util; |
| 30 | 26 | ||
| 31 | /// Timestamp for incoming packets. Use Embassy time when enabled. | 27 | /// Timestamp for incoming packets. Use Embassy time when enabled. |
| 32 | #[cfg(feature = "time")] | 28 | #[cfg(feature = "time")] |
| @@ -439,10 +435,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 439 | fn setup(self) -> Self { | 435 | fn setup(self) -> Self { |
| 440 | // We don't want interrupts being processed while we change modes. | 436 | // We don't want interrupts being processed while we change modes. |
| 441 | critical_section::with(|_| unsafe { | 437 | critical_section::with(|_| unsafe { |
| 442 | let rx_inner = self::common::ClassicBufferedRxInner { | 438 | let rx_inner = super::common::ClassicBufferedRxInner { |
| 443 | rx_sender: self.rx_buf.sender().into(), | 439 | rx_sender: self.rx_buf.sender().into(), |
| 444 | }; | 440 | }; |
| 445 | let tx_inner = self::common::ClassicBufferedTxInner { | 441 | let tx_inner = super::common::ClassicBufferedTxInner { |
| 446 | tx_receiver: self.tx_buf.receiver().into(), | 442 | tx_receiver: self.tx_buf.receiver().into(), |
| 447 | }; | 443 | }; |
| 448 | T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner); | 444 | T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner); |
| @@ -555,10 +551,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 555 | fn setup(self) -> Self { | 551 | fn setup(self) -> Self { |
| 556 | // We don't want interrupts being processed while we change modes. | 552 | // We don't want interrupts being processed while we change modes. |
| 557 | critical_section::with(|_| unsafe { | 553 | critical_section::with(|_| unsafe { |
| 558 | let rx_inner = self::common::FdBufferedRxInner { | 554 | let rx_inner = super::common::FdBufferedRxInner { |
| 559 | rx_sender: self.rx_buf.sender().into(), | 555 | rx_sender: self.rx_buf.sender().into(), |
| 560 | }; | 556 | }; |
| 561 | let tx_inner = self::common::FdBufferedTxInner { | 557 | let tx_inner = super::common::FdBufferedTxInner { |
| 562 | tx_receiver: self.tx_buf.receiver().into(), | 558 | tx_receiver: self.tx_buf.receiver().into(), |
| 563 | }; | 559 | }; |
| 564 | T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner); | 560 | T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner); |
| @@ -649,8 +645,8 @@ impl<'c, 'd, T: Instance> CanRx<'d, T> { | |||
| 649 | 645 | ||
| 650 | enum RxMode { | 646 | enum RxMode { |
| 651 | NonBuffered(AtomicWaker), | 647 | NonBuffered(AtomicWaker), |
| 652 | ClassicBuffered(self::common::ClassicBufferedRxInner), | 648 | ClassicBuffered(super::common::ClassicBufferedRxInner), |
| 653 | FdBuffered(self::common::FdBufferedRxInner), | 649 | FdBuffered(super::common::FdBufferedRxInner), |
| 654 | } | 650 | } |
| 655 | 651 | ||
| 656 | impl RxMode { | 652 | impl RxMode { |
| @@ -758,8 +754,8 @@ impl RxMode { | |||
| 758 | 754 | ||
| 759 | enum TxMode { | 755 | enum TxMode { |
| 760 | NonBuffered(AtomicWaker), | 756 | NonBuffered(AtomicWaker), |
| 761 | ClassicBuffered(self::common::ClassicBufferedTxInner), | 757 | ClassicBuffered(super::common::ClassicBufferedTxInner), |
| 762 | FdBuffered(self::common::FdBufferedTxInner), | 758 | FdBuffered(super::common::FdBufferedTxInner), |
| 763 | } | 759 | } |
| 764 | 760 | ||
| 765 | impl TxMode { | 761 | impl TxMode { |
diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs index 915edb3a6..410a6bfcb 100644 --- a/embassy-stm32/src/can/mod.rs +++ b/embassy-stm32/src/can/mod.rs | |||
| @@ -1,7 +1,14 @@ | |||
| 1 | //! Controller Area Network (CAN) | 1 | //! Controller Area Network (CAN) |
| 2 | #![macro_use] | 2 | #![macro_use] |
| 3 | 3 | ||
| 4 | #[cfg_attr(can_bxcan, path = "bxcan.rs")] | 4 | #[cfg_attr(can_bxcan, path = "bxcan/mod.rs")] |
| 5 | #[cfg_attr(any(can_fdcan_v1, can_fdcan_h7), path = "fdcan.rs")] | 5 | #[cfg_attr(any(can_fdcan_v1, can_fdcan_h7), path = "fdcan.rs")] |
| 6 | mod _version; | 6 | mod _version; |
| 7 | pub use _version::*; | 7 | pub use _version::*; |
| 8 | |||
| 9 | mod common; | ||
| 10 | pub mod enums; | ||
| 11 | pub mod frame; | ||
| 12 | pub mod util; | ||
| 13 | |||
| 14 | pub use frame::Frame; | ||
diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index 90cb9e46b..1c13d623d 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs | |||
| @@ -3,8 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::can::frame::Envelope; | ||
| 6 | use embassy_stm32::can::{ | 7 | use embassy_stm32::can::{ |
| 7 | filter, Can, Envelope, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, | 8 | filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, |
| 8 | TxInterruptHandler, | 9 | TxInterruptHandler, |
| 9 | }; | 10 | }; |
| 10 | use embassy_stm32::peripherals::CAN; | 11 | use embassy_stm32::peripherals::CAN; |
| @@ -55,17 +56,13 @@ async fn main(_spawner: Spawner) { | |||
| 55 | 56 | ||
| 56 | let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); | 57 | let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); |
| 57 | 58 | ||
| 58 | can.as_mut() | 59 | can.modify_filters() |
| 59 | .modify_filters() | ||
| 60 | .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all()); | 60 | .enable_bank(0, Fifo::Fifo0, filter::Mask32::accept_all()); |
| 61 | 61 | ||
| 62 | can.as_mut() | 62 | can.modify_config() |
| 63 | .modify_config() | ||
| 64 | .set_loopback(false) | 63 | .set_loopback(false) |
| 65 | .set_silent(false) | 64 | .set_silent(false) |
| 66 | .leave_disabled(); | 65 | .set_bitrate(250_000); |
| 67 | |||
| 68 | can.set_bitrate(250_000); | ||
| 69 | 66 | ||
| 70 | can.enable().await; | 67 | can.enable().await; |
| 71 | let mut i: u8 = 0; | 68 | let mut i: u8 = 0; |
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index 71b9453eb..cedc057a7 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs | |||
| @@ -35,17 +35,12 @@ async fn main(_spawner: Spawner) { | |||
| 35 | 35 | ||
| 36 | let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); | 36 | let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); |
| 37 | 37 | ||
| 38 | can.as_mut() | 38 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); |
| 39 | .modify_filters() | ||
| 40 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 41 | 39 | ||
| 42 | can.as_mut() | 40 | can.modify_config() |
| 43 | .modify_config() | ||
| 44 | .set_loopback(true) // Receive own frames | 41 | .set_loopback(true) // Receive own frames |
| 45 | .set_silent(true) | 42 | .set_silent(true) |
| 46 | .leave_disabled(); | 43 | .set_bitrate(1_000_000); |
| 47 | |||
| 48 | can.set_bitrate(1_000_000); | ||
| 49 | 44 | ||
| 50 | can.enable().await; | 45 | can.enable().await; |
| 51 | 46 | ||
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index 221ac2a05..e32b4d3df 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs | |||
| @@ -47,20 +47,18 @@ async fn main(spawner: Spawner) { | |||
| 47 | 47 | ||
| 48 | static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new(); | 48 | static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new(); |
| 49 | let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); | 49 | let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); |
| 50 | can.as_mut() | 50 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); |
| 51 | .modify_filters() | ||
| 52 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 53 | 51 | ||
| 54 | can.as_mut() | 52 | can.modify_config() |
| 55 | .modify_config() | ||
| 56 | .set_bit_timing(can::util::NominalBitTiming { | 53 | .set_bit_timing(can::util::NominalBitTiming { |
| 57 | prescaler: NonZeroU16::new(2).unwrap(), | 54 | prescaler: NonZeroU16::new(2).unwrap(), |
| 58 | seg1: NonZeroU8::new(13).unwrap(), | 55 | seg1: NonZeroU8::new(13).unwrap(), |
| 59 | seg2: NonZeroU8::new(2).unwrap(), | 56 | seg2: NonZeroU8::new(2).unwrap(), |
| 60 | sync_jump_width: NonZeroU8::new(1).unwrap(), | 57 | sync_jump_width: NonZeroU8::new(1).unwrap(), |
| 61 | }) // http://www.bittiming.can-wiki.info/ | 58 | }) // http://www.bittiming.can-wiki.info/ |
| 62 | .set_loopback(true) | 59 | .set_loopback(true); |
| 63 | .enable(); | 60 | |
| 61 | can.enable().await; | ||
| 64 | 62 | ||
| 65 | let (tx, mut rx) = can.split(); | 63 | let (tx, mut rx) = can.split(); |
| 66 | 64 | ||
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index 74d84c42f..551764458 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs | |||
| @@ -8,9 +8,10 @@ mod common; | |||
| 8 | use common::*; | 8 | use common::*; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_stm32::bind_interrupts; | 10 | use embassy_stm32::bind_interrupts; |
| 11 | use embassy_stm32::can::bx::filter::Mask32; | 11 | use embassy_stm32::can::filter::Mask32; |
| 12 | use embassy_stm32::can::bx::Fifo; | 12 | use embassy_stm32::can::{ |
| 13 | use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; | 13 | Can, Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, |
| 14 | }; | ||
| 14 | use embassy_stm32::gpio::{Input, Pull}; | 15 | use embassy_stm32::gpio::{Input, Pull}; |
| 15 | use embassy_stm32::peripherals::CAN1; | 16 | use embassy_stm32::peripherals::CAN1; |
| 16 | use embassy_time::Duration; | 17 | use embassy_time::Duration; |
| @@ -51,17 +52,15 @@ async fn main(_spawner: Spawner) { | |||
| 51 | 52 | ||
| 52 | info!("Configuring can..."); | 53 | info!("Configuring can..."); |
| 53 | 54 | ||
| 54 | can.as_mut() | 55 | can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); |
| 55 | .modify_filters() | ||
| 56 | .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); | ||
| 57 | 56 | ||
| 58 | can.set_bitrate(1_000_000); | 57 | can.modify_config() |
| 59 | can.as_mut() | ||
| 60 | .modify_config() | ||
| 61 | .set_loopback(true) // Receive own frames | 58 | .set_loopback(true) // Receive own frames |
| 62 | .set_silent(true) | 59 | .set_silent(true) |
| 63 | // .set_bit_timing(0x001c0003) | 60 | // .set_bit_timing(0x001c0003) |
| 64 | .enable(); | 61 | .set_bitrate(1_000_000); |
| 62 | |||
| 63 | can.enable().await; | ||
| 65 | 64 | ||
| 66 | info!("Can configured"); | 65 | info!("Can configured"); |
| 67 | 66 | ||
