diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-03-28 00:10:11 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-03-28 00:10:11 +0000 |
| commit | 393de9e19f12528a11ba98658c29d4fb43f75fa0 (patch) | |
| tree | e6e144041c6d973066b8fffd979650eb443ef7a3 | |
| parent | 8f6c07c7750647edf9acea76cf6fe0ca1bc4da87 (diff) | |
| parent | 25618cd93d5209d864fa250b2077a59532e0bedf (diff) | |
Merge pull request #2744 from cschuhen/feature/bxcan_use_fdcan_api
Synchronise the feature sets and API between BXCAN and FDCAN.
| -rw-r--r-- | embassy-stm32/src/can/bx/mod.rs | 815 | ||||
| -rw-r--r-- | embassy-stm32/src/can/bxcan.rs | 519 | ||||
| -rw-r--r-- | embassy-stm32/src/can/common.rs | 52 | ||||
| -rw-r--r-- | embassy-stm32/src/can/enums.rs | 10 | ||||
| -rw-r--r-- | embassy-stm32/src/can/fd/peripheral.rs | 12 | ||||
| -rw-r--r-- | embassy-stm32/src/can/fdcan.rs | 207 | ||||
| -rw-r--r-- | embassy-stm32/src/can/frame.rs | 67 | ||||
| -rw-r--r-- | examples/stm32f1/Cargo.toml | 1 | ||||
| -rw-r--r-- | examples/stm32f1/src/bin/can.rs | 102 | ||||
| -rw-r--r-- | examples/stm32g4/src/bin/can.rs | 29 | ||||
| -rw-r--r-- | examples/stm32h5/src/bin/can.rs | 12 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/can.rs | 12 | ||||
| -rw-r--r-- | tests/stm32/src/bin/can.rs | 50 | ||||
| -rw-r--r-- | tests/stm32/src/bin/can_common.rs | 112 | ||||
| -rw-r--r-- | tests/stm32/src/bin/fdcan.rs | 199 |
15 files changed, 1305 insertions, 894 deletions
diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs index 121da1bb2..cd82148ba 100644 --- a/embassy-stm32/src/can/bx/mod.rs +++ b/embassy-stm32/src/can/bx/mod.rs | |||
| @@ -40,10 +40,37 @@ pub type Header = crate::can::frame::Header; | |||
| 40 | /// Data for a CAN Frame | 40 | /// Data for a CAN Frame |
| 41 | pub type Data = crate::can::frame::ClassicData; | 41 | pub type Data = crate::can::frame::ClassicData; |
| 42 | 42 | ||
| 43 | use crate::can::_version::Envelope; | ||
| 44 | use crate::can::bx::filter::MasterFilters; | ||
| 45 | use crate::can::enums::BusError; | ||
| 43 | /// CAN Frame | 46 | /// CAN Frame |
| 44 | pub type Frame = crate::can::frame::ClassicFrame; | 47 | pub use crate::can::frame::Frame; |
| 48 | use crate::pac::can::vals::Lec; | ||
| 45 | 49 | ||
| 46 | use crate::can::bx::filter::MasterFilters; | 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 | } | ||
| 47 | 74 | ||
| 48 | /// A bxCAN peripheral instance. | 75 | /// A bxCAN peripheral instance. |
| 49 | /// | 76 | /// |
| @@ -233,230 +260,37 @@ impl PartialOrd for IdReg { | |||
| 233 | } | 260 | } |
| 234 | } | 261 | } |
| 235 | 262 | ||
| 236 | /// Configuration proxy returned by [`Can::modify_config`]. | 263 | pub(crate) struct Registers { |
| 237 | #[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"] | 264 | pub canregs: crate::pac::can::Can, |
| 238 | pub struct CanConfig<'a, I: Instance> { | ||
| 239 | can: &'a mut Can<I>, | ||
| 240 | } | 265 | } |
| 241 | 266 | ||
| 242 | impl<I: Instance> CanConfig<'_, I> { | 267 | impl Registers { |
| 243 | /// Configures the bit timings. | 268 | fn enter_init_mode(&mut self) { |
| 244 | /// | 269 | self.canregs.mcr().modify(|reg| { |
| 245 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | 270 | reg.set_sleep(false); |
| 246 | /// parameters as follows: | 271 | reg.set_inrq(true); |
| 247 | /// | ||
| 248 | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). | ||
| 249 | /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). | ||
| 250 | /// - *Sample Point*: Should normally be left at the default value of 87.5%. | ||
| 251 | /// - *SJW*: Should normally be left at the default value of 1. | ||
| 252 | /// | ||
| 253 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | ||
| 254 | /// parameter to this method. | ||
| 255 | pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { | ||
| 256 | self.can.set_bit_timing(bt); | ||
| 257 | self | ||
| 258 | } | ||
| 259 | |||
| 260 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 261 | /// signals together. | ||
| 262 | pub fn set_loopback(self, enabled: bool) -> Self { | ||
| 263 | self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); | ||
| 264 | self | ||
| 265 | } | ||
| 266 | |||
| 267 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 268 | pub fn set_silent(self, enabled: bool) -> Self { | ||
| 269 | let mode = match enabled { | ||
| 270 | false => stm32_metapac::can::vals::Silm::NORMAL, | ||
| 271 | true => stm32_metapac::can::vals::Silm::SILENT, | ||
| 272 | }; | ||
| 273 | self.can.canregs.btr().modify(|reg| reg.set_silm(mode)); | ||
| 274 | self | ||
| 275 | } | ||
| 276 | |||
| 277 | /// Enables or disables automatic retransmission of messages. | ||
| 278 | /// | ||
| 279 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 280 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 281 | /// | ||
| 282 | /// Automatic retransmission is enabled by default. | ||
| 283 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { | ||
| 284 | self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled)); | ||
| 285 | self | ||
| 286 | } | ||
| 287 | |||
| 288 | /// Leaves initialization mode and enables the peripheral. | ||
| 289 | /// | ||
| 290 | /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected | ||
| 291 | /// on the bus. | ||
| 292 | /// | ||
| 293 | /// If you want to finish configuration without enabling the peripheral, you can call | ||
| 294 | /// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead. | ||
| 295 | pub fn enable(mut self) { | ||
| 296 | self.leave_init_mode(); | ||
| 297 | |||
| 298 | match nb::block!(self.can.enable_non_blocking()) { | ||
| 299 | Ok(()) => {} | ||
| 300 | Err(void) => match void {}, | ||
| 301 | } | ||
| 302 | |||
| 303 | // Don't run the destructor. | ||
| 304 | mem::forget(self); | ||
| 305 | } | ||
| 306 | |||
| 307 | /// Leaves initialization mode, but keeps the peripheral in sleep mode. | ||
| 308 | /// | ||
| 309 | /// Before the [`Can`] instance can be used, you have to enable it by calling | ||
| 310 | /// [`Can::enable_non_blocking`]. | ||
| 311 | pub fn leave_disabled(mut self) { | ||
| 312 | self.leave_init_mode(); | ||
| 313 | } | ||
| 314 | |||
| 315 | /// Leaves initialization mode, enters sleep mode. | ||
| 316 | fn leave_init_mode(&mut self) { | ||
| 317 | self.can.canregs.mcr().modify(|reg| { | ||
| 318 | reg.set_sleep(true); | ||
| 319 | reg.set_inrq(false); | ||
| 320 | }); | 272 | }); |
| 321 | loop { | 273 | loop { |
| 322 | let msr = self.can.canregs.msr().read(); | 274 | let msr = self.canregs.msr().read(); |
| 323 | if msr.slak() && !msr.inak() { | 275 | if !msr.slak() && msr.inak() { |
| 324 | break; | 276 | break; |
| 325 | } | 277 | } |
| 326 | } | 278 | } |
| 327 | } | 279 | } |
| 328 | } | ||
| 329 | |||
| 330 | impl<I: Instance> Drop for CanConfig<'_, I> { | ||
| 331 | #[inline] | ||
| 332 | fn drop(&mut self) { | ||
| 333 | self.leave_init_mode(); | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | /// Builder returned by [`Can::builder`]. | ||
| 338 | #[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"] | ||
| 339 | pub struct CanBuilder<I: Instance> { | ||
| 340 | can: Can<I>, | ||
| 341 | } | ||
| 342 | |||
| 343 | impl<I: Instance> CanBuilder<I> { | ||
| 344 | /// Configures the bit timings. | ||
| 345 | /// | ||
| 346 | /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter | ||
| 347 | /// parameters as follows: | ||
| 348 | /// | ||
| 349 | /// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed). | ||
| 350 | /// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1). | ||
| 351 | /// - *Sample Point*: Should normally be left at the default value of 87.5%. | ||
| 352 | /// - *SJW*: Should normally be left at the default value of 1. | ||
| 353 | /// | ||
| 354 | /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` | ||
| 355 | /// parameter to this method. | ||
| 356 | pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self { | ||
| 357 | self.can.set_bit_timing(bt); | ||
| 358 | self | ||
| 359 | } | ||
| 360 | /// Enables or disables loopback mode: Internally connects the TX and RX | ||
| 361 | /// signals together. | ||
| 362 | pub fn set_loopback(self, enabled: bool) -> Self { | ||
| 363 | self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled)); | ||
| 364 | self | ||
| 365 | } | ||
| 366 | |||
| 367 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. | ||
| 368 | pub fn set_silent(self, enabled: bool) -> Self { | ||
| 369 | let mode = match enabled { | ||
| 370 | false => stm32_metapac::can::vals::Silm::NORMAL, | ||
| 371 | true => stm32_metapac::can::vals::Silm::SILENT, | ||
| 372 | }; | ||
| 373 | self.can.canregs.btr().modify(|reg| reg.set_silm(mode)); | ||
| 374 | self | ||
| 375 | } | ||
| 376 | |||
| 377 | /// Enables or disables automatic retransmission of messages. | ||
| 378 | /// | ||
| 379 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame | ||
| 380 | /// until it can be sent. Otherwise, it will try only once to send each frame. | ||
| 381 | /// | ||
| 382 | /// Automatic retransmission is enabled by default. | ||
| 383 | pub fn set_automatic_retransmit(self, enabled: bool) -> Self { | ||
| 384 | self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled)); | ||
| 385 | self | ||
| 386 | } | ||
| 387 | |||
| 388 | /// Leaves initialization mode and enables the peripheral. | ||
| 389 | /// | ||
| 390 | /// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected | ||
| 391 | /// on the bus. | ||
| 392 | /// | ||
| 393 | /// If you want to finish configuration without enabling the peripheral, you can call | ||
| 394 | /// [`CanBuilder::leave_disabled`] instead. | ||
| 395 | pub fn enable(mut self) -> Can<I> { | ||
| 396 | self.leave_init_mode(); | ||
| 397 | |||
| 398 | match nb::block!(self.can.enable_non_blocking()) { | ||
| 399 | Ok(()) => self.can, | ||
| 400 | Err(void) => match void {}, | ||
| 401 | } | ||
| 402 | } | ||
| 403 | 280 | ||
| 404 | /// Returns the [`Can`] interface without enabling it. | 281 | // Leaves initialization mode, enters sleep mode. |
| 405 | /// | ||
| 406 | /// This leaves initialization mode, but keeps the peripheral in sleep mode instead of enabling | ||
| 407 | /// it. | ||
| 408 | /// | ||
| 409 | /// Before the [`Can`] instance can be used, you have to enable it by calling | ||
| 410 | /// [`Can::enable_non_blocking`]. | ||
| 411 | pub fn leave_disabled(mut self) -> Can<I> { | ||
| 412 | self.leave_init_mode(); | ||
| 413 | self.can | ||
| 414 | } | ||
| 415 | |||
| 416 | /// Leaves initialization mode, enters sleep mode. | ||
| 417 | fn leave_init_mode(&mut self) { | 282 | fn leave_init_mode(&mut self) { |
| 418 | self.can.canregs.mcr().modify(|reg| { | 283 | self.canregs.mcr().modify(|reg| { |
| 419 | reg.set_sleep(true); | 284 | reg.set_sleep(true); |
| 420 | reg.set_inrq(false); | 285 | reg.set_inrq(false); |
| 421 | }); | 286 | }); |
| 422 | loop { | 287 | loop { |
| 423 | let msr = self.can.canregs.msr().read(); | 288 | let msr = self.canregs.msr().read(); |
| 424 | if msr.slak() && !msr.inak() { | 289 | if msr.slak() && !msr.inak() { |
| 425 | break; | 290 | break; |
| 426 | } | 291 | } |
| 427 | } | 292 | } |
| 428 | } | 293 | } |
| 429 | } | ||
| 430 | |||
| 431 | /// Interface to a bxCAN peripheral. | ||
| 432 | pub struct Can<I: Instance> { | ||
| 433 | instance: I, | ||
| 434 | canregs: crate::pac::can::Can, | ||
| 435 | } | ||
| 436 | |||
| 437 | impl<I> Can<I> | ||
| 438 | where | ||
| 439 | I: Instance, | ||
| 440 | { | ||
| 441 | /// Creates a [`CanBuilder`] for constructing a CAN interface. | ||
| 442 | pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder<I> { | ||
| 443 | let can_builder = CanBuilder { | ||
| 444 | can: Can { instance, canregs }, | ||
| 445 | }; | ||
| 446 | |||
| 447 | canregs.mcr().modify(|reg| { | ||
| 448 | reg.set_sleep(false); | ||
| 449 | reg.set_inrq(true); | ||
| 450 | }); | ||
| 451 | loop { | ||
| 452 | let msr = canregs.msr().read(); | ||
| 453 | if !msr.slak() && msr.inak() { | ||
| 454 | break; | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | can_builder | ||
| 459 | } | ||
| 460 | 294 | ||
| 461 | fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { | 295 | fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { |
| 462 | let prescaler = u16::from(bt.prescaler) & 0x1FF; | 296 | let prescaler = u16::from(bt.prescaler) & 0x1FF; |
| @@ -471,38 +305,29 @@ where | |||
| 471 | }); | 305 | }); |
| 472 | } | 306 | } |
| 473 | 307 | ||
| 474 | /// Returns a reference to the peripheral instance. | 308 | /// Enables or disables silent mode: Disconnects the TX signal from the pin. |
| 475 | /// | 309 | pub fn set_silent(&self, enabled: bool) { |
| 476 | /// This allows accessing HAL-specific data stored in the instance type. | 310 | let mode = match enabled { |
| 477 | pub fn instance(&mut self) -> &mut I { | 311 | false => stm32_metapac::can::vals::Silm::NORMAL, |
| 478 | &mut self.instance | 312 | true => stm32_metapac::can::vals::Silm::SILENT, |
| 313 | }; | ||
| 314 | self.canregs.btr().modify(|reg| reg.set_silm(mode)); | ||
| 479 | } | 315 | } |
| 480 | 316 | ||
| 481 | /// Disables the CAN interface and returns back the raw peripheral it was created from. | 317 | /// Enables or disables automatic retransmission of messages. |
| 482 | /// | 318 | /// |
| 483 | /// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to | 319 | /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame |
| 484 | /// enter sleep mode. | 320 | /// until it can be sent. Otherwise, it will try only once to send each frame. |
| 485 | pub fn free(self) -> I { | ||
| 486 | self.canregs.mcr().write(|reg| reg.set_reset(true)); | ||
| 487 | self.instance | ||
| 488 | } | ||
| 489 | |||
| 490 | /// Configure bit timings and silent/loop-back mode. | ||
| 491 | /// | 321 | /// |
| 492 | /// Calling this method will enter initialization mode. | 322 | /// Automatic retransmission is enabled by default. |
| 493 | pub fn modify_config(&mut self) -> CanConfig<'_, I> { | 323 | pub fn set_automatic_retransmit(&self, enabled: bool) { |
| 494 | self.canregs.mcr().modify(|reg| { | 324 | self.canregs.mcr().modify(|reg| reg.set_nart(enabled)); |
| 495 | reg.set_sleep(false); | 325 | } |
| 496 | reg.set_inrq(true); | ||
| 497 | }); | ||
| 498 | loop { | ||
| 499 | let msr = self.canregs.msr().read(); | ||
| 500 | if !msr.slak() && msr.inak() { | ||
| 501 | break; | ||
| 502 | } | ||
| 503 | } | ||
| 504 | 326 | ||
| 505 | CanConfig { can: self } | 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)); | ||
| 506 | } | 331 | } |
| 507 | 332 | ||
| 508 | /// Configures the automatic wake-up feature. | 333 | /// Configures the automatic wake-up feature. |
| @@ -512,6 +337,7 @@ where | |||
| 512 | /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and | 337 | /// When turned on, an incoming frame will cause the peripheral to wake up from sleep and |
| 513 | /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming | 338 | /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming |
| 514 | /// frame. | 339 | /// frame. |
| 340 | #[allow(dead_code)] | ||
| 515 | pub fn set_automatic_wakeup(&mut self, enabled: bool) { | 341 | pub fn set_automatic_wakeup(&mut self, enabled: bool) { |
| 516 | self.canregs.mcr().modify(|reg| reg.set_awum(enabled)); | 342 | self.canregs.mcr().modify(|reg| reg.set_awum(enabled)); |
| 517 | } | 343 | } |
| @@ -540,6 +366,7 @@ where | |||
| 540 | /// Puts the peripheral in a sleep mode to save power. | 366 | /// Puts the peripheral in a sleep mode to save power. |
| 541 | /// | 367 | /// |
| 542 | /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. | 368 | /// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled. |
| 369 | #[allow(dead_code)] | ||
| 543 | pub fn sleep(&mut self) { | 370 | pub fn sleep(&mut self) { |
| 544 | self.canregs.mcr().modify(|reg| { | 371 | self.canregs.mcr().modify(|reg| { |
| 545 | reg.set_sleep(true); | 372 | reg.set_sleep(true); |
| @@ -553,10 +380,19 @@ where | |||
| 553 | } | 380 | } |
| 554 | } | 381 | } |
| 555 | 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 | |||
| 556 | /// Wakes up from sleep mode. | 391 | /// Wakes up from sleep mode. |
| 557 | /// | 392 | /// |
| 558 | /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN | 393 | /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN |
| 559 | /// frame will cause that interrupt. | 394 | /// frame will cause that interrupt. |
| 395 | #[allow(dead_code)] | ||
| 560 | pub fn wakeup(&mut self) { | 396 | pub fn wakeup(&mut self) { |
| 561 | self.canregs.mcr().modify(|reg| { | 397 | self.canregs.mcr().modify(|reg| { |
| 562 | reg.set_sleep(false); | 398 | reg.set_sleep(false); |
| @@ -570,113 +406,18 @@ where | |||
| 570 | } | 406 | } |
| 571 | } | 407 | } |
| 572 | 408 | ||
| 573 | /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. | 409 | pub fn curr_error(&self) -> Option<BusError> { |
| 574 | /// | 410 | let err = { self.canregs.esr().read() }; |
| 575 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). | 411 | if err.boff() { |
| 576 | /// Transmit order is preserved for frames with identical priority. | 412 | return Some(BusError::BusOff); |
| 577 | /// | 413 | } else if err.epvf() { |
| 578 | /// If all transmit mailboxes are full, and `frame` has a higher priority than the | 414 | return Some(BusError::BusPassive); |
| 579 | /// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is | 415 | } else if err.ewgf() { |
| 580 | /// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as | 416 | return Some(BusError::BusWarning); |
| 581 | /// [`TransmitStatus::dequeued_frame`]. | 417 | } else if let Some(err) = err.lec().into_bus_err() { |
| 582 | pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { | 418 | return Some(err); |
| 583 | // Safety: We have a `&mut self` and have unique access to the peripheral. | ||
| 584 | unsafe { Tx::<I>::conjure(self.canregs).transmit(frame) } | ||
| 585 | } | ||
| 586 | |||
| 587 | /// Returns `true` if no frame is pending for transmission. | ||
| 588 | pub fn is_transmitter_idle(&self) -> bool { | ||
| 589 | // Safety: Read-only operation. | ||
| 590 | unsafe { Tx::<I>::conjure(self.canregs).is_idle() } | ||
| 591 | } | ||
| 592 | |||
| 593 | /// Attempts to abort the sending of a frame that is pending in a mailbox. | ||
| 594 | /// | ||
| 595 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be | ||
| 596 | /// aborted, this function has no effect and returns `false`. | ||
| 597 | /// | ||
| 598 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function | ||
| 599 | /// returns `true`. | ||
| 600 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | ||
| 601 | // Safety: We have a `&mut self` and have unique access to the peripheral. | ||
| 602 | unsafe { Tx::<I>::conjure(self.canregs).abort(mailbox) } | ||
| 603 | } | ||
| 604 | |||
| 605 | /// Returns a received frame if available. | ||
| 606 | /// | ||
| 607 | /// This will first check FIFO 0 for a message or error. If none are available, FIFO 1 is | ||
| 608 | /// checked. | ||
| 609 | /// | ||
| 610 | /// Returns `Err` when a frame was lost due to buffer overrun. | ||
| 611 | pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> { | ||
| 612 | // Safety: We have a `&mut self` and have unique access to the peripheral. | ||
| 613 | let mut rx0 = unsafe { Rx0::<I>::conjure(self.canregs) }; | ||
| 614 | let mut rx1 = unsafe { Rx1::<I>::conjure(self.canregs) }; | ||
| 615 | |||
| 616 | match rx0.receive() { | ||
| 617 | Err(nb::Error::WouldBlock) => rx1.receive(), | ||
| 618 | result => result, | ||
| 619 | } | ||
| 620 | } | ||
| 621 | |||
| 622 | /// Returns a reference to the RX FIFO 0. | ||
| 623 | pub fn rx0(&mut self) -> Rx0<I> { | ||
| 624 | // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. | ||
| 625 | unsafe { Rx0::conjure(self.canregs) } | ||
| 626 | } | ||
| 627 | |||
| 628 | /// Returns a reference to the RX FIFO 1. | ||
| 629 | pub fn rx1(&mut self) -> Rx1<I> { | ||
| 630 | // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. | ||
| 631 | unsafe { Rx1::conjure(self.canregs) } | ||
| 632 | } | ||
| 633 | |||
| 634 | pub(crate) fn split_by_ref(&mut self) -> (Tx<I>, Rx0<I>, Rx1<I>) { | ||
| 635 | // Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime. | ||
| 636 | let tx = unsafe { Tx::conjure(self.canregs) }; | ||
| 637 | let rx0 = unsafe { Rx0::conjure(self.canregs) }; | ||
| 638 | let rx1 = unsafe { Rx1::conjure(self.canregs) }; | ||
| 639 | (tx, rx0, rx1) | ||
| 640 | } | ||
| 641 | |||
| 642 | /// Consumes this `Can` instance and splits it into transmitting and receiving halves. | ||
| 643 | pub fn split(self) -> (Tx<I>, Rx0<I>, Rx1<I>) { | ||
| 644 | // Safety: `Self` is not `Copy` and is destroyed by moving it into this method. | ||
| 645 | unsafe { | ||
| 646 | ( | ||
| 647 | Tx::conjure(self.canregs), | ||
| 648 | Rx0::conjure(self.canregs), | ||
| 649 | Rx1::conjure(self.canregs), | ||
| 650 | ) | ||
| 651 | } | ||
| 652 | } | ||
| 653 | } | ||
| 654 | |||
| 655 | impl<I: FilterOwner> Can<I> { | ||
| 656 | /// Accesses the filter banks owned by this CAN peripheral. | ||
| 657 | /// | ||
| 658 | /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master | ||
| 659 | /// peripheral instead. | ||
| 660 | pub fn modify_filters(&mut self) -> MasterFilters<'_, I> { | ||
| 661 | unsafe { MasterFilters::new(self.canregs) } | ||
| 662 | } | ||
| 663 | } | ||
| 664 | |||
| 665 | /// Interface to the CAN transmitter part. | ||
| 666 | pub struct Tx<I> { | ||
| 667 | _can: PhantomData<I>, | ||
| 668 | canregs: crate::pac::can::Can, | ||
| 669 | } | ||
| 670 | |||
| 671 | impl<I> Tx<I> | ||
| 672 | where | ||
| 673 | I: Instance, | ||
| 674 | { | ||
| 675 | unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { | ||
| 676 | Self { | ||
| 677 | _can: PhantomData, | ||
| 678 | canregs, | ||
| 679 | } | 419 | } |
| 420 | None | ||
| 680 | } | 421 | } |
| 681 | 422 | ||
| 682 | /// Puts a CAN frame in a transmit mailbox for transmission on the bus. | 423 | /// Puts a CAN frame in a transmit mailbox for transmission on the bus. |
| @@ -842,89 +583,387 @@ where | |||
| 842 | reg.set_rqcp(2, true); | 583 | reg.set_rqcp(2, true); |
| 843 | }); | 584 | }); |
| 844 | } | 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 | } | ||
| 845 | } | 643 | } |
| 846 | 644 | ||
| 847 | /// Interface to receiver FIFO 0. | 645 | /// Configuration proxy returned by [`Can::modify_config`]. |
| 848 | pub struct Rx0<I> { | 646 | #[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"] |
| 849 | _can: PhantomData<I>, | 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, | ||
| 850 | canregs: crate::pac::can::Can, | 812 | canregs: crate::pac::can::Can, |
| 813 | pub(crate) registers: Registers, | ||
| 851 | } | 814 | } |
| 852 | 815 | ||
| 853 | impl<I> Rx0<I> | 816 | impl<I> Can<I> |
| 854 | where | 817 | where |
| 855 | I: Instance, | 818 | I: Instance, |
| 856 | { | 819 | { |
| 857 | unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { | 820 | /// Creates a [`CanBuilder`] for constructing a CAN interface. |
| 858 | Self { | 821 | pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder<I> { |
| 859 | _can: PhantomData, | 822 | let mut can_builder = CanBuilder { |
| 860 | canregs, | 823 | can: Can { |
| 861 | } | 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) } | ||
| 862 | } | 865 | } |
| 863 | 866 | ||
| 864 | /// Returns a received frame if available. | 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. | ||
| 865 | /// | 874 | /// |
| 866 | /// Returns `Err` when a frame was lost due to buffer overrun. | 875 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be |
| 867 | pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> { | 876 | /// aborted, this function has no effect and returns `false`. |
| 868 | receive_fifo(self.canregs, 0) | 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) } | ||
| 869 | } | 900 | } |
| 870 | } | 901 | } |
| 871 | 902 | ||
| 872 | /// Interface to receiver FIFO 1. | 903 | /// Marker for Tx half |
| 873 | pub struct Rx1<I> { | 904 | pub struct Tx<I> { |
| 874 | _can: PhantomData<I>, | 905 | _can: PhantomData<I>, |
| 875 | canregs: crate::pac::can::Can, | 906 | pub(crate) registers: Registers, |
| 876 | } | 907 | } |
| 877 | 908 | ||
| 878 | impl<I> Rx1<I> | 909 | impl<I> Tx<I> |
| 879 | where | 910 | where |
| 880 | I: Instance, | 911 | I: Instance, |
| 881 | { | 912 | { |
| 882 | unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { | 913 | unsafe fn conjure(canregs: crate::pac::can::Can) -> Self { |
| 883 | Self { | 914 | Self { |
| 884 | _can: PhantomData, | 915 | _can: PhantomData, |
| 885 | canregs, | 916 | registers: Registers { canregs }, //canregs, |
| 886 | } | 917 | } |
| 887 | } | 918 | } |
| 888 | 919 | ||
| 889 | /// Returns a received frame if available. | 920 | /// Puts a CAN frame in a transmit mailbox for transmission on the bus. |
| 890 | /// | 921 | /// |
| 891 | /// Returns `Err` when a frame was lost due to buffer overrun. | 922 | /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). |
| 892 | pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> { | 923 | /// Transmit order is preserved for frames with identical priority. |
| 893 | receive_fifo(self.canregs, 1) | 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) | ||
| 894 | } | 931 | } |
| 895 | } | ||
| 896 | 932 | ||
| 897 | fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result<Frame, OverrunError> { | 933 | /// Attempts to abort the sending of a frame that is pending in a mailbox. |
| 898 | assert!(fifo_nr < 2); | 934 | /// |
| 899 | let rfr = canregs.rfr(fifo_nr); | 935 | /// If there is no frame in the provided mailbox, or its transmission succeeds before it can be |
| 900 | let rx = canregs.rx(fifo_nr); | 936 | /// aborted, this function has no effect and returns `false`. |
| 901 | 937 | /// | |
| 902 | //let rfr = &can.rfr[fifo_nr]; | 938 | /// If there is a frame in the provided mailbox, and it is canceled successfully, this function |
| 903 | //let rx = &can.rx[fifo_nr]; | 939 | /// returns `true`. |
| 904 | 940 | pub fn abort(&mut self, mailbox: Mailbox) -> bool { | |
| 905 | // Check if a frame is available in the mailbox. | 941 | self.registers.abort(mailbox) |
| 906 | let rfr_read = rfr.read(); | ||
| 907 | if rfr_read.fmp() == 0 { | ||
| 908 | return Err(nb::Error::WouldBlock); | ||
| 909 | } | 942 | } |
| 910 | 943 | ||
| 911 | // Check for RX FIFO overrun. | 944 | /// Returns `true` if no frame is pending for transmission. |
| 912 | if rfr_read.fovr() { | 945 | pub fn is_idle(&self) -> bool { |
| 913 | rfr.write(|w| w.set_fovr(true)); | 946 | self.registers.is_idle() |
| 914 | return Err(nb::Error::Other(OverrunError { _priv: () })); | ||
| 915 | } | 947 | } |
| 916 | 948 | ||
| 917 | // Read the frame. | 949 | /// Clears the request complete flag for all mailboxes. |
| 918 | let id = IdReg(rx.rir().read().0); | 950 | pub fn clear_interrupt_flags(&mut self) { |
| 919 | let mut data = [0xff; 8]; | 951 | self.registers.clear_interrupt_flags() |
| 920 | data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes()); | 952 | } |
| 921 | data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes()); | 953 | } |
| 922 | let len = rx.rdtr().read().dlc(); | ||
| 923 | 954 | ||
| 924 | // Release the mailbox. | 955 | /// Marker for Rx half |
| 925 | rfr.write(|w| w.set_rfom(true)); | 956 | pub struct Rx<I> { |
| 957 | _can: PhantomData<I>, | ||
| 958 | } | ||
| 926 | 959 | ||
| 927 | Ok(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap()) | 960 | impl<I> Rx<I> |
| 961 | where | ||
| 962 | I: Instance, | ||
| 963 | { | ||
| 964 | unsafe fn conjure() -> Self { | ||
| 965 | Self { _can: PhantomData } | ||
| 966 | } | ||
| 928 | } | 967 | } |
| 929 | 968 | ||
| 930 | /// Identifies one of the two receive FIFOs. | 969 | /// Identifies one of the two receive FIFOs. |
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 017c5110d..fd6a79092 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -10,31 +10,19 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | |||
| 10 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 10 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 11 | use embassy_sync::channel::Channel; | 11 | use embassy_sync::channel::Channel; |
| 12 | use embassy_sync::waitqueue::AtomicWaker; | 12 | use embassy_sync::waitqueue::AtomicWaker; |
| 13 | use futures::FutureExt; | ||
| 14 | 13 | ||
| 15 | use crate::gpio::AFType; | 14 | use crate::gpio::AFType; |
| 16 | use crate::interrupt::typelevel::Interrupt; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 17 | use crate::pac::can::vals::{Ide, Lec}; | ||
| 18 | use crate::rcc::RccPeripheral; | 16 | use crate::rcc::RccPeripheral; |
| 19 | use crate::{interrupt, peripherals, Peripheral}; | 17 | use crate::{interrupt, peripherals, Peripheral}; |
| 20 | 18 | ||
| 21 | pub mod enums; | 19 | pub mod enums; |
| 22 | use enums::*; | ||
| 23 | pub mod frame; | 20 | pub mod frame; |
| 24 | pub mod util; | 21 | pub mod util; |
| 22 | pub use frame::Envelope; | ||
| 25 | 23 | ||
| 26 | /// Contains CAN frame and additional metadata. | 24 | mod common; |
| 27 | /// | 25 | pub use self::common::{BufferedCanReceiver, BufferedCanSender}; |
| 28 | /// Timestamp is available if `time` feature is enabled. | ||
| 29 | #[derive(Debug, Clone)] | ||
| 30 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 31 | pub struct Envelope { | ||
| 32 | /// Reception time. | ||
| 33 | #[cfg(feature = "time")] | ||
| 34 | pub ts: embassy_time::Instant, | ||
| 35 | /// The actual CAN frame. | ||
| 36 | pub frame: Frame, | ||
| 37 | } | ||
| 38 | 26 | ||
| 39 | /// Interrupt handler. | 27 | /// Interrupt handler. |
| 40 | pub struct TxInterruptHandler<T: Instance> { | 28 | pub struct TxInterruptHandler<T: Instance> { |
| @@ -48,8 +36,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptH | |||
| 48 | v.set_rqcp(1, true); | 36 | v.set_rqcp(1, true); |
| 49 | v.set_rqcp(2, true); | 37 | v.set_rqcp(2, true); |
| 50 | }); | 38 | }); |
| 51 | 39 | T::state().tx_mode.on_interrupt::<T>(); | |
| 52 | T::state().tx_waker.wake(); | ||
| 53 | } | 40 | } |
| 54 | } | 41 | } |
| 55 | 42 | ||
| @@ -60,8 +47,7 @@ pub struct Rx0InterruptHandler<T: Instance> { | |||
| 60 | 47 | ||
| 61 | impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { | 48 | impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> { |
| 62 | unsafe fn on_interrupt() { | 49 | unsafe fn on_interrupt() { |
| 63 | // info!("rx0 irq"); | 50 | T::state().rx_mode.on_interrupt::<T>(RxFifo::Fifo0); |
| 64 | Can::<T>::receive_fifo(RxFifo::Fifo0); | ||
| 65 | } | 51 | } |
| 66 | } | 52 | } |
| 67 | 53 | ||
| @@ -72,8 +58,7 @@ pub struct Rx1InterruptHandler<T: Instance> { | |||
| 72 | 58 | ||
| 73 | impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { | 59 | impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> { |
| 74 | unsafe fn on_interrupt() { | 60 | unsafe fn on_interrupt() { |
| 75 | // info!("rx1 irq"); | 61 | T::state().rx_mode.on_interrupt::<T>(RxFifo::Fifo1); |
| 76 | Can::<T>::receive_fifo(RxFifo::Fifo1); | ||
| 77 | } | 62 | } |
| 78 | } | 63 | } |
| 79 | 64 | ||
| @@ -100,16 +85,6 @@ pub struct Can<'d, T: Instance> { | |||
| 100 | can: crate::can::bx::Can<BxcanInstance<'d, T>>, | 85 | can: crate::can::bx::Can<BxcanInstance<'d, T>>, |
| 101 | } | 86 | } |
| 102 | 87 | ||
| 103 | /// Error returned by `try_read` | ||
| 104 | #[derive(Debug)] | ||
| 105 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 106 | pub enum TryReadError { | ||
| 107 | /// Bus error | ||
| 108 | BusError(BusError), | ||
| 109 | /// Receive buffer is empty | ||
| 110 | Empty, | ||
| 111 | } | ||
| 112 | |||
| 113 | /// Error returned by `try_write` | 88 | /// Error returned by `try_write` |
| 114 | #[derive(Debug)] | 89 | #[derive(Debug)] |
| 115 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 90 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| @@ -185,7 +160,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 185 | /// This will wait for 11 consecutive recessive bits (bus idle state). | 160 | /// This will wait for 11 consecutive recessive bits (bus idle state). |
| 186 | /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. | 161 | /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. |
| 187 | pub async fn enable(&mut self) { | 162 | pub async fn enable(&mut self) { |
| 188 | while self.enable_non_blocking().is_err() { | 163 | while self.registers.enable_non_blocking().is_err() { |
| 189 | // SCE interrupt is only generated for entering sleep mode, but not leaving. | 164 | // SCE interrupt is only generated for entering sleep mode, but not leaving. |
| 190 | // Yield to allow other tasks to execute while can bus is initializing. | 165 | // Yield to allow other tasks to execute while can bus is initializing. |
| 191 | embassy_futures::yield_now().await; | 166 | embassy_futures::yield_now().await; |
| @@ -227,77 +202,40 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 227 | /// | 202 | /// |
| 228 | /// Returns a tuple of the time the message was received and the message frame | 203 | /// Returns a tuple of the time the message was received and the message frame |
| 229 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | 204 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 230 | self.split().1.read().await | 205 | T::state().rx_mode.read::<T>().await |
| 231 | } | 206 | } |
| 232 | 207 | ||
| 233 | /// Attempts to read a CAN frame without blocking. | 208 | /// Attempts to read a CAN frame without blocking. |
| 234 | /// | 209 | /// |
| 235 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | 210 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. |
| 236 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | 211 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { |
| 237 | self.split().1.try_read() | 212 | T::state().rx_mode.try_read::<T>() |
| 238 | } | 213 | } |
| 239 | 214 | ||
| 240 | /// Waits while receive queue is empty. | 215 | /// Waits while receive queue is empty. |
| 241 | pub async fn wait_not_empty(&mut self) { | 216 | pub async fn wait_not_empty(&mut self) { |
| 242 | self.split().1.wait_not_empty().await | 217 | T::state().rx_mode.wait_not_empty::<T>().await |
| 243 | } | ||
| 244 | |||
| 245 | unsafe fn receive_fifo(fifo: RxFifo) { | ||
| 246 | // Generate timestamp as early as possible | ||
| 247 | #[cfg(feature = "time")] | ||
| 248 | let ts = embassy_time::Instant::now(); | ||
| 249 | |||
| 250 | let state = T::state(); | ||
| 251 | let regs = T::regs(); | ||
| 252 | let fifo_idx = match fifo { | ||
| 253 | RxFifo::Fifo0 => 0usize, | ||
| 254 | RxFifo::Fifo1 => 1usize, | ||
| 255 | }; | ||
| 256 | let rfr = regs.rfr(fifo_idx); | ||
| 257 | let fifo = regs.rx(fifo_idx); | ||
| 258 | |||
| 259 | loop { | ||
| 260 | // If there are no pending messages, there is nothing to do | ||
| 261 | if rfr.read().fmp() == 0 { | ||
| 262 | return; | ||
| 263 | } | ||
| 264 | |||
| 265 | let rir = fifo.rir().read(); | ||
| 266 | let id: embedded_can::Id = if rir.ide() == Ide::STANDARD { | ||
| 267 | embedded_can::StandardId::new(rir.stid()).unwrap().into() | ||
| 268 | } else { | ||
| 269 | let stid = (rir.stid() & 0x7FF) as u32; | ||
| 270 | let exid = rir.exid() & 0x3FFFF; | ||
| 271 | let id = (stid << 18) | (exid); | ||
| 272 | embedded_can::ExtendedId::new(id).unwrap().into() | ||
| 273 | }; | ||
| 274 | let data_len = fifo.rdtr().read().dlc(); | ||
| 275 | let mut data: [u8; 8] = [0; 8]; | ||
| 276 | data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); | ||
| 277 | data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); | ||
| 278 | |||
| 279 | let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap(); | ||
| 280 | let envelope = Envelope { | ||
| 281 | #[cfg(feature = "time")] | ||
| 282 | ts, | ||
| 283 | frame, | ||
| 284 | }; | ||
| 285 | |||
| 286 | rfr.modify(|v| v.set_rfom(true)); | ||
| 287 | |||
| 288 | /* | ||
| 289 | NOTE: consensus was reached that if rx_queue is full, packets should be dropped | ||
| 290 | */ | ||
| 291 | let _ = state.rx_queue.try_send(envelope); | ||
| 292 | } | ||
| 293 | } | 218 | } |
| 294 | 219 | ||
| 295 | /// Split the CAN driver into transmit and receive halves. | 220 | /// Split the CAN driver into transmit and receive halves. |
| 296 | /// | 221 | /// |
| 297 | /// Useful for doing separate transmit/receive tasks. | 222 | /// Useful for doing separate transmit/receive tasks. |
| 298 | pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { | 223 | pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { |
| 299 | let (tx, rx0, rx1) = self.can.split_by_ref(); | 224 | let (tx, rx) = self.can.split_by_ref(); |
| 300 | (CanTx { tx }, CanRx { rx0, rx1 }) | 225 | (CanTx { tx }, CanRx { rx }) |
| 226 | } | ||
| 227 | |||
| 228 | /// Return a buffered instance of driver. User must supply Buffers | ||
| 229 | pub fn buffered<'c, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>( | ||
| 230 | &'c mut self, | ||
| 231 | txb: &'static mut TxBuf<TX_BUF_SIZE>, | ||
| 232 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, | ||
| 233 | ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { | ||
| 234 | let (tx, rx) = self.split(); | ||
| 235 | BufferedCan { | ||
| 236 | tx: tx.buffered(txb), | ||
| 237 | rx: rx.buffered(rxb), | ||
| 238 | } | ||
| 301 | } | 239 | } |
| 302 | } | 240 | } |
| 303 | 241 | ||
| @@ -308,6 +246,46 @@ impl<'d, T: Instance> AsMut<crate::can::bx::Can<BxcanInstance<'d, T>>> for Can<' | |||
| 308 | } | 246 | } |
| 309 | } | 247 | } |
| 310 | 248 | ||
| 249 | /// Buffered CAN driver. | ||
| 250 | pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | ||
| 251 | tx: BufferedCanTx<'d, T, TX_BUF_SIZE>, | ||
| 252 | rx: BufferedCanRx<'d, T, RX_BUF_SIZE>, | ||
| 253 | } | ||
| 254 | |||
| 255 | impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { | ||
| 256 | /// Async write frame to TX buffer. | ||
| 257 | pub async fn write(&mut self, frame: &Frame) { | ||
| 258 | self.tx.write(frame).await | ||
| 259 | } | ||
| 260 | |||
| 261 | /// Returns a sender that can be used for sending CAN frames. | ||
| 262 | pub fn writer(&self) -> BufferedCanSender { | ||
| 263 | self.tx.writer() | ||
| 264 | } | ||
| 265 | |||
| 266 | /// Async read frame from RX buffer. | ||
| 267 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | ||
| 268 | self.rx.read().await | ||
| 269 | } | ||
| 270 | |||
| 271 | /// Attempts to read a CAN frame without blocking. | ||
| 272 | /// | ||
| 273 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 274 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | ||
| 275 | self.rx.try_read() | ||
| 276 | } | ||
| 277 | |||
| 278 | /// Waits while receive queue is empty. | ||
| 279 | pub async fn wait_not_empty(&mut self) { | ||
| 280 | self.rx.wait_not_empty().await | ||
| 281 | } | ||
| 282 | |||
| 283 | /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | ||
| 284 | pub fn reader(&self) -> BufferedCanReceiver { | ||
| 285 | self.rx.reader() | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 311 | /// CAN driver, transmit half. | 289 | /// CAN driver, transmit half. |
| 312 | pub struct CanTx<'d, T: Instance> { | 290 | pub struct CanTx<'d, T: Instance> { |
| 313 | tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, | 291 | tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, |
| @@ -319,7 +297,7 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 319 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | 297 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. |
| 320 | pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { | 298 | pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { |
| 321 | poll_fn(|cx| { | 299 | poll_fn(|cx| { |
| 322 | T::state().tx_waker.register(cx.waker()); | 300 | T::state().tx_mode.register(cx.waker()); |
| 323 | if let Ok(status) = self.tx.transmit(frame) { | 301 | if let Ok(status) = self.tx.transmit(frame) { |
| 324 | return Poll::Ready(status); | 302 | return Poll::Ready(status); |
| 325 | } | 303 | } |
| @@ -338,7 +316,7 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 338 | 316 | ||
| 339 | async fn flush_inner(mb: crate::can::bx::Mailbox) { | 317 | async fn flush_inner(mb: crate::can::bx::Mailbox) { |
| 340 | poll_fn(|cx| { | 318 | poll_fn(|cx| { |
| 341 | T::state().tx_waker.register(cx.waker()); | 319 | T::state().tx_mode.register(cx.waker()); |
| 342 | if T::regs().tsr().read().tme(mb.index()) { | 320 | if T::regs().tsr().read().tme(mb.index()) { |
| 343 | return Poll::Ready(()); | 321 | return Poll::Ready(()); |
| 344 | } | 322 | } |
| @@ -355,7 +333,7 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 355 | 333 | ||
| 356 | async fn flush_any_inner() { | 334 | async fn flush_any_inner() { |
| 357 | poll_fn(|cx| { | 335 | poll_fn(|cx| { |
| 358 | T::state().tx_waker.register(cx.waker()); | 336 | T::state().tx_mode.register(cx.waker()); |
| 359 | 337 | ||
| 360 | let tsr = T::regs().tsr().read(); | 338 | let tsr = T::regs().tsr().read(); |
| 361 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | 339 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) |
| @@ -377,7 +355,7 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 377 | 355 | ||
| 378 | async fn flush_all_inner() { | 356 | async fn flush_all_inner() { |
| 379 | poll_fn(|cx| { | 357 | poll_fn(|cx| { |
| 380 | T::state().tx_waker.register(cx.waker()); | 358 | T::state().tx_mode.register(cx.waker()); |
| 381 | 359 | ||
| 382 | let tsr = T::regs().tsr().read(); | 360 | let tsr = T::regs().tsr().read(); |
| 383 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | 361 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) |
| @@ -396,13 +374,68 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 396 | pub async fn flush_all(&self) { | 374 | pub async fn flush_all(&self) { |
| 397 | Self::flush_all_inner().await | 375 | Self::flush_all_inner().await |
| 398 | } | 376 | } |
| 377 | |||
| 378 | /// Return a buffered instance of driver. User must supply Buffers | ||
| 379 | pub fn buffered<const TX_BUF_SIZE: usize>( | ||
| 380 | self, | ||
| 381 | txb: &'static mut TxBuf<TX_BUF_SIZE>, | ||
| 382 | ) -> BufferedCanTx<'d, T, TX_BUF_SIZE> { | ||
| 383 | BufferedCanTx::new(self.tx, txb) | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | /// User supplied buffer for TX buffering | ||
| 388 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; | ||
| 389 | |||
| 390 | /// Buffered CAN driver, transmit half. | ||
| 391 | pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { | ||
| 392 | _tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, | ||
| 393 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | ||
| 394 | } | ||
| 395 | |||
| 396 | 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 { | ||
| 398 | Self { _tx, tx_buf }.setup() | ||
| 399 | } | ||
| 400 | |||
| 401 | fn setup(self) -> Self { | ||
| 402 | // We don't want interrupts being processed while we change modes. | ||
| 403 | critical_section::with(|_| unsafe { | ||
| 404 | let tx_inner = self::common::ClassicBufferedTxInner { | ||
| 405 | tx_receiver: self.tx_buf.receiver().into(), | ||
| 406 | }; | ||
| 407 | T::mut_state().tx_mode = TxMode::Buffered(tx_inner); | ||
| 408 | }); | ||
| 409 | self | ||
| 410 | } | ||
| 411 | |||
| 412 | /// Async write frame to TX buffer. | ||
| 413 | pub async fn write(&mut self, frame: &Frame) { | ||
| 414 | self.tx_buf.send(*frame).await; | ||
| 415 | T::TXInterrupt::pend(); // Wake for Tx | ||
| 416 | } | ||
| 417 | |||
| 418 | /// Returns a sender that can be used for sending CAN frames. | ||
| 419 | pub fn writer(&self) -> BufferedCanSender { | ||
| 420 | BufferedCanSender { | ||
| 421 | tx_buf: self.tx_buf.sender().into(), | ||
| 422 | waker: T::TXInterrupt::pend, | ||
| 423 | } | ||
| 424 | } | ||
| 425 | } | ||
| 426 | |||
| 427 | impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> { | ||
| 428 | fn drop(&mut self) { | ||
| 429 | critical_section::with(|_| unsafe { | ||
| 430 | T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 431 | }); | ||
| 432 | } | ||
| 399 | } | 433 | } |
| 400 | 434 | ||
| 401 | /// CAN driver, receive half. | 435 | /// CAN driver, receive half. |
| 402 | #[allow(dead_code)] | 436 | #[allow(dead_code)] |
| 403 | pub struct CanRx<'d, T: Instance> { | 437 | pub struct CanRx<'d, T: Instance> { |
| 404 | rx0: crate::can::bx::Rx0<BxcanInstance<'d, T>>, | 438 | rx: crate::can::bx::Rx<BxcanInstance<'d, T>>, |
| 405 | rx1: crate::can::bx::Rx1<BxcanInstance<'d, T>>, | ||
| 406 | } | 439 | } |
| 407 | 440 | ||
| 408 | impl<'d, T: Instance> CanRx<'d, T> { | 441 | impl<'d, T: Instance> CanRx<'d, T> { |
| @@ -412,59 +445,107 @@ impl<'d, T: Instance> CanRx<'d, T> { | |||
| 412 | /// | 445 | /// |
| 413 | /// Returns a tuple of the time the message was received and the message frame | 446 | /// Returns a tuple of the time the message was received and the message frame |
| 414 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | 447 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 415 | poll_fn(|cx| { | 448 | T::state().rx_mode.read::<T>().await |
| 416 | T::state().err_waker.register(cx.waker()); | ||
| 417 | if let Poll::Ready(envelope) = T::state().rx_queue.receive().poll_unpin(cx) { | ||
| 418 | return Poll::Ready(Ok(envelope)); | ||
| 419 | } else if let Some(err) = self.curr_error() { | ||
| 420 | return Poll::Ready(Err(err)); | ||
| 421 | } | ||
| 422 | |||
| 423 | Poll::Pending | ||
| 424 | }) | ||
| 425 | .await | ||
| 426 | } | 449 | } |
| 427 | 450 | ||
| 428 | /// Attempts to read a CAN frame without blocking. | 451 | /// Attempts to read a CAN frame without blocking. |
| 429 | /// | 452 | /// |
| 430 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | 453 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. |
| 431 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | 454 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { |
| 432 | if let Ok(envelope) = T::state().rx_queue.try_receive() { | 455 | T::state().rx_mode.try_read::<T>() |
| 433 | return Ok(envelope); | 456 | } |
| 434 | } | ||
| 435 | 457 | ||
| 436 | if let Some(err) = self.curr_error() { | 458 | /// Waits while receive queue is empty. |
| 437 | return Err(TryReadError::BusError(err)); | 459 | pub async fn wait_not_empty(&mut self) { |
| 438 | } | 460 | T::state().rx_mode.wait_not_empty::<T>().await |
| 461 | } | ||
| 439 | 462 | ||
| 440 | Err(TryReadError::Empty) | 463 | /// Return a buffered instance of driver. User must supply Buffers |
| 464 | pub fn buffered<const RX_BUF_SIZE: usize>( | ||
| 465 | self, | ||
| 466 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, | ||
| 467 | ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { | ||
| 468 | BufferedCanRx::new(self.rx, rxb) | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | /// User supplied buffer for RX Buffering | ||
| 473 | pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>; | ||
| 474 | |||
| 475 | /// CAN driver, receive half in Buffered mode. | ||
| 476 | pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { | ||
| 477 | _rx: crate::can::bx::Rx<BxcanInstance<'d, T>>, | ||
| 478 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | ||
| 479 | } | ||
| 480 | |||
| 481 | 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 { | ||
| 483 | BufferedCanRx { _rx, rx_buf }.setup() | ||
| 484 | } | ||
| 485 | |||
| 486 | fn setup(self) -> Self { | ||
| 487 | // We don't want interrupts being processed while we change modes. | ||
| 488 | critical_section::with(|_| unsafe { | ||
| 489 | let rx_inner = self::common::ClassicBufferedRxInner { | ||
| 490 | rx_sender: self.rx_buf.sender().into(), | ||
| 491 | }; | ||
| 492 | T::mut_state().rx_mode = RxMode::Buffered(rx_inner); | ||
| 493 | }); | ||
| 494 | self | ||
| 495 | } | ||
| 496 | |||
| 497 | /// Async read frame from RX buffer. | ||
| 498 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | ||
| 499 | self.rx_buf.receive().await | ||
| 500 | } | ||
| 501 | |||
| 502 | /// Attempts to read a CAN frame without blocking. | ||
| 503 | /// | ||
| 504 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | ||
| 505 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | ||
| 506 | match &T::state().rx_mode { | ||
| 507 | RxMode::Buffered(_) => { | ||
| 508 | if let Ok(result) = self.rx_buf.try_receive() { | ||
| 509 | match result { | ||
| 510 | Ok(envelope) => Ok(envelope), | ||
| 511 | Err(e) => Err(TryReadError::BusError(e)), | ||
| 512 | } | ||
| 513 | } else { | ||
| 514 | let registers = crate::can::bx::Registers { canregs: T::regs() }; | ||
| 515 | if let Some(err) = registers.curr_error() { | ||
| 516 | return Err(TryReadError::BusError(err)); | ||
| 517 | } else { | ||
| 518 | Err(TryReadError::Empty) | ||
| 519 | } | ||
| 520 | } | ||
| 521 | } | ||
| 522 | _ => { | ||
| 523 | panic!("Bad Mode") | ||
| 524 | } | ||
| 525 | } | ||
| 441 | } | 526 | } |
| 442 | 527 | ||
| 443 | /// Waits while receive queue is empty. | 528 | /// Waits while receive queue is empty. |
| 444 | pub async fn wait_not_empty(&mut self) { | 529 | pub async fn wait_not_empty(&mut self) { |
| 445 | poll_fn(|cx| T::state().rx_queue.poll_ready_to_receive(cx)).await | 530 | poll_fn(|cx| self.rx_buf.poll_ready_to_receive(cx)).await |
| 446 | } | 531 | } |
| 447 | 532 | ||
| 448 | fn curr_error(&self) -> Option<BusError> { | 533 | /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. |
| 449 | let err = { T::regs().esr().read() }; | 534 | pub fn reader(&self) -> BufferedCanReceiver { |
| 450 | if err.boff() { | 535 | self.rx_buf.receiver().into() |
| 451 | return Some(BusError::BusOff); | ||
| 452 | } else if err.epvf() { | ||
| 453 | return Some(BusError::BusPassive); | ||
| 454 | } else if err.ewgf() { | ||
| 455 | return Some(BusError::BusWarning); | ||
| 456 | } else if let Some(err) = err.lec().into_bus_err() { | ||
| 457 | return Some(err); | ||
| 458 | } | ||
| 459 | None | ||
| 460 | } | 536 | } |
| 461 | } | 537 | } |
| 462 | 538 | ||
| 463 | enum RxFifo { | 539 | impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> { |
| 464 | Fifo0, | 540 | fn drop(&mut self) { |
| 465 | Fifo1, | 541 | critical_section::with(|_| unsafe { |
| 542 | T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 543 | }); | ||
| 544 | } | ||
| 466 | } | 545 | } |
| 467 | 546 | ||
| 547 | use crate::can::bx::RxFifo; | ||
| 548 | |||
| 468 | impl<'d, T: Instance> Drop for Can<'d, T> { | 549 | impl<'d, T: Instance> Drop for Can<'d, T> { |
| 469 | fn drop(&mut self) { | 550 | fn drop(&mut self) { |
| 470 | // Cannot call `free()` because it moves the instance. | 551 | // Cannot call `free()` because it moves the instance. |
| @@ -488,18 +569,163 @@ impl<'d, T: Instance> DerefMut for Can<'d, T> { | |||
| 488 | } | 569 | } |
| 489 | } | 570 | } |
| 490 | 571 | ||
| 572 | use crate::can::enums::{BusError, TryReadError}; | ||
| 573 | |||
| 574 | pub(crate) enum RxMode { | ||
| 575 | NonBuffered(AtomicWaker), | ||
| 576 | Buffered(crate::can::_version::common::ClassicBufferedRxInner), | ||
| 577 | } | ||
| 578 | |||
| 579 | impl RxMode { | ||
| 580 | pub fn on_interrupt<T: Instance>(&self, fifo: crate::can::_version::bx::RxFifo) { | ||
| 581 | match self { | ||
| 582 | Self::NonBuffered(waker) => { | ||
| 583 | // Disable interrupts until read | ||
| 584 | let fifo_idx = match fifo { | ||
| 585 | crate::can::_version::bx::RxFifo::Fifo0 => 0usize, | ||
| 586 | crate::can::_version::bx::RxFifo::Fifo1 => 1usize, | ||
| 587 | }; | ||
| 588 | T::regs().ier().write(|w| { | ||
| 589 | w.set_fmpie(fifo_idx, false); | ||
| 590 | }); | ||
| 591 | waker.wake(); | ||
| 592 | } | ||
| 593 | Self::Buffered(buf) => { | ||
| 594 | let regsisters = crate::can::bx::Registers { canregs: T::regs() }; | ||
| 595 | |||
| 596 | loop { | ||
| 597 | match regsisters.receive_fifo(fifo) { | ||
| 598 | Some(envelope) => { | ||
| 599 | // NOTE: consensus was reached that if rx_queue is full, packets should be dropped | ||
| 600 | let _ = buf.rx_sender.try_send(Ok(envelope)); | ||
| 601 | } | ||
| 602 | None => return, | ||
| 603 | }; | ||
| 604 | } | ||
| 605 | } | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | pub async fn read<T: Instance>(&self) -> Result<Envelope, BusError> { | ||
| 610 | match self { | ||
| 611 | Self::NonBuffered(waker) => { | ||
| 612 | poll_fn(|cx| { | ||
| 613 | T::state().err_waker.register(cx.waker()); | ||
| 614 | waker.register(cx.waker()); | ||
| 615 | match self.try_read::<T>() { | ||
| 616 | Ok(result) => Poll::Ready(Ok(result)), | ||
| 617 | Err(TryReadError::Empty) => Poll::Pending, | ||
| 618 | Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), | ||
| 619 | } | ||
| 620 | }) | ||
| 621 | .await | ||
| 622 | } | ||
| 623 | _ => { | ||
| 624 | panic!("Bad Mode") | ||
| 625 | } | ||
| 626 | } | ||
| 627 | } | ||
| 628 | pub fn try_read<T: Instance>(&self) -> Result<Envelope, TryReadError> { | ||
| 629 | match self { | ||
| 630 | Self::NonBuffered(_) => { | ||
| 631 | let registers = crate::can::bx::Registers { canregs: T::regs() }; | ||
| 632 | if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo0) { | ||
| 633 | T::regs().ier().write(|w| { | ||
| 634 | w.set_fmpie(0, true); | ||
| 635 | }); | ||
| 636 | Ok(msg) | ||
| 637 | } else if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo1) { | ||
| 638 | T::regs().ier().write(|w| { | ||
| 639 | w.set_fmpie(1, true); | ||
| 640 | }); | ||
| 641 | Ok(msg) | ||
| 642 | } else if let Some(err) = registers.curr_error() { | ||
| 643 | Err(TryReadError::BusError(err)) | ||
| 644 | } else { | ||
| 645 | Err(TryReadError::Empty) | ||
| 646 | } | ||
| 647 | } | ||
| 648 | _ => { | ||
| 649 | panic!("Bad Mode") | ||
| 650 | } | ||
| 651 | } | ||
| 652 | } | ||
| 653 | pub async fn wait_not_empty<T: Instance>(&self) { | ||
| 654 | match &T::state().rx_mode { | ||
| 655 | Self::NonBuffered(waker) => { | ||
| 656 | poll_fn(|cx| { | ||
| 657 | waker.register(cx.waker()); | ||
| 658 | let registers = crate::can::bx::Registers { canregs: T::regs() }; | ||
| 659 | if registers.receive_frame_available() { | ||
| 660 | Poll::Ready(()) | ||
| 661 | } else { | ||
| 662 | Poll::Pending | ||
| 663 | } | ||
| 664 | }) | ||
| 665 | .await | ||
| 666 | } | ||
| 667 | _ => { | ||
| 668 | panic!("Bad Mode") | ||
| 669 | } | ||
| 670 | } | ||
| 671 | } | ||
| 672 | } | ||
| 673 | |||
| 674 | enum TxMode { | ||
| 675 | NonBuffered(AtomicWaker), | ||
| 676 | Buffered(self::common::ClassicBufferedTxInner), | ||
| 677 | } | ||
| 678 | |||
| 679 | impl TxMode { | ||
| 680 | pub fn buffer_free<T: Instance>(&self) -> bool { | ||
| 681 | let tsr = T::regs().tsr().read(); | ||
| 682 | tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | ||
| 683 | || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) | ||
| 684 | || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) | ||
| 685 | } | ||
| 686 | pub fn on_interrupt<T: Instance>(&self) { | ||
| 687 | match &T::state().tx_mode { | ||
| 688 | TxMode::NonBuffered(waker) => waker.wake(), | ||
| 689 | TxMode::Buffered(buf) => { | ||
| 690 | while self.buffer_free::<T>() { | ||
| 691 | match buf.tx_receiver.try_receive() { | ||
| 692 | Ok(frame) => { | ||
| 693 | let mut registers = crate::can::bx::Registers { canregs: T::regs() }; | ||
| 694 | _ = registers.transmit(&frame); | ||
| 695 | } | ||
| 696 | Err(_) => { | ||
| 697 | break; | ||
| 698 | } | ||
| 699 | } | ||
| 700 | } | ||
| 701 | } | ||
| 702 | } | ||
| 703 | } | ||
| 704 | |||
| 705 | fn register(&self, arg: &core::task::Waker) { | ||
| 706 | match self { | ||
| 707 | TxMode::NonBuffered(waker) => { | ||
| 708 | waker.register(arg); | ||
| 709 | } | ||
| 710 | _ => { | ||
| 711 | panic!("Bad mode"); | ||
| 712 | } | ||
| 713 | } | ||
| 714 | } | ||
| 715 | } | ||
| 716 | |||
| 491 | struct State { | 717 | struct State { |
| 492 | pub tx_waker: AtomicWaker, | 718 | pub(crate) rx_mode: RxMode, |
| 719 | pub(crate) tx_mode: TxMode, | ||
| 493 | pub err_waker: AtomicWaker, | 720 | pub err_waker: AtomicWaker, |
| 494 | pub rx_queue: Channel<CriticalSectionRawMutex, Envelope, 32>, | ||
| 495 | } | 721 | } |
| 496 | 722 | ||
| 497 | impl State { | 723 | impl State { |
| 498 | pub const fn new() -> Self { | 724 | pub const fn new() -> Self { |
| 499 | Self { | 725 | Self { |
| 500 | tx_waker: AtomicWaker::new(), | 726 | rx_mode: RxMode::NonBuffered(AtomicWaker::new()), |
| 727 | tx_mode: TxMode::NonBuffered(AtomicWaker::new()), | ||
| 501 | err_waker: AtomicWaker::new(), | 728 | err_waker: AtomicWaker::new(), |
| 502 | rx_queue: Channel::new(), | ||
| 503 | } | 729 | } |
| 504 | } | 730 | } |
| 505 | } | 731 | } |
| @@ -507,6 +733,7 @@ impl State { | |||
| 507 | trait SealedInstance { | 733 | trait SealedInstance { |
| 508 | fn regs() -> crate::pac::can::Can; | 734 | fn regs() -> crate::pac::can::Can; |
| 509 | fn state() -> &'static State; | 735 | fn state() -> &'static State; |
| 736 | unsafe fn mut_state() -> &'static mut State; | ||
| 510 | } | 737 | } |
| 511 | 738 | ||
| 512 | /// CAN instance trait. | 739 | /// CAN instance trait. |
| @@ -535,9 +762,12 @@ foreach_peripheral!( | |||
| 535 | crate::pac::$inst | 762 | crate::pac::$inst |
| 536 | } | 763 | } |
| 537 | 764 | ||
| 765 | unsafe fn mut_state() -> & 'static mut State { | ||
| 766 | static mut STATE: State = State::new(); | ||
| 767 | &mut *core::ptr::addr_of_mut!(STATE) | ||
| 768 | } | ||
| 538 | fn state() -> &'static State { | 769 | fn state() -> &'static State { |
| 539 | static STATE: State = State::new(); | 770 | unsafe { peripherals::$inst::mut_state() } |
| 540 | &STATE | ||
| 541 | } | 771 | } |
| 542 | } | 772 | } |
| 543 | 773 | ||
| @@ -601,22 +831,3 @@ impl Index for crate::can::bx::Mailbox { | |||
| 601 | } | 831 | } |
| 602 | } | 832 | } |
| 603 | } | 833 | } |
| 604 | |||
| 605 | trait IntoBusError { | ||
| 606 | fn into_bus_err(self) -> Option<BusError>; | ||
| 607 | } | ||
| 608 | |||
| 609 | impl IntoBusError for Lec { | ||
| 610 | fn into_bus_err(self) -> Option<BusError> { | ||
| 611 | match self { | ||
| 612 | Lec::STUFF => Some(BusError::Stuff), | ||
| 613 | Lec::FORM => Some(BusError::Form), | ||
| 614 | Lec::ACK => Some(BusError::Acknowledge), | ||
| 615 | Lec::BITRECESSIVE => Some(BusError::BitRecessive), | ||
| 616 | Lec::BITDOMINANT => Some(BusError::BitDominant), | ||
| 617 | Lec::CRC => Some(BusError::Crc), | ||
| 618 | Lec::CUSTOM => Some(BusError::Software), | ||
| 619 | _ => None, | ||
| 620 | } | ||
| 621 | } | ||
| 622 | } | ||
diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs new file mode 100644 index 000000000..570761b19 --- /dev/null +++ b/embassy-stm32/src/can/common.rs | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | use embassy_sync::channel::{DynamicReceiver, DynamicSender}; | ||
| 2 | |||
| 3 | use crate::can::_version::enums::*; | ||
| 4 | use crate::can::_version::frame::*; | ||
| 5 | |||
| 6 | pub(crate) struct ClassicBufferedRxInner { | ||
| 7 | pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>, | ||
| 8 | } | ||
| 9 | pub(crate) struct ClassicBufferedTxInner { | ||
| 10 | pub tx_receiver: DynamicReceiver<'static, Frame>, | ||
| 11 | } | ||
| 12 | |||
| 13 | #[cfg(any(can_fdcan_v1, can_fdcan_h7))] | ||
| 14 | |||
| 15 | pub(crate) struct FdBufferedRxInner { | ||
| 16 | pub rx_sender: DynamicSender<'static, Result<FdEnvelope, BusError>>, | ||
| 17 | } | ||
| 18 | |||
| 19 | #[cfg(any(can_fdcan_v1, can_fdcan_h7))] | ||
| 20 | pub(crate) struct FdBufferedTxInner { | ||
| 21 | pub tx_receiver: DynamicReceiver<'static, FdFrame>, | ||
| 22 | } | ||
| 23 | |||
| 24 | /// Sender that can be used for sending CAN frames. | ||
| 25 | #[derive(Copy, Clone)] | ||
| 26 | pub struct BufferedCanSender { | ||
| 27 | pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, Frame>, | ||
| 28 | pub(crate) waker: fn(), | ||
| 29 | } | ||
| 30 | |||
| 31 | impl BufferedCanSender { | ||
| 32 | /// Async write frame to TX buffer. | ||
| 33 | pub fn try_write(&mut self, frame: Frame) -> Result<(), embassy_sync::channel::TrySendError<Frame>> { | ||
| 34 | self.tx_buf.try_send(frame)?; | ||
| 35 | (self.waker)(); | ||
| 36 | Ok(()) | ||
| 37 | } | ||
| 38 | |||
| 39 | /// Async write frame to TX buffer. | ||
| 40 | pub async fn write(&mut self, frame: Frame) { | ||
| 41 | self.tx_buf.send(frame).await; | ||
| 42 | (self.waker)(); | ||
| 43 | } | ||
| 44 | |||
| 45 | /// Allows a poll_fn to poll until the channel is ready to write | ||
| 46 | pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { | ||
| 47 | self.tx_buf.poll_ready_to_send(cx) | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | ||
| 52 | pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, Result<Envelope, BusError>>; | ||
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 651de9194..4d89c84d1 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs | |||
| @@ -40,3 +40,13 @@ pub enum FrameCreateError { | |||
| 40 | /// Invalid ID. | 40 | /// Invalid ID. |
| 41 | InvalidCanId, | 41 | InvalidCanId, |
| 42 | } | 42 | } |
| 43 | |||
| 44 | /// Error returned by `try_read` | ||
| 45 | #[derive(Debug)] | ||
| 46 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 47 | pub enum TryReadError { | ||
| 48 | /// Bus error | ||
| 49 | BusError(BusError), | ||
| 50 | /// Receive buffer is empty | ||
| 51 | Empty, | ||
| 52 | } | ||
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 76b76afe1..e32f19d91 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs | |||
| @@ -397,13 +397,13 @@ impl Registers { | |||
| 397 | 397 | ||
| 398 | /// Moves out of ConfigMode and into specified mode | 398 | /// Moves out of ConfigMode and into specified mode |
| 399 | #[inline] | 399 | #[inline] |
| 400 | pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::FdcanOperatingMode) { | 400 | pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) { |
| 401 | match mode { | 401 | match mode { |
| 402 | crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), | 402 | crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), |
| 403 | crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), | 403 | crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), |
| 404 | crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true), | 404 | crate::can::OperatingMode::NormalOperationMode => self.set_normal_operations(true), |
| 405 | crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), | 405 | crate::can::OperatingMode::RestrictedOperationMode => self.set_restricted_operations(true), |
| 406 | crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), | 406 | crate::can::OperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true), |
| 407 | } | 407 | } |
| 408 | self.leave_init_mode(config); | 408 | self.leave_init_mode(config); |
| 409 | } | 409 | } |
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 4ea036ab4..2ccf4b093 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs | |||
| @@ -14,6 +14,7 @@ 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; | ||
| 17 | pub mod enums; | 18 | pub mod enums; |
| 18 | pub(crate) mod fd; | 19 | pub(crate) mod fd; |
| 19 | pub mod frame; | 20 | pub mod frame; |
| @@ -25,6 +26,8 @@ use fd::filter::*; | |||
| 25 | pub use fd::{config, filter}; | 26 | pub use fd::{config, filter}; |
| 26 | use frame::*; | 27 | use frame::*; |
| 27 | 28 | ||
| 29 | pub use self::common::{BufferedCanReceiver, BufferedCanSender}; | ||
| 30 | |||
| 28 | /// Timestamp for incoming packets. Use Embassy time when enabled. | 31 | /// Timestamp for incoming packets. Use Embassy time when enabled. |
| 29 | #[cfg(feature = "time")] | 32 | #[cfg(feature = "time")] |
| 30 | pub type Timestamp = embassy_time::Instant; | 33 | pub type Timestamp = embassy_time::Instant; |
| @@ -107,7 +110,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1Interrup | |||
| 107 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 110 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 108 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 111 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 109 | /// Different operating modes | 112 | /// Different operating modes |
| 110 | pub enum FdcanOperatingMode { | 113 | pub enum OperatingMode { |
| 111 | //PoweredDownMode, | 114 | //PoweredDownMode, |
| 112 | //ConfigMode, | 115 | //ConfigMode, |
| 113 | /// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without | 116 | /// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without |
| @@ -145,7 +148,7 @@ pub enum FdcanOperatingMode { | |||
| 145 | 148 | ||
| 146 | /// FDCAN Configuration instance instance | 149 | /// FDCAN Configuration instance instance |
| 147 | /// Create instance of this first | 150 | /// Create instance of this first |
| 148 | pub struct FdcanConfigurator<'d, T: Instance> { | 151 | pub struct CanConfigurator<'d, T: Instance> { |
| 149 | config: crate::can::fd::config::FdCanConfig, | 152 | config: crate::can::fd::config::FdCanConfig, |
| 150 | /// Reference to internals. | 153 | /// Reference to internals. |
| 151 | instance: FdcanInstance<'d, T>, | 154 | instance: FdcanInstance<'d, T>, |
| @@ -166,7 +169,7 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransm | |||
| 166 | } | 169 | } |
| 167 | } | 170 | } |
| 168 | 171 | ||
| 169 | impl<'d, T: Instance> FdcanConfigurator<'d, T> { | 172 | impl<'d, T: Instance> CanConfigurator<'d, T> { |
| 170 | /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. | 173 | /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. |
| 171 | /// You must call [Fdcan::enable_non_blocking] to use the peripheral. | 174 | /// You must call [Fdcan::enable_non_blocking] to use the peripheral. |
| 172 | pub fn new( | 175 | pub fn new( |
| @@ -176,7 +179,7 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { | |||
| 176 | _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> | 179 | _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> |
| 177 | + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> | 180 | + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> |
| 178 | + 'd, | 181 | + 'd, |
| 179 | ) -> FdcanConfigurator<'d, T> { | 182 | ) -> CanConfigurator<'d, T> { |
| 180 | into_ref!(peri, rx, tx); | 183 | into_ref!(peri, rx, tx); |
| 181 | 184 | ||
| 182 | rx.set_as_af(rx.af_num(), AFType::Input); | 185 | rx.set_as_af(rx.af_num(), AFType::Input); |
| @@ -270,13 +273,13 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { | |||
| 270 | } | 273 | } |
| 271 | 274 | ||
| 272 | /// Start in mode. | 275 | /// Start in mode. |
| 273 | pub fn start(self, mode: FdcanOperatingMode) -> Fdcan<'d, T> { | 276 | pub fn start(self, mode: OperatingMode) -> Can<'d, T> { |
| 274 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit); | 277 | let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit); |
| 275 | critical_section::with(|_| unsafe { | 278 | critical_section::with(|_| unsafe { |
| 276 | T::mut_state().ns_per_timer_tick = ns_per_timer_tick; | 279 | T::mut_state().ns_per_timer_tick = ns_per_timer_tick; |
| 277 | }); | 280 | }); |
| 278 | T::registers().into_mode(self.config, mode); | 281 | T::registers().into_mode(self.config, mode); |
| 279 | let ret = Fdcan { | 282 | let ret = Can { |
| 280 | config: self.config, | 283 | config: self.config, |
| 281 | instance: self.instance, | 284 | instance: self.instance, |
| 282 | _mode: mode, | 285 | _mode: mode, |
| @@ -285,30 +288,30 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> { | |||
| 285 | } | 288 | } |
| 286 | 289 | ||
| 287 | /// Start, entering mode. Does same as start(mode) | 290 | /// Start, entering mode. Does same as start(mode) |
| 288 | pub fn into_normal_mode(self) -> Fdcan<'d, T> { | 291 | pub fn into_normal_mode(self) -> Can<'d, T> { |
| 289 | self.start(FdcanOperatingMode::NormalOperationMode) | 292 | self.start(OperatingMode::NormalOperationMode) |
| 290 | } | 293 | } |
| 291 | 294 | ||
| 292 | /// Start, entering mode. Does same as start(mode) | 295 | /// Start, entering mode. Does same as start(mode) |
| 293 | pub fn into_internal_loopback_mode(self) -> Fdcan<'d, T> { | 296 | pub fn into_internal_loopback_mode(self) -> Can<'d, T> { |
| 294 | self.start(FdcanOperatingMode::InternalLoopbackMode) | 297 | self.start(OperatingMode::InternalLoopbackMode) |
| 295 | } | 298 | } |
| 296 | 299 | ||
| 297 | /// Start, entering mode. Does same as start(mode) | 300 | /// Start, entering mode. Does same as start(mode) |
| 298 | pub fn into_external_loopback_mode(self) -> Fdcan<'d, T> { | 301 | pub fn into_external_loopback_mode(self) -> Can<'d, T> { |
| 299 | self.start(FdcanOperatingMode::ExternalLoopbackMode) | 302 | self.start(OperatingMode::ExternalLoopbackMode) |
| 300 | } | 303 | } |
| 301 | } | 304 | } |
| 302 | 305 | ||
| 303 | /// FDCAN Instance | 306 | /// FDCAN Instance |
| 304 | pub struct Fdcan<'d, T: Instance> { | 307 | pub struct Can<'d, T: Instance> { |
| 305 | config: crate::can::fd::config::FdCanConfig, | 308 | config: crate::can::fd::config::FdCanConfig, |
| 306 | /// Reference to internals. | 309 | /// Reference to internals. |
| 307 | instance: FdcanInstance<'d, T>, | 310 | instance: FdcanInstance<'d, T>, |
| 308 | _mode: FdcanOperatingMode, | 311 | _mode: OperatingMode, |
| 309 | } | 312 | } |
| 310 | 313 | ||
| 311 | impl<'d, T: Instance> Fdcan<'d, T> { | 314 | impl<'d, T: Instance> Can<'d, T> { |
| 312 | /// Flush one of the TX mailboxes. | 315 | /// Flush one of the TX mailboxes. |
| 313 | pub async fn flush(&self, idx: usize) { | 316 | pub async fn flush(&self, idx: usize) { |
| 314 | poll_fn(|cx| { | 317 | poll_fn(|cx| { |
| @@ -331,12 +334,12 @@ impl<'d, T: Instance> Fdcan<'d, T> { | |||
| 331 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | 334 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames |
| 332 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 335 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 333 | /// transmitted, then tries again. | 336 | /// transmitted, then tries again. |
| 334 | pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { | 337 | pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { |
| 335 | T::state().tx_mode.write::<T>(frame).await | 338 | T::state().tx_mode.write::<T>(frame).await |
| 336 | } | 339 | } |
| 337 | 340 | ||
| 338 | /// Returns the next received message frame | 341 | /// Returns the next received message frame |
| 339 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | 342 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 340 | T::state().rx_mode.read_classic::<T>().await | 343 | T::state().rx_mode.read_classic::<T>().await |
| 341 | } | 344 | } |
| 342 | 345 | ||
| @@ -349,19 +352,19 @@ impl<'d, T: Instance> Fdcan<'d, T> { | |||
| 349 | } | 352 | } |
| 350 | 353 | ||
| 351 | /// Returns the next received message frame | 354 | /// Returns the next received message frame |
| 352 | pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | 355 | pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> { |
| 353 | T::state().rx_mode.read_fd::<T>().await | 356 | T::state().rx_mode.read_fd::<T>().await |
| 354 | } | 357 | } |
| 355 | 358 | ||
| 356 | /// Split instance into separate Tx(write) and Rx(read) portions | 359 | /// Split instance into separate Tx(write) and Rx(read) portions |
| 357 | pub fn split(self) -> (FdcanTx<'d, T>, FdcanRx<'d, T>) { | 360 | pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>) { |
| 358 | ( | 361 | ( |
| 359 | FdcanTx { | 362 | CanTx { |
| 360 | config: self.config, | 363 | config: self.config, |
| 361 | _instance: self.instance, | 364 | _instance: self.instance, |
| 362 | _mode: self._mode, | 365 | _mode: self._mode, |
| 363 | }, | 366 | }, |
| 364 | FdcanRx { | 367 | CanRx { |
| 365 | _instance1: PhantomData::<T>, | 368 | _instance1: PhantomData::<T>, |
| 366 | _instance2: T::regs(), | 369 | _instance2: T::regs(), |
| 367 | _mode: self._mode, | 370 | _mode: self._mode, |
| @@ -370,8 +373,8 @@ impl<'d, T: Instance> Fdcan<'d, T> { | |||
| 370 | } | 373 | } |
| 371 | 374 | ||
| 372 | /// Join split rx and tx portions back together | 375 | /// Join split rx and tx portions back together |
| 373 | pub fn join(tx: FdcanTx<'d, T>, rx: FdcanRx<'d, T>) -> Self { | 376 | pub fn join(tx: CanTx<'d, T>, rx: CanRx<'d, T>) -> Self { |
| 374 | Fdcan { | 377 | Can { |
| 375 | config: tx.config, | 378 | config: tx.config, |
| 376 | //_instance2: T::regs(), | 379 | //_instance2: T::regs(), |
| 377 | instance: tx._instance, | 380 | instance: tx._instance, |
| @@ -399,59 +402,27 @@ impl<'d, T: Instance> Fdcan<'d, T> { | |||
| 399 | } | 402 | } |
| 400 | 403 | ||
| 401 | /// User supplied buffer for RX Buffering | 404 | /// User supplied buffer for RX Buffering |
| 402 | pub type RxBuf<const BUF_SIZE: usize> = | 405 | pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>; |
| 403 | Channel<CriticalSectionRawMutex, Result<(ClassicFrame, Timestamp), BusError>, BUF_SIZE>; | ||
| 404 | 406 | ||
| 405 | /// User supplied buffer for TX buffering | 407 | /// User supplied buffer for TX buffering |
| 406 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, ClassicFrame, BUF_SIZE>; | 408 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; |
| 407 | 409 | ||
| 408 | /// Buffered FDCAN Instance | 410 | /// Buffered FDCAN Instance |
| 409 | pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | 411 | pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { |
| 410 | _instance1: PhantomData<T>, | 412 | _instance1: PhantomData<T>, |
| 411 | _instance2: &'d crate::pac::can::Fdcan, | 413 | _instance2: &'d crate::pac::can::Fdcan, |
| 412 | _mode: FdcanOperatingMode, | 414 | _mode: OperatingMode, |
| 413 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | 415 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, |
| 414 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | 416 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, |
| 415 | } | 417 | } |
| 416 | 418 | ||
| 417 | /// Sender that can be used for sending CAN frames. | ||
| 418 | #[derive(Copy, Clone)] | ||
| 419 | pub struct BufferedCanSender { | ||
| 420 | tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>, | ||
| 421 | waker: fn(), | ||
| 422 | } | ||
| 423 | |||
| 424 | impl BufferedCanSender { | ||
| 425 | /// Async write frame to TX buffer. | ||
| 426 | pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError<ClassicFrame>> { | ||
| 427 | self.tx_buf.try_send(frame)?; | ||
| 428 | (self.waker)(); | ||
| 429 | Ok(()) | ||
| 430 | } | ||
| 431 | |||
| 432 | /// Async write frame to TX buffer. | ||
| 433 | pub async fn write(&mut self, frame: ClassicFrame) { | ||
| 434 | self.tx_buf.send(frame).await; | ||
| 435 | (self.waker)(); | ||
| 436 | } | ||
| 437 | |||
| 438 | /// Allows a poll_fn to poll until the channel is ready to write | ||
| 439 | pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { | ||
| 440 | self.tx_buf.poll_ready_to_send(cx) | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | ||
| 445 | pub type BufferedCanReceiver = | ||
| 446 | embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>; | ||
| 447 | |||
| 448 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | 419 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> |
| 449 | BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> | 420 | BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> |
| 450 | { | 421 | { |
| 451 | fn new( | 422 | fn new( |
| 452 | _instance1: PhantomData<T>, | 423 | _instance1: PhantomData<T>, |
| 453 | _instance2: &'d crate::pac::can::Fdcan, | 424 | _instance2: &'d crate::pac::can::Fdcan, |
| 454 | _mode: FdcanOperatingMode, | 425 | _mode: OperatingMode, |
| 455 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | 426 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, |
| 456 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, | 427 | rx_buf: &'static RxBuf<RX_BUF_SIZE>, |
| 457 | ) -> Self { | 428 | ) -> Self { |
| @@ -468,10 +439,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 468 | fn setup(self) -> Self { | 439 | fn setup(self) -> Self { |
| 469 | // We don't want interrupts being processed while we change modes. | 440 | // We don't want interrupts being processed while we change modes. |
| 470 | critical_section::with(|_| unsafe { | 441 | critical_section::with(|_| unsafe { |
| 471 | let rx_inner = ClassicBufferedRxInner { | 442 | let rx_inner = self::common::ClassicBufferedRxInner { |
| 472 | rx_sender: self.rx_buf.sender().into(), | 443 | rx_sender: self.rx_buf.sender().into(), |
| 473 | }; | 444 | }; |
| 474 | let tx_inner = ClassicBufferedTxInner { | 445 | let tx_inner = self::common::ClassicBufferedTxInner { |
| 475 | tx_receiver: self.tx_buf.receiver().into(), | 446 | tx_receiver: self.tx_buf.receiver().into(), |
| 476 | }; | 447 | }; |
| 477 | T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner); | 448 | T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner); |
| @@ -481,13 +452,13 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 481 | } | 452 | } |
| 482 | 453 | ||
| 483 | /// Async write frame to TX buffer. | 454 | /// Async write frame to TX buffer. |
| 484 | pub async fn write(&mut self, frame: ClassicFrame) { | 455 | pub async fn write(&mut self, frame: Frame) { |
| 485 | self.tx_buf.send(frame).await; | 456 | self.tx_buf.send(frame).await; |
| 486 | T::IT0Interrupt::pend(); // Wake for Tx | 457 | T::IT0Interrupt::pend(); // Wake for Tx |
| 487 | } | 458 | } |
| 488 | 459 | ||
| 489 | /// Async read frame from RX buffer. | 460 | /// Async read frame from RX buffer. |
| 490 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | 461 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 491 | self.rx_buf.receive().await | 462 | self.rx_buf.receive().await |
| 492 | } | 463 | } |
| 493 | 464 | ||
| @@ -517,8 +488,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr | |||
| 517 | } | 488 | } |
| 518 | 489 | ||
| 519 | /// User supplied buffer for RX Buffering | 490 | /// User supplied buffer for RX Buffering |
| 520 | pub type RxFdBuf<const BUF_SIZE: usize> = | 491 | pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<FdEnvelope, BusError>, BUF_SIZE>; |
| 521 | Channel<CriticalSectionRawMutex, Result<(FdFrame, Timestamp), BusError>, BUF_SIZE>; | ||
| 522 | 492 | ||
| 523 | /// User supplied buffer for TX buffering | 493 | /// User supplied buffer for TX buffering |
| 524 | pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>; | 494 | pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>; |
| @@ -527,7 +497,7 @@ pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFra | |||
| 527 | pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | 497 | pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { |
| 528 | _instance1: PhantomData<T>, | 498 | _instance1: PhantomData<T>, |
| 529 | _instance2: &'d crate::pac::can::Fdcan, | 499 | _instance2: &'d crate::pac::can::Fdcan, |
| 530 | _mode: FdcanOperatingMode, | 500 | _mode: OperatingMode, |
| 531 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, | 501 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, |
| 532 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, | 502 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, |
| 533 | } | 503 | } |
| @@ -535,7 +505,7 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF | |||
| 535 | /// Sender that can be used for sending CAN frames. | 505 | /// Sender that can be used for sending CAN frames. |
| 536 | #[derive(Copy, Clone)] | 506 | #[derive(Copy, Clone)] |
| 537 | pub struct BufferedFdCanSender { | 507 | pub struct BufferedFdCanSender { |
| 538 | tx_buf: embassy_sync::channel::DynamicSender<'static, FdFrame>, | 508 | tx_buf: DynamicSender<'static, FdFrame>, |
| 539 | waker: fn(), | 509 | waker: fn(), |
| 540 | } | 510 | } |
| 541 | 511 | ||
| @@ -560,8 +530,7 @@ impl BufferedFdCanSender { | |||
| 560 | } | 530 | } |
| 561 | 531 | ||
| 562 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | 532 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. |
| 563 | pub type BufferedFdCanReceiver = | 533 | pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>; |
| 564 | embassy_sync::channel::DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>; | ||
| 565 | 534 | ||
| 566 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | 535 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> |
| 567 | BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> | 536 | BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> |
| @@ -569,7 +538,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 569 | fn new( | 538 | fn new( |
| 570 | _instance1: PhantomData<T>, | 539 | _instance1: PhantomData<T>, |
| 571 | _instance2: &'d crate::pac::can::Fdcan, | 540 | _instance2: &'d crate::pac::can::Fdcan, |
| 572 | _mode: FdcanOperatingMode, | 541 | _mode: OperatingMode, |
| 573 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, | 542 | tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, |
| 574 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, | 543 | rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, |
| 575 | ) -> Self { | 544 | ) -> Self { |
| @@ -586,10 +555,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 586 | fn setup(self) -> Self { | 555 | fn setup(self) -> Self { |
| 587 | // We don't want interrupts being processed while we change modes. | 556 | // We don't want interrupts being processed while we change modes. |
| 588 | critical_section::with(|_| unsafe { | 557 | critical_section::with(|_| unsafe { |
| 589 | let rx_inner = FdBufferedRxInner { | 558 | let rx_inner = self::common::FdBufferedRxInner { |
| 590 | rx_sender: self.rx_buf.sender().into(), | 559 | rx_sender: self.rx_buf.sender().into(), |
| 591 | }; | 560 | }; |
| 592 | let tx_inner = FdBufferedTxInner { | 561 | let tx_inner = self::common::FdBufferedTxInner { |
| 593 | tx_receiver: self.tx_buf.receiver().into(), | 562 | tx_receiver: self.tx_buf.receiver().into(), |
| 594 | }; | 563 | }; |
| 595 | T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner); | 564 | T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner); |
| @@ -605,7 +574,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | |||
| 605 | } | 574 | } |
| 606 | 575 | ||
| 607 | /// Async read frame from RX buffer. | 576 | /// Async read frame from RX buffer. |
| 608 | pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | 577 | pub async fn read(&mut self) -> Result<FdEnvelope, BusError> { |
| 609 | self.rx_buf.receive().await | 578 | self.rx_buf.receive().await |
| 610 | } | 579 | } |
| 611 | 580 | ||
| @@ -635,25 +604,25 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr | |||
| 635 | } | 604 | } |
| 636 | 605 | ||
| 637 | /// FDCAN Rx only Instance | 606 | /// FDCAN Rx only Instance |
| 638 | pub struct FdcanRx<'d, T: Instance> { | 607 | pub struct CanRx<'d, T: Instance> { |
| 639 | _instance1: PhantomData<T>, | 608 | _instance1: PhantomData<T>, |
| 640 | _instance2: &'d crate::pac::can::Fdcan, | 609 | _instance2: &'d crate::pac::can::Fdcan, |
| 641 | _mode: FdcanOperatingMode, | 610 | _mode: OperatingMode, |
| 642 | } | 611 | } |
| 643 | 612 | ||
| 644 | /// FDCAN Tx only Instance | 613 | /// FDCAN Tx only Instance |
| 645 | pub struct FdcanTx<'d, T: Instance> { | 614 | pub struct CanTx<'d, T: Instance> { |
| 646 | config: crate::can::fd::config::FdCanConfig, | 615 | config: crate::can::fd::config::FdCanConfig, |
| 647 | _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); | 616 | _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>); |
| 648 | _mode: FdcanOperatingMode, | 617 | _mode: OperatingMode, |
| 649 | } | 618 | } |
| 650 | 619 | ||
| 651 | impl<'c, 'd, T: Instance> FdcanTx<'d, T> { | 620 | impl<'c, 'd, T: Instance> CanTx<'d, T> { |
| 652 | /// Queues the message to be sent but exerts backpressure. If a lower-priority | 621 | /// Queues the message to be sent but exerts backpressure. If a lower-priority |
| 653 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | 622 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames |
| 654 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 623 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 655 | /// transmitted, then tries again. | 624 | /// transmitted, then tries again. |
| 656 | pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> { | 625 | pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { |
| 657 | T::state().tx_mode.write::<T>(frame).await | 626 | T::state().tx_mode.write::<T>(frame).await |
| 658 | } | 627 | } |
| 659 | 628 | ||
| @@ -666,36 +635,22 @@ impl<'c, 'd, T: Instance> FdcanTx<'d, T> { | |||
| 666 | } | 635 | } |
| 667 | } | 636 | } |
| 668 | 637 | ||
| 669 | impl<'c, 'd, T: Instance> FdcanRx<'d, T> { | 638 | impl<'c, 'd, T: Instance> CanRx<'d, T> { |
| 670 | /// Returns the next received message frame | 639 | /// Returns the next received message frame |
| 671 | pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> { | 640 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 672 | T::state().rx_mode.read_classic::<T>().await | 641 | T::state().rx_mode.read_classic::<T>().await |
| 673 | } | 642 | } |
| 674 | 643 | ||
| 675 | /// Returns the next received message frame | 644 | /// Returns the next received message frame |
| 676 | pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> { | 645 | pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> { |
| 677 | T::state().rx_mode.read_fd::<T>().await | 646 | T::state().rx_mode.read_fd::<T>().await |
| 678 | } | 647 | } |
| 679 | } | 648 | } |
| 680 | 649 | ||
| 681 | struct ClassicBufferedRxInner { | ||
| 682 | rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>, | ||
| 683 | } | ||
| 684 | struct ClassicBufferedTxInner { | ||
| 685 | tx_receiver: DynamicReceiver<'static, ClassicFrame>, | ||
| 686 | } | ||
| 687 | |||
| 688 | struct FdBufferedRxInner { | ||
| 689 | rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>, | ||
| 690 | } | ||
| 691 | struct FdBufferedTxInner { | ||
| 692 | tx_receiver: DynamicReceiver<'static, FdFrame>, | ||
| 693 | } | ||
| 694 | |||
| 695 | enum RxMode { | 650 | enum RxMode { |
| 696 | NonBuffered(AtomicWaker), | 651 | NonBuffered(AtomicWaker), |
| 697 | ClassicBuffered(ClassicBufferedRxInner), | 652 | ClassicBuffered(self::common::ClassicBufferedRxInner), |
| 698 | FdBuffered(FdBufferedRxInner), | 653 | FdBuffered(self::common::FdBufferedRxInner), |
| 699 | } | 654 | } |
| 700 | 655 | ||
| 701 | impl RxMode { | 656 | impl RxMode { |
| @@ -715,18 +670,50 @@ impl RxMode { | |||
| 715 | waker.wake(); | 670 | waker.wake(); |
| 716 | } | 671 | } |
| 717 | RxMode::ClassicBuffered(buf) => { | 672 | RxMode::ClassicBuffered(buf) => { |
| 718 | if let Some(result) = self.read::<T, _>() { | 673 | if let Some(result) = self.try_read::<T>() { |
| 719 | let _ = buf.rx_sender.try_send(result); | 674 | let _ = buf.rx_sender.try_send(result); |
| 720 | } | 675 | } |
| 721 | } | 676 | } |
| 722 | RxMode::FdBuffered(buf) => { | 677 | RxMode::FdBuffered(buf) => { |
| 723 | if let Some(result) = self.read::<T, _>() { | 678 | if let Some(result) = self.try_read_fd::<T>() { |
| 724 | let _ = buf.rx_sender.try_send(result); | 679 | let _ = buf.rx_sender.try_send(result); |
| 725 | } | 680 | } |
| 726 | } | 681 | } |
| 727 | } | 682 | } |
| 728 | } | 683 | } |
| 729 | 684 | ||
| 685 | //async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> { | ||
| 686 | fn try_read<T: Instance>(&self) -> Option<Result<Envelope, BusError>> { | ||
| 687 | if let Some((frame, ts)) = T::registers().read(0) { | ||
| 688 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 689 | Some(Ok(Envelope { ts, frame })) | ||
| 690 | } else if let Some((frame, ts)) = T::registers().read(1) { | ||
| 691 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 692 | Some(Ok(Envelope { ts, frame })) | ||
| 693 | } else if let Some(err) = T::registers().curr_error() { | ||
| 694 | // TODO: this is probably wrong | ||
| 695 | Some(Err(err)) | ||
| 696 | } else { | ||
| 697 | None | ||
| 698 | } | ||
| 699 | } | ||
| 700 | |||
| 701 | //async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> { | ||
| 702 | fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> { | ||
| 703 | if let Some((frame, ts)) = T::registers().read(0) { | ||
| 704 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 705 | Some(Ok(FdEnvelope { ts, frame })) | ||
| 706 | } else if let Some((frame, ts)) = T::registers().read(1) { | ||
| 707 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | ||
| 708 | Some(Ok(FdEnvelope { ts, frame })) | ||
| 709 | } else if let Some(err) = T::registers().curr_error() { | ||
| 710 | // TODO: this is probably wrong | ||
| 711 | Some(Err(err)) | ||
| 712 | } else { | ||
| 713 | None | ||
| 714 | } | ||
| 715 | } | ||
| 716 | |||
| 730 | fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> { | 717 | fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> { |
| 731 | if let Some((msg, ts)) = T::registers().read(0) { | 718 | if let Some((msg, ts)) = T::registers().read(0) { |
| 732 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); | 719 | let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); |
| @@ -754,19 +741,25 @@ impl RxMode { | |||
| 754 | .await | 741 | .await |
| 755 | } | 742 | } |
| 756 | 743 | ||
| 757 | async fn read_classic<T: Instance>(&self) -> Result<(ClassicFrame, Timestamp), BusError> { | 744 | async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> { |
| 758 | self.read_async::<T, _>().await | 745 | match self.read_async::<T, _>().await { |
| 746 | Ok((frame, ts)) => Ok(Envelope { ts, frame }), | ||
| 747 | Err(e) => Err(e), | ||
| 748 | } | ||
| 759 | } | 749 | } |
| 760 | 750 | ||
| 761 | async fn read_fd<T: Instance>(&self) -> Result<(FdFrame, Timestamp), BusError> { | 751 | async fn read_fd<T: Instance>(&self) -> Result<FdEnvelope, BusError> { |
| 762 | self.read_async::<T, _>().await | 752 | match self.read_async::<T, _>().await { |
| 753 | Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }), | ||
| 754 | Err(e) => Err(e), | ||
| 755 | } | ||
| 763 | } | 756 | } |
| 764 | } | 757 | } |
| 765 | 758 | ||
| 766 | enum TxMode { | 759 | enum TxMode { |
| 767 | NonBuffered(AtomicWaker), | 760 | NonBuffered(AtomicWaker), |
| 768 | ClassicBuffered(ClassicBufferedTxInner), | 761 | ClassicBuffered(self::common::ClassicBufferedTxInner), |
| 769 | FdBuffered(FdBufferedTxInner), | 762 | FdBuffered(self::common::FdBufferedTxInner), |
| 770 | } | 763 | } |
| 771 | 764 | ||
| 772 | impl TxMode { | 765 | impl TxMode { |
| @@ -804,7 +797,7 @@ impl TxMode { | |||
| 804 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames | 797 | /// frame is dropped from the mailbox, it is returned. If no lower-priority frames |
| 805 | /// can be replaced, this call asynchronously waits for a frame to be successfully | 798 | /// can be replaced, this call asynchronously waits for a frame to be successfully |
| 806 | /// transmitted, then tries again. | 799 | /// transmitted, then tries again. |
| 807 | async fn write<T: Instance>(&self, frame: &ClassicFrame) -> Option<ClassicFrame> { | 800 | async fn write<T: Instance>(&self, frame: &Frame) -> Option<Frame> { |
| 808 | self.write_generic::<T, _>(frame).await | 801 | self.write_generic::<T, _>(frame).await |
| 809 | } | 802 | } |
| 810 | 803 | ||
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index 14fc32c51..d2d1f7aa6 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs | |||
| @@ -3,6 +3,14 @@ use bit_field::BitField; | |||
| 3 | 3 | ||
| 4 | use crate::can::enums::FrameCreateError; | 4 | use crate::can::enums::FrameCreateError; |
| 5 | 5 | ||
| 6 | /// Calculate proper timestamp when available. | ||
| 7 | #[cfg(feature = "time")] | ||
| 8 | pub type Timestamp = embassy_time::Instant; | ||
| 9 | |||
| 10 | /// Raw register timestamp | ||
| 11 | #[cfg(not(feature = "time"))] | ||
| 12 | pub type Timestamp = u16; | ||
| 13 | |||
| 6 | /// CAN Header, without meta data | 14 | /// CAN Header, without meta data |
| 7 | #[derive(Debug, Copy, Clone)] | 15 | #[derive(Debug, Copy, Clone)] |
| 8 | pub struct Header { | 16 | pub struct Header { |
| @@ -136,19 +144,20 @@ impl ClassicData { | |||
| 136 | } | 144 | } |
| 137 | } | 145 | } |
| 138 | 146 | ||
| 139 | /// Frame with up to 8 bytes of data payload as per Classic CAN | 147 | /// Frame with up to 8 bytes of data payload as per Classic(non-FD) CAN |
| 148 | /// For CAN-FD support use FdFrame | ||
| 140 | #[derive(Debug, Copy, Clone)] | 149 | #[derive(Debug, Copy, Clone)] |
| 141 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 150 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 142 | pub struct ClassicFrame { | 151 | pub struct Frame { |
| 143 | can_header: Header, | 152 | can_header: Header, |
| 144 | data: ClassicData, | 153 | data: ClassicData, |
| 145 | } | 154 | } |
| 146 | 155 | ||
| 147 | impl ClassicFrame { | 156 | impl Frame { |
| 148 | /// Create a new CAN classic Frame | 157 | /// Create a new CAN classic Frame |
| 149 | pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> { | 158 | pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> { |
| 150 | let data = ClassicData::new(raw_data)?; | 159 | let data = ClassicData::new(raw_data)?; |
| 151 | Ok(ClassicFrame { can_header, data: data }) | 160 | Ok(Frame { can_header, data: data }) |
| 152 | } | 161 | } |
| 153 | 162 | ||
| 154 | /// Creates a new data frame. | 163 | /// Creates a new data frame. |
| @@ -206,9 +215,9 @@ impl ClassicFrame { | |||
| 206 | } | 215 | } |
| 207 | } | 216 | } |
| 208 | 217 | ||
| 209 | impl embedded_can::Frame for ClassicFrame { | 218 | impl embedded_can::Frame for Frame { |
| 210 | fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { | 219 | fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { |
| 211 | let frameopt = ClassicFrame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data); | 220 | let frameopt = Frame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data); |
| 212 | match frameopt { | 221 | match frameopt { |
| 213 | Ok(frame) => Some(frame), | 222 | Ok(frame) => Some(frame), |
| 214 | Err(_) => None, | 223 | Err(_) => None, |
| @@ -216,7 +225,7 @@ impl embedded_can::Frame for ClassicFrame { | |||
| 216 | } | 225 | } |
| 217 | fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { | 226 | fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { |
| 218 | if len <= 8 { | 227 | if len <= 8 { |
| 219 | let frameopt = ClassicFrame::new(Header::new(id.into(), len as u8, true), &[0; 8]); | 228 | let frameopt = Frame::new(Header::new(id.into(), len as u8, true), &[0; 8]); |
| 220 | match frameopt { | 229 | match frameopt { |
| 221 | Ok(frame) => Some(frame), | 230 | Ok(frame) => Some(frame), |
| 222 | Err(_) => None, | 231 | Err(_) => None, |
| @@ -245,7 +254,7 @@ impl embedded_can::Frame for ClassicFrame { | |||
| 245 | } | 254 | } |
| 246 | } | 255 | } |
| 247 | 256 | ||
| 248 | impl CanHeader for ClassicFrame { | 257 | impl CanHeader for Frame { |
| 249 | fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> { | 258 | fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> { |
| 250 | Self::new(header, data) | 259 | Self::new(header, data) |
| 251 | } | 260 | } |
| @@ -255,10 +264,31 @@ impl CanHeader for ClassicFrame { | |||
| 255 | } | 264 | } |
| 256 | } | 265 | } |
| 257 | 266 | ||
| 267 | /// Contains CAN frame and additional metadata. | ||
| 268 | /// | ||
| 269 | /// Timestamp is available if `time` feature is enabled. | ||
| 270 | /// For CAN-FD support use FdEnvelope | ||
| 271 | #[derive(Debug, Clone)] | ||
| 272 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 273 | pub struct Envelope { | ||
| 274 | /// Reception time. | ||
| 275 | pub ts: Timestamp, | ||
| 276 | /// The actual CAN frame. | ||
| 277 | pub frame: Frame, | ||
| 278 | } | ||
| 279 | |||
| 280 | impl Envelope { | ||
| 281 | /// Convert into a tuple | ||
| 282 | pub fn parts(self) -> (Frame, Timestamp) { | ||
| 283 | (self.frame, self.ts) | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 258 | /// Payload of a (FD)CAN data frame. | 287 | /// Payload of a (FD)CAN data frame. |
| 259 | /// | 288 | /// |
| 260 | /// Contains 0 to 64 Bytes of data. | 289 | /// Contains 0 to 64 Bytes of data. |
| 261 | #[derive(Debug, Copy, Clone)] | 290 | #[derive(Debug, Copy, Clone)] |
| 291 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 262 | pub struct FdData { | 292 | pub struct FdData { |
| 263 | pub(crate) bytes: [u8; 64], | 293 | pub(crate) bytes: [u8; 64], |
| 264 | } | 294 | } |
| @@ -308,6 +338,7 @@ impl FdData { | |||
| 308 | 338 | ||
| 309 | /// Frame with up to 8 bytes of data payload as per Fd CAN | 339 | /// Frame with up to 8 bytes of data payload as per Fd CAN |
| 310 | #[derive(Debug, Copy, Clone)] | 340 | #[derive(Debug, Copy, Clone)] |
| 341 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 311 | pub struct FdFrame { | 342 | pub struct FdFrame { |
| 312 | can_header: Header, | 343 | can_header: Header, |
| 313 | data: FdData, | 344 | data: FdData, |
| @@ -410,3 +441,23 @@ impl CanHeader for FdFrame { | |||
| 410 | self.header() | 441 | self.header() |
| 411 | } | 442 | } |
| 412 | } | 443 | } |
| 444 | |||
| 445 | /// Contains CAN FD frame and additional metadata. | ||
| 446 | /// | ||
| 447 | /// Timestamp is available if `time` feature is enabled. | ||
| 448 | #[derive(Debug, Clone)] | ||
| 449 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 450 | pub struct FdEnvelope { | ||
| 451 | /// Reception time. | ||
| 452 | pub ts: Timestamp, | ||
| 453 | |||
| 454 | /// The actual CAN frame. | ||
| 455 | pub frame: FdFrame, | ||
| 456 | } | ||
| 457 | |||
| 458 | impl FdEnvelope { | ||
| 459 | /// Convert into a tuple | ||
| 460 | pub fn parts(self) -> (FdFrame, Timestamp) { | ||
| 461 | (self.frame, self.ts) | ||
| 462 | } | ||
| 463 | } | ||
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index df5d32f70..4f282f326 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml | |||
| @@ -23,6 +23,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } | |||
| 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 24 | heapless = { version = "0.8", default-features = false } | 24 | heapless = { version = "0.8", default-features = false } |
| 25 | nb = "1.0.0" | 25 | nb = "1.0.0" |
| 26 | static_cell = "2.0.0" | ||
| 26 | 27 | ||
| 27 | [profile.dev] | 28 | [profile.dev] |
| 28 | opt-level = "s" | 29 | opt-level = "s" |
diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index ac337e8a0..90cb9e46b 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs | |||
| @@ -4,11 +4,12 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::can::{ | 6 | use embassy_stm32::can::{ |
| 7 | filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, | 7 | filter, Can, Envelope, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, |
| 8 | TxInterruptHandler, | 8 | TxInterruptHandler, |
| 9 | }; | 9 | }; |
| 10 | use embassy_stm32::peripherals::CAN; | 10 | use embassy_stm32::peripherals::CAN; |
| 11 | use embassy_stm32::{bind_interrupts, Config}; | 11 | use embassy_stm32::{bind_interrupts, Config}; |
| 12 | use static_cell::StaticCell; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 14 | ||
| 14 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| @@ -21,6 +22,27 @@ bind_interrupts!(struct Irqs { | |||
| 21 | // This example is configured to work with real CAN transceivers on B8/B9. | 22 | // This example is configured to work with real CAN transceivers on B8/B9. |
| 22 | // See other examples for loopback. | 23 | // See other examples for loopback. |
| 23 | 24 | ||
| 25 | fn handle_frame(env: Envelope, read_mode: &str) { | ||
| 26 | match env.frame.id() { | ||
| 27 | Id::Extended(id) => { | ||
| 28 | defmt::println!( | ||
| 29 | "{} Extended Frame id={:x} {:02x}", | ||
| 30 | read_mode, | ||
| 31 | id.as_raw(), | ||
| 32 | env.frame.data() | ||
| 33 | ); | ||
| 34 | } | ||
| 35 | Id::Standard(id) => { | ||
| 36 | defmt::println!( | ||
| 37 | "{} Standard Frame id={:x} {:02x}", | ||
| 38 | read_mode, | ||
| 39 | id.as_raw(), | ||
| 40 | env.frame.data() | ||
| 41 | ); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 24 | #[embassy_executor::main] | 46 | #[embassy_executor::main] |
| 25 | async fn main(_spawner: Spawner) { | 47 | async fn main(_spawner: Spawner) { |
| 26 | let p = embassy_stm32::init(Config::default()); | 48 | let p = embassy_stm32::init(Config::default()); |
| @@ -28,6 +50,9 @@ async fn main(_spawner: Spawner) { | |||
| 28 | // Set alternate pin mapping to B8/B9 | 50 | // Set alternate pin mapping to B8/B9 |
| 29 | embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2)); | 51 | embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2)); |
| 30 | 52 | ||
| 53 | static RX_BUF: StaticCell<embassy_stm32::can::RxBuf<10>> = StaticCell::new(); | ||
| 54 | static TX_BUF: StaticCell<embassy_stm32::can::TxBuf<10>> = StaticCell::new(); | ||
| 55 | |||
| 31 | let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); | 56 | let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs); |
| 32 | 57 | ||
| 33 | can.as_mut() | 58 | can.as_mut() |
| @@ -43,21 +68,72 @@ async fn main(_spawner: Spawner) { | |||
| 43 | can.set_bitrate(250_000); | 68 | can.set_bitrate(250_000); |
| 44 | 69 | ||
| 45 | can.enable().await; | 70 | can.enable().await; |
| 46 | |||
| 47 | let mut i: u8 = 0; | 71 | let mut i: u8 = 0; |
| 72 | |||
| 73 | /* | ||
| 74 | // Example for using buffered Tx and Rx without needing to | ||
| 75 | // split first as is done below. | ||
| 76 | let mut can = can.buffered( | ||
| 77 | TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()), | ||
| 78 | RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new())); | ||
| 79 | loop { | ||
| 80 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | ||
| 81 | can.write(&tx_frame).await; | ||
| 82 | |||
| 83 | match can.read().await { | ||
| 84 | Ok((frame, ts)) => { | ||
| 85 | handle_frame(Envelope { ts, frame }, "Buf"); | ||
| 86 | } | ||
| 87 | Err(err) => { | ||
| 88 | defmt::println!("Error {}", err); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | i += 1; | ||
| 92 | } | ||
| 93 | |||
| 94 | */ | ||
| 95 | let (mut tx, mut rx) = can.split(); | ||
| 96 | |||
| 97 | // This example shows using the wait_not_empty API before try read | ||
| 98 | while i < 3 { | ||
| 99 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | ||
| 100 | tx.write(&tx_frame).await; | ||
| 101 | |||
| 102 | rx.wait_not_empty().await; | ||
| 103 | let env = rx.try_read().unwrap(); | ||
| 104 | handle_frame(env, "Wait"); | ||
| 105 | i += 1; | ||
| 106 | } | ||
| 107 | |||
| 108 | // This example shows using the full async non-buffered API | ||
| 109 | while i < 6 { | ||
| 110 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | ||
| 111 | tx.write(&tx_frame).await; | ||
| 112 | |||
| 113 | match rx.read().await { | ||
| 114 | Ok(env) => { | ||
| 115 | handle_frame(env, "NoBuf"); | ||
| 116 | } | ||
| 117 | Err(err) => { | ||
| 118 | defmt::println!("Error {}", err); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | i += 1; | ||
| 122 | } | ||
| 123 | |||
| 124 | // This example shows using buffered RX and TX. User passes in desired buffer (size) | ||
| 125 | // It's possible this way to have just RX or TX buffered. | ||
| 126 | let mut rx = rx.buffered(RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new())); | ||
| 127 | let mut tx = tx.buffered(TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new())); | ||
| 128 | |||
| 48 | loop { | 129 | loop { |
| 49 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); | 130 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap(); |
| 50 | can.write(&tx_frame).await; | 131 | tx.write(&tx_frame).await; |
| 51 | 132 | ||
| 52 | match can.read().await { | 133 | match rx.read().await { |
| 53 | Ok(env) => match env.frame.id() { | 134 | Ok(envelope) => { |
| 54 | Id::Extended(id) => { | 135 | handle_frame(envelope, "Buf"); |
| 55 | defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data()); | 136 | } |
| 56 | } | ||
| 57 | Id::Standard(id) => { | ||
| 58 | defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data()); | ||
| 59 | } | ||
| 60 | }, | ||
| 61 | Err(err) => { | 137 | Err(err) => { |
| 62 | defmt::println!("Error {}", err); | 138 | defmt::println!("Error {}", err); |
| 63 | } | 139 | } |
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 4373a89a8..2ed632a93 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs | |||
| @@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) { | |||
| 36 | } | 36 | } |
| 37 | let peripherals = embassy_stm32::init(config); | 37 | let peripherals = embassy_stm32::init(config); |
| 38 | 38 | ||
| 39 | let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | 39 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |
| 40 | 40 | ||
| 41 | can.set_extended_filter( | 41 | can.set_extended_filter( |
| 42 | can::filter::ExtendedFilterSlot::_0, | 42 | can::filter::ExtendedFilterSlot::_0, |
| @@ -56,21 +56,22 @@ async fn main(_spawner: Spawner) { | |||
| 56 | info!("Configured"); | 56 | info!("Configured"); |
| 57 | 57 | ||
| 58 | let mut can = can.start(match use_fd { | 58 | let mut can = can.start(match use_fd { |
| 59 | true => can::FdcanOperatingMode::InternalLoopbackMode, | 59 | true => can::OperatingMode::InternalLoopbackMode, |
| 60 | false => can::FdcanOperatingMode::NormalOperationMode, | 60 | false => can::OperatingMode::NormalOperationMode, |
| 61 | }); | 61 | }); |
| 62 | 62 | ||
| 63 | let mut i = 0; | 63 | let mut i = 0; |
| 64 | let mut last_read_ts = embassy_time::Instant::now(); | 64 | let mut last_read_ts = embassy_time::Instant::now(); |
| 65 | 65 | ||
| 66 | loop { | 66 | loop { |
| 67 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 67 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 68 | info!("Writing frame"); | 68 | info!("Writing frame"); |
| 69 | 69 | ||
| 70 | _ = can.write(&frame).await; | 70 | _ = can.write(&frame).await; |
| 71 | 71 | ||
| 72 | match can.read().await { | 72 | match can.read().await { |
| 73 | Ok((rx_frame, ts)) => { | 73 | Ok(envelope) => { |
| 74 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 74 | let delta = (ts - last_read_ts).as_millis(); | 75 | let delta = (ts - last_read_ts).as_millis(); |
| 75 | last_read_ts = ts; | 76 | last_read_ts = ts; |
| 76 | info!( | 77 | info!( |
| @@ -105,7 +106,8 @@ async fn main(_spawner: Spawner) { | |||
| 105 | } | 106 | } |
| 106 | 107 | ||
| 107 | match can.read_fd().await { | 108 | match can.read_fd().await { |
| 108 | Ok((rx_frame, ts)) => { | 109 | Ok(envelope) => { |
| 110 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 109 | let delta = (ts - last_read_ts).as_millis(); | 111 | let delta = (ts - last_read_ts).as_millis(); |
| 110 | last_read_ts = ts; | 112 | last_read_ts = ts; |
| 111 | info!( | 113 | info!( |
| @@ -129,12 +131,13 @@ async fn main(_spawner: Spawner) { | |||
| 129 | let (mut tx, mut rx) = can.split(); | 131 | let (mut tx, mut rx) = can.split(); |
| 130 | // With split | 132 | // With split |
| 131 | loop { | 133 | loop { |
| 132 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 134 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 133 | info!("Writing frame"); | 135 | info!("Writing frame"); |
| 134 | _ = tx.write(&frame).await; | 136 | _ = tx.write(&frame).await; |
| 135 | 137 | ||
| 136 | match rx.read().await { | 138 | match rx.read().await { |
| 137 | Ok((rx_frame, ts)) => { | 139 | Ok(envelope) => { |
| 140 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 138 | let delta = (ts - last_read_ts).as_millis(); | 141 | let delta = (ts - last_read_ts).as_millis(); |
| 139 | last_read_ts = ts; | 142 | last_read_ts = ts; |
| 140 | info!( | 143 | info!( |
| @@ -156,7 +159,7 @@ async fn main(_spawner: Spawner) { | |||
| 156 | } | 159 | } |
| 157 | } | 160 | } |
| 158 | 161 | ||
| 159 | let can = can::Fdcan::join(tx, rx); | 162 | let can = can::Can::join(tx, rx); |
| 160 | 163 | ||
| 161 | info!("\n\n\nBuffered\n"); | 164 | info!("\n\n\nBuffered\n"); |
| 162 | if use_fd { | 165 | if use_fd { |
| @@ -173,7 +176,8 @@ async fn main(_spawner: Spawner) { | |||
| 173 | _ = can.write(frame).await; | 176 | _ = can.write(frame).await; |
| 174 | 177 | ||
| 175 | match can.read().await { | 178 | match can.read().await { |
| 176 | Ok((rx_frame, ts)) => { | 179 | Ok(envelope) => { |
| 180 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 177 | let delta = (ts - last_read_ts).as_millis(); | 181 | let delta = (ts - last_read_ts).as_millis(); |
| 178 | last_read_ts = ts; | 182 | last_read_ts = ts; |
| 179 | info!( | 183 | info!( |
| @@ -198,7 +202,7 @@ async fn main(_spawner: Spawner) { | |||
| 198 | RX_BUF.init(can::RxBuf::<10>::new()), | 202 | RX_BUF.init(can::RxBuf::<10>::new()), |
| 199 | ); | 203 | ); |
| 200 | loop { | 204 | loop { |
| 201 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 205 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 202 | info!("Writing frame"); | 206 | info!("Writing frame"); |
| 203 | 207 | ||
| 204 | // You can use any of these approaches to send. The writer makes it | 208 | // You can use any of these approaches to send. The writer makes it |
| @@ -208,7 +212,8 @@ async fn main(_spawner: Spawner) { | |||
| 208 | can.writer().write(frame).await; | 212 | can.writer().write(frame).await; |
| 209 | 213 | ||
| 210 | match can.read().await { | 214 | match can.read().await { |
| 211 | Ok((rx_frame, ts)) => { | 215 | Ok(envelope) => { |
| 216 | let (ts, rx_frame) = (envelope.ts, envelope.frame); | ||
| 212 | let delta = (ts - last_read_ts).as_millis(); | 217 | let delta = (ts - last_read_ts).as_millis(); |
| 213 | last_read_ts = ts; | 218 | last_read_ts = ts; |
| 214 | info!( | 219 | info!( |
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index 643df27f9..dd625c90a 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs | |||
| @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { | |||
| 24 | 24 | ||
| 25 | let peripherals = embassy_stm32::init(config); | 25 | let peripherals = embassy_stm32::init(config); |
| 26 | 26 | ||
| 27 | let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | 27 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |
| 28 | 28 | ||
| 29 | // 250k bps | 29 | // 250k bps |
| 30 | can.set_bitrate(250_000); | 30 | can.set_bitrate(250_000); |
| @@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) { | |||
| 38 | let mut last_read_ts = embassy_time::Instant::now(); | 38 | let mut last_read_ts = embassy_time::Instant::now(); |
| 39 | 39 | ||
| 40 | loop { | 40 | loop { |
| 41 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 41 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 42 | info!("Writing frame"); | 42 | info!("Writing frame"); |
| 43 | _ = can.write(&frame).await; | 43 | _ = can.write(&frame).await; |
| 44 | 44 | ||
| 45 | match can.read().await { | 45 | match can.read().await { |
| 46 | Ok((rx_frame, ts)) => { | 46 | Ok(envelope) => { |
| 47 | let (rx_frame, ts) = envelope.parts(); | ||
| 47 | let delta = (ts - last_read_ts).as_millis(); | 48 | let delta = (ts - last_read_ts).as_millis(); |
| 48 | last_read_ts = ts; | 49 | last_read_ts = ts; |
| 49 | info!( | 50 | info!( |
| @@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) { | |||
| 69 | let (mut tx, mut rx) = can.split(); | 70 | let (mut tx, mut rx) = can.split(); |
| 70 | // With split | 71 | // With split |
| 71 | loop { | 72 | loop { |
| 72 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 73 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 73 | info!("Writing frame"); | 74 | info!("Writing frame"); |
| 74 | _ = tx.write(&frame).await; | 75 | _ = tx.write(&frame).await; |
| 75 | 76 | ||
| 76 | match rx.read().await { | 77 | match rx.read().await { |
| 77 | Ok((rx_frame, ts)) => { | 78 | Ok(envelope) => { |
| 79 | let (rx_frame, ts) = envelope.parts(); | ||
| 78 | let delta = (ts - last_read_ts).as_millis(); | 80 | let delta = (ts - last_read_ts).as_millis(); |
| 79 | last_read_ts = ts; | 81 | last_read_ts = ts; |
| 80 | info!( | 82 | info!( |
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index 13a6a5051..22cb27481 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs | |||
| @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { | |||
| 24 | 24 | ||
| 25 | let peripherals = embassy_stm32::init(config); | 25 | let peripherals = embassy_stm32::init(config); |
| 26 | 26 | ||
| 27 | let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | 27 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); |
| 28 | 28 | ||
| 29 | // 250k bps | 29 | // 250k bps |
| 30 | can.set_bitrate(250_000); | 30 | can.set_bitrate(250_000); |
| @@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) { | |||
| 38 | let mut last_read_ts = embassy_time::Instant::now(); | 38 | let mut last_read_ts = embassy_time::Instant::now(); |
| 39 | 39 | ||
| 40 | loop { | 40 | loop { |
| 41 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 41 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 42 | info!("Writing frame"); | 42 | info!("Writing frame"); |
| 43 | _ = can.write(&frame).await; | 43 | _ = can.write(&frame).await; |
| 44 | 44 | ||
| 45 | match can.read().await { | 45 | match can.read().await { |
| 46 | Ok((rx_frame, ts)) => { | 46 | Ok(envelope) => { |
| 47 | let (rx_frame, ts) = envelope.parts(); | ||
| 47 | let delta = (ts - last_read_ts).as_millis(); | 48 | let delta = (ts - last_read_ts).as_millis(); |
| 48 | last_read_ts = ts; | 49 | last_read_ts = ts; |
| 49 | info!( | 50 | info!( |
| @@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) { | |||
| 69 | let (mut tx, mut rx) = can.split(); | 70 | let (mut tx, mut rx) = can.split(); |
| 70 | // With split | 71 | // With split |
| 71 | loop { | 72 | loop { |
| 72 | let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap(); | 73 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); |
| 73 | info!("Writing frame"); | 74 | info!("Writing frame"); |
| 74 | _ = tx.write(&frame).await; | 75 | _ = tx.write(&frame).await; |
| 75 | 76 | ||
| 76 | match rx.read().await { | 77 | match rx.read().await { |
| 77 | Ok((rx_frame, ts)) => { | 78 | Ok(envelope) => { |
| 79 | let (rx_frame, ts) = envelope.parts(); | ||
| 78 | let delta = (ts - last_read_ts).as_millis(); | 80 | let delta = (ts - last_read_ts).as_millis(); |
| 79 | last_read_ts = ts; | 81 | last_read_ts = ts; |
| 80 | info!( | 82 | info!( |
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index c08c69a3b..74d84c42f 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs | |||
| @@ -6,17 +6,19 @@ | |||
| 6 | #[path = "../common.rs"] | 6 | #[path = "../common.rs"] |
| 7 | mod common; | 7 | mod common; |
| 8 | use common::*; | 8 | use common::*; |
| 9 | use defmt::assert; | ||
| 10 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 11 | use embassy_stm32::bind_interrupts; | 10 | use embassy_stm32::bind_interrupts; |
| 12 | use embassy_stm32::can::bx::filter::Mask32; | 11 | use embassy_stm32::can::bx::filter::Mask32; |
| 13 | use embassy_stm32::can::bx::{Fifo, Frame, StandardId}; | 12 | use embassy_stm32::can::bx::Fifo; |
| 14 | use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; | 13 | use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; |
| 15 | use embassy_stm32::gpio::{Input, Pull}; | 14 | use embassy_stm32::gpio::{Input, Pull}; |
| 16 | use embassy_stm32::peripherals::CAN1; | 15 | use embassy_stm32::peripherals::CAN1; |
| 17 | use embassy_time::{Duration, Instant}; | 16 | use embassy_time::Duration; |
| 18 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {defmt_rtt as _, panic_probe as _}; |
| 19 | 18 | ||
| 19 | mod can_common; | ||
| 20 | use can_common::*; | ||
| 21 | |||
| 20 | bind_interrupts!(struct Irqs { | 22 | bind_interrupts!(struct Irqs { |
| 21 | CAN1_RX0 => Rx0InterruptHandler<CAN1>; | 23 | CAN1_RX0 => Rx0InterruptHandler<CAN1>; |
| 22 | CAN1_RX1 => Rx1InterruptHandler<CAN1>; | 24 | CAN1_RX1 => Rx1InterruptHandler<CAN1>; |
| @@ -29,6 +31,11 @@ async fn main(_spawner: Spawner) { | |||
| 29 | let p = embassy_stm32::init(config()); | 31 | let p = embassy_stm32::init(config()); |
| 30 | info!("Hello World!"); | 32 | info!("Hello World!"); |
| 31 | 33 | ||
| 34 | let options = TestOptions { | ||
| 35 | max_latency: Duration::from_micros(1200), | ||
| 36 | max_buffered: 2, | ||
| 37 | }; | ||
| 38 | |||
| 32 | let can = peri!(p, CAN); | 39 | let can = peri!(p, CAN); |
| 33 | let tx = peri!(p, CAN_TX); | 40 | let tx = peri!(p, CAN_TX); |
| 34 | let mut rx = peri!(p, CAN_RX); | 41 | let mut rx = peri!(p, CAN_RX); |
| @@ -58,40 +65,13 @@ async fn main(_spawner: Spawner) { | |||
| 58 | 65 | ||
| 59 | info!("Can configured"); | 66 | info!("Can configured"); |
| 60 | 67 | ||
| 61 | let mut i: u8 = 0; | 68 | run_can_tests(&mut can, &options).await; |
| 62 | loop { | ||
| 63 | let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap(); | ||
| 64 | |||
| 65 | info!("Transmitting frame..."); | ||
| 66 | let tx_ts = Instant::now(); | ||
| 67 | can.write(&tx_frame).await; | ||
| 68 | |||
| 69 | let envelope = can.read().await.unwrap(); | ||
| 70 | info!("Frame received!"); | ||
| 71 | 69 | ||
| 72 | info!("loopback time {}", envelope.ts); | 70 | // Test again with a split |
| 73 | info!("loopback frame {=u8}", envelope.frame.data()[0]); | 71 | let (mut tx, mut rx) = can.split(); |
| 74 | 72 | run_split_can_tests(&mut tx, &mut rx, &options).await; | |
| 75 | let latency = envelope.ts.saturating_duration_since(tx_ts); | ||
| 76 | info!("loopback latency {} us", latency.as_micros()); | ||
| 77 | |||
| 78 | // Theoretical minimum latency is 55us, actual is usually ~80us | ||
| 79 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 80 | const MAX_LATENCY: Duration = Duration::from_micros(150); | ||
| 81 | assert!( | ||
| 82 | MIN_LATENCY <= latency && latency <= MAX_LATENCY, | ||
| 83 | "{} <= {} <= {}", | ||
| 84 | MIN_LATENCY, | ||
| 85 | latency, | ||
| 86 | MAX_LATENCY | ||
| 87 | ); | ||
| 88 | |||
| 89 | i += 1; | ||
| 90 | if i > 10 { | ||
| 91 | break; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | 73 | ||
| 95 | info!("Test OK"); | 74 | info!("Test OK"); |
| 75 | |||
| 96 | cortex_m::asm::bkpt(); | 76 | cortex_m::asm::bkpt(); |
| 97 | } | 77 | } |
diff --git a/tests/stm32/src/bin/can_common.rs b/tests/stm32/src/bin/can_common.rs new file mode 100644 index 000000000..4b39269cc --- /dev/null +++ b/tests/stm32/src/bin/can_common.rs | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | use defmt::{assert, *}; | ||
| 2 | use embassy_stm32::can; | ||
| 3 | use embassy_time::{Duration, Instant}; | ||
| 4 | |||
| 5 | #[derive(Clone, Copy, Debug)] | ||
| 6 | pub struct TestOptions { | ||
| 7 | pub max_latency: Duration, | ||
| 8 | pub max_buffered: u8, | ||
| 9 | } | ||
| 10 | |||
| 11 | pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) { | ||
| 12 | let mut i: u8 = 0; | ||
| 13 | loop { | ||
| 14 | //let tx_frame = can::frame::Frame::new_standard(0x123, &[i, 0x12 as u8, 0x34 as u8, 0x56 as u8, 0x78 as u8, 0x9A as u8, 0xBC as u8 ]).unwrap(); | ||
| 15 | let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); | ||
| 16 | |||
| 17 | //info!("Transmitting frame..."); | ||
| 18 | let tx_ts = Instant::now(); | ||
| 19 | can.write(&tx_frame).await; | ||
| 20 | |||
| 21 | let (frame, timestamp) = can.read().await.unwrap().parts(); | ||
| 22 | //info!("Frame received!"); | ||
| 23 | |||
| 24 | // Check data. | ||
| 25 | assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); | ||
| 26 | |||
| 27 | //info!("loopback time {}", timestamp); | ||
| 28 | //info!("loopback frame {=u8}", frame.data()[0]); | ||
| 29 | let latency = timestamp.saturating_duration_since(tx_ts); | ||
| 30 | info!("loopback latency {} us", latency.as_micros()); | ||
| 31 | |||
| 32 | // Theoretical minimum latency is 55us, actual is usually ~80us | ||
| 33 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 34 | // Was failing at 150 but we are not getting a real time stamp. I'm not | ||
| 35 | // sure if there are other delays | ||
| 36 | assert!( | ||
| 37 | MIN_LATENCY <= latency && latency <= options.max_latency, | ||
| 38 | "{} <= {} <= {}", | ||
| 39 | MIN_LATENCY, | ||
| 40 | latency, | ||
| 41 | options.max_latency | ||
| 42 | ); | ||
| 43 | |||
| 44 | i += 1; | ||
| 45 | if i > 5 { | ||
| 46 | break; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | // Below here, check that we can receive from both FIFO0 and FIFO1 | ||
| 51 | // Above we configured FIFO1 for extended ID packets. There are only 3 slots | ||
| 52 | // in each FIFO so make sure we write enough to fill them both up before reading. | ||
| 53 | for i in 0..options.max_buffered { | ||
| 54 | // Try filling up the RX FIFO0 buffers | ||
| 55 | //let tx_frame = if 0 != (i & 0x01) { | ||
| 56 | let tx_frame = if i < options.max_buffered / 2 { | ||
| 57 | info!("Transmitting standard frame {}", i); | ||
| 58 | can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap() | ||
| 59 | } else { | ||
| 60 | info!("Transmitting extended frame {}", i); | ||
| 61 | can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap() | ||
| 62 | }; | ||
| 63 | can.write(&tx_frame).await; | ||
| 64 | } | ||
| 65 | |||
| 66 | // Try and receive all 6 packets | ||
| 67 | for _i in 0..options.max_buffered { | ||
| 68 | let (frame, _ts) = can.read().await.unwrap().parts(); | ||
| 69 | match frame.id() { | ||
| 70 | embedded_can::Id::Extended(_id) => { | ||
| 71 | info!("Extended received! {}", frame.data()[0]); | ||
| 72 | //info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 73 | } | ||
| 74 | embedded_can::Id::Standard(_id) => { | ||
| 75 | info!("Standard received! {}", frame.data()[0]); | ||
| 76 | //info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | pub async fn run_split_can_tests<'d, T: can::Instance>( | ||
| 83 | tx: &mut can::CanTx<'d, T>, | ||
| 84 | rx: &mut can::CanRx<'d, T>, | ||
| 85 | options: &TestOptions, | ||
| 86 | ) { | ||
| 87 | for i in 0..options.max_buffered { | ||
| 88 | // Try filling up the RX FIFO0 buffers | ||
| 89 | //let tx_frame = if 0 != (i & 0x01) { | ||
| 90 | let tx_frame = if i < options.max_buffered / 2 { | ||
| 91 | info!("Transmitting standard frame {}", i); | ||
| 92 | can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap() | ||
| 93 | } else { | ||
| 94 | info!("Transmitting extended frame {}", i); | ||
| 95 | can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap() | ||
| 96 | }; | ||
| 97 | tx.write(&tx_frame).await; | ||
| 98 | } | ||
| 99 | |||
| 100 | // Try and receive all 6 packets | ||
| 101 | for _i in 0..options.max_buffered { | ||
| 102 | let (frame, _ts) = rx.read().await.unwrap().parts(); | ||
| 103 | match frame.id() { | ||
| 104 | embedded_can::Id::Extended(_id) => { | ||
| 105 | info!("Extended received! {}", frame.data()[0]); | ||
| 106 | } | ||
| 107 | embedded_can::Id::Standard(_id) => { | ||
| 108 | info!("Standard received! {}", frame.data()[0]); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index c7373e294..27bdd038a 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs | |||
| @@ -6,13 +6,15 @@ | |||
| 6 | #[path = "../common.rs"] | 6 | #[path = "../common.rs"] |
| 7 | mod common; | 7 | mod common; |
| 8 | use common::*; | 8 | use common::*; |
| 9 | use defmt::assert; | ||
| 10 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 11 | use embassy_stm32::peripherals::*; | 10 | use embassy_stm32::peripherals::*; |
| 12 | use embassy_stm32::{bind_interrupts, can, Config}; | 11 | use embassy_stm32::{bind_interrupts, can, Config}; |
| 13 | use embassy_time::{Duration, Instant}; | 12 | use embassy_time::Duration; |
| 14 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 14 | ||
| 15 | mod can_common; | ||
| 16 | use can_common::*; | ||
| 17 | |||
| 16 | bind_interrupts!(struct Irqs2 { | 18 | bind_interrupts!(struct Irqs2 { |
| 17 | FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>; | 19 | FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>; |
| 18 | FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>; | 20 | FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>; |
| @@ -22,14 +24,8 @@ bind_interrupts!(struct Irqs1 { | |||
| 22 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; | 24 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; |
| 23 | }); | 25 | }); |
| 24 | 26 | ||
| 25 | struct TestOptions { | ||
| 26 | config: Config, | ||
| 27 | max_latency: Duration, | ||
| 28 | second_fifo_working: bool, | ||
| 29 | } | ||
| 30 | |||
| 31 | #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] | 27 | #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] |
| 32 | fn options() -> TestOptions { | 28 | fn options() -> (Config, TestOptions) { |
| 33 | use embassy_stm32::rcc; | 29 | use embassy_stm32::rcc; |
| 34 | info!("H75 config"); | 30 | info!("H75 config"); |
| 35 | let mut c = config(); | 31 | let mut c = config(); |
| @@ -38,15 +34,17 @@ fn options() -> TestOptions { | |||
| 38 | mode: rcc::HseMode::Oscillator, | 34 | mode: rcc::HseMode::Oscillator, |
| 39 | }); | 35 | }); |
| 40 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; | 36 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; |
| 41 | TestOptions { | 37 | ( |
| 42 | config: c, | 38 | c, |
| 43 | max_latency: Duration::from_micros(1200), | 39 | TestOptions { |
| 44 | second_fifo_working: false, | 40 | max_latency: Duration::from_micros(1200), |
| 45 | } | 41 | max_buffered: 3, |
| 42 | }, | ||
| 43 | ) | ||
| 46 | } | 44 | } |
| 47 | 45 | ||
| 48 | #[cfg(any(feature = "stm32h7a3zi"))] | 46 | #[cfg(any(feature = "stm32h7a3zi"))] |
| 49 | fn options() -> TestOptions { | 47 | fn options() -> (Config, TestOptions) { |
| 50 | use embassy_stm32::rcc; | 48 | use embassy_stm32::rcc; |
| 51 | info!("H7a config"); | 49 | info!("H7a config"); |
| 52 | let mut c = config(); | 50 | let mut c = config(); |
| @@ -55,32 +53,36 @@ fn options() -> TestOptions { | |||
| 55 | mode: rcc::HseMode::Oscillator, | 53 | mode: rcc::HseMode::Oscillator, |
| 56 | }); | 54 | }); |
| 57 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; | 55 | c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; |
| 58 | TestOptions { | 56 | ( |
| 59 | config: c, | 57 | c, |
| 60 | max_latency: Duration::from_micros(1200), | 58 | TestOptions { |
| 61 | second_fifo_working: false, | 59 | max_latency: Duration::from_micros(1200), |
| 62 | } | 60 | max_buffered: 3, |
| 61 | }, | ||
| 62 | ) | ||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] | 65 | #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] |
| 66 | fn options() -> TestOptions { | 66 | fn options() -> (Config, TestOptions) { |
| 67 | info!("G4 config"); | 67 | info!("G4 config"); |
| 68 | TestOptions { | 68 | ( |
| 69 | config: config(), | 69 | config(), |
| 70 | max_latency: Duration::from_micros(500), | 70 | TestOptions { |
| 71 | second_fifo_working: true, | 71 | max_latency: Duration::from_micros(500), |
| 72 | } | 72 | max_buffered: 6, |
| 73 | }, | ||
| 74 | ) | ||
| 73 | } | 75 | } |
| 74 | 76 | ||
| 75 | #[embassy_executor::main] | 77 | #[embassy_executor::main] |
| 76 | async fn main(_spawner: Spawner) { | 78 | async fn main(_spawner: Spawner) { |
| 77 | //let peripherals = embassy_stm32::init(config()); | 79 | //let peripherals = embassy_stm32::init(config()); |
| 78 | 80 | ||
| 79 | let options = options(); | 81 | let (config, options) = options(); |
| 80 | let peripherals = embassy_stm32::init(options.config); | 82 | let peripherals = embassy_stm32::init(config); |
| 81 | 83 | ||
| 82 | let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); | 84 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); |
| 83 | let mut can2 = can::FdcanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); | 85 | let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); |
| 84 | 86 | ||
| 85 | // 250k bps | 87 | // 250k bps |
| 86 | can.set_bitrate(250_000); | 88 | can.set_bitrate(250_000); |
| @@ -98,141 +100,16 @@ async fn main(_spawner: Spawner) { | |||
| 98 | let mut can = can.into_internal_loopback_mode(); | 100 | let mut can = can.into_internal_loopback_mode(); |
| 99 | let mut can2 = can2.into_internal_loopback_mode(); | 101 | let mut can2 = can2.into_internal_loopback_mode(); |
| 100 | 102 | ||
| 101 | info!("CAN Configured"); | 103 | run_can_tests(&mut can, &options).await; |
| 104 | run_can_tests(&mut can2, &options).await; | ||
| 102 | 105 | ||
| 103 | let mut i: u8 = 0; | 106 | info!("CAN Configured"); |
| 104 | loop { | ||
| 105 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||
| 106 | |||
| 107 | info!("Transmitting frame..."); | ||
| 108 | let tx_ts = Instant::now(); | ||
| 109 | can.write(&tx_frame).await; | ||
| 110 | |||
| 111 | let (frame, timestamp) = can.read().await.unwrap(); | ||
| 112 | info!("Frame received!"); | ||
| 113 | |||
| 114 | // Check data. | ||
| 115 | assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); | ||
| 116 | |||
| 117 | info!("loopback time {}", timestamp); | ||
| 118 | info!("loopback frame {=u8}", frame.data()[0]); | ||
| 119 | let latency = timestamp.saturating_duration_since(tx_ts); | ||
| 120 | info!("loopback latency {} us", latency.as_micros()); | ||
| 121 | |||
| 122 | // Theoretical minimum latency is 55us, actual is usually ~80us | ||
| 123 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 124 | // Was failing at 150 but we are not getting a real time stamp. I'm not | ||
| 125 | // sure if there are other delays | ||
| 126 | assert!( | ||
| 127 | MIN_LATENCY <= latency && latency <= options.max_latency, | ||
| 128 | "{} <= {} <= {}", | ||
| 129 | MIN_LATENCY, | ||
| 130 | latency, | ||
| 131 | options.max_latency | ||
| 132 | ); | ||
| 133 | |||
| 134 | i += 1; | ||
| 135 | if i > 10 { | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | let mut i: u8 = 0; | ||
| 141 | loop { | ||
| 142 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||
| 143 | |||
| 144 | info!("Transmitting frame..."); | ||
| 145 | let tx_ts = Instant::now(); | ||
| 146 | can2.write(&tx_frame).await; | ||
| 147 | |||
| 148 | let (frame, timestamp) = can2.read().await.unwrap(); | ||
| 149 | info!("Frame received!"); | ||
| 150 | |||
| 151 | //print_regs().await; | ||
| 152 | // Check data. | ||
| 153 | assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]); | ||
| 154 | |||
| 155 | info!("loopback time {}", timestamp); | ||
| 156 | info!("loopback frame {=u8}", frame.data()[0]); | ||
| 157 | let latency = timestamp.saturating_duration_since(tx_ts); | ||
| 158 | info!("loopback latency {} us", latency.as_micros()); | ||
| 159 | |||
| 160 | // Theoretical minimum latency is 55us, actual is usually ~80us | ||
| 161 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 162 | // Was failing at 150 but we are not getting a real time stamp. I'm not | ||
| 163 | // sure if there are other delays | ||
| 164 | assert!( | ||
| 165 | MIN_LATENCY <= latency && latency <= options.max_latency, | ||
| 166 | "{} <= {} <= {}", | ||
| 167 | MIN_LATENCY, | ||
| 168 | latency, | ||
| 169 | options.max_latency | ||
| 170 | ); | ||
| 171 | |||
| 172 | i += 1; | ||
| 173 | if i > 10 { | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | let max_buffered = if options.second_fifo_working { 6 } else { 3 }; | ||
| 179 | |||
| 180 | // Below here, check that we can receive from both FIFO0 and FIFO0 | ||
| 181 | // Above we configured FIFO1 for extended ID packets. There are only 3 slots | ||
| 182 | // in each FIFO so make sure we write enough to fill them both up before reading. | ||
| 183 | for i in 0..3 { | ||
| 184 | // Try filling up the RX FIFO0 buffers with standard packets | ||
| 185 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | ||
| 186 | info!("Transmitting frame {}", i); | ||
| 187 | can.write(&tx_frame).await; | ||
| 188 | } | ||
| 189 | for i in 3..max_buffered { | ||
| 190 | // Try filling up the RX FIFO0 buffers with extended packets | ||
| 191 | let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); | ||
| 192 | info!("Transmitting frame {}", i); | ||
| 193 | can.write(&tx_frame).await; | ||
| 194 | } | ||
| 195 | |||
| 196 | // Try and receive all 6 packets | ||
| 197 | for i in 0..max_buffered { | ||
| 198 | let (frame, _ts) = can.read().await.unwrap(); | ||
| 199 | match frame.id() { | ||
| 200 | embedded_can::Id::Extended(id) => { | ||
| 201 | info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 202 | } | ||
| 203 | embedded_can::Id::Standard(id) => { | ||
| 204 | info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | } | ||
| 208 | 107 | ||
| 209 | // Test again with a split | 108 | // Test again with a split |
| 210 | let (mut tx, mut rx) = can.split(); | 109 | let (mut tx, mut rx) = can.split(); |
| 211 | for i in 0..3 { | 110 | let (mut tx2, mut rx2) = can2.split(); |
| 212 | // Try filling up the RX FIFO0 buffers with standard packets | 111 | run_split_can_tests(&mut tx, &mut rx, &options).await; |
| 213 | let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap(); | 112 | run_split_can_tests(&mut tx2, &mut rx2, &options).await; |
| 214 | info!("Transmitting frame {}", i); | ||
| 215 | tx.write(&tx_frame).await; | ||
| 216 | } | ||
| 217 | for i in 3..max_buffered { | ||
| 218 | // Try filling up the RX FIFO0 buffers with extended packets | ||
| 219 | let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap(); | ||
| 220 | info!("Transmitting frame {}", i); | ||
| 221 | tx.write(&tx_frame).await; | ||
| 222 | } | ||
| 223 | |||
| 224 | // Try and receive all 6 packets | ||
| 225 | for i in 0..max_buffered { | ||
| 226 | let (frame, _ts) = rx.read().await.unwrap(); | ||
| 227 | match frame.id() { | ||
| 228 | embedded_can::Id::Extended(id) => { | ||
| 229 | info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 230 | } | ||
| 231 | embedded_can::Id::Standard(id) => { | ||
| 232 | info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | } | ||
| 236 | 113 | ||
| 237 | info!("Test OK"); | 114 | info!("Test OK"); |
| 238 | cortex_m::asm::bkpt(); | 115 | cortex_m::asm::bkpt(); |
