From 289762c0efc43cf8357309bb98b28a5959b63d26 Mon Sep 17 00:00:00 2001 From: Eric Yanush <> Date: Mon, 20 Mar 2023 14:19:14 -0600 Subject: [PATCH 1/3] Add initial setup of async can for STM32 --- embassy-stm32/src/can/bxcan.rs | 157 ++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index bd92b35a..7e5b1cfa 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -1,9 +1,13 @@ +use core::future::poll_fn; use core::ops::{Deref, DerefMut}; +use core::task::Poll; pub use bxcan; +use bxcan::Frame; use embassy_hal_common::{into_ref, PeripheralRef}; use crate::gpio::sealed::AFType; +use crate::interrupt::{Interrupt, InterruptExt}; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; @@ -39,8 +43,12 @@ impl<'d, T: Instance> Can<'d, T> { peri: impl Peripheral
+ 'd, rx: impl Peripheral
> + 'd, tx: impl Peripheral
> + 'd, + tx_irq: impl Peripheral
+ 'd, + rx0_irq: impl Peripheral
+ 'd, + rx1_irq: impl Peripheral
+ 'd, + sce_irq: impl Peripheral
+ 'd,
) -> Self {
- into_ref!(peri, rx, tx);
+ into_ref!(peri, rx, tx, tx_irq, rx0_irq, rx1_irq, sce_irq);
unsafe {
rx.set_as_af(rx.af_num(), AFType::Input);
@@ -50,10 +58,75 @@ impl<'d, T: Instance> Can<'d, T> {
T::enable();
T::reset();
+ tx_irq.unpend();
+ tx_irq.set_handler(Self::tx_interrupt);
+ tx_irq.enable();
+
+ rx0_irq.unpend();
+ rx0_irq.set_handler(Self::rx0_interrupt);
+ rx0_irq.enable();
+
+ rx1_irq.unpend();
+ rx1_irq.set_handler(Self::rx1_interrupt);
+ rx1_irq.enable();
+
+ sce_irq.unpend();
+ sce_irq.set_handler(Self::sce_interrupt);
+ sce_irq.enable();
+
Self {
can: bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(),
}
}
+
+ pub async fn transmit_async(&mut self, frame: &Frame) {
+ defmt::info!("Staring async frame transmission");
+ let tx_status = self.queue_transmit(frame).await;
+ self.wait_transission(tx_status.mailbox()).await;
+ }
+
+ async fn queue_transmit(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
+ poll_fn(|cx| {
+ if let Ok(status) = self.can.transmit(frame) {
+ defmt::info!("Frame queued successfully in mb{}", status.mailbox());
+ return Poll::Ready(status);
+ }
+ defmt::info!("Mailboxes full, waiting to queue");
+ T::state().tx_waker.register(cx.waker());
+ Poll::Pending
+ })
+ .await
+ }
+
+ async fn wait_transission(&mut self, mb: bxcan::Mailbox) {
+ poll_fn(|cx| unsafe {
+ defmt::info!("Waiting for tx to complete");
+ if T::regs().tsr().read().tme(mb.index()) {
+ defmt::info!("TX complete for mb {}", mb);
+ return Poll::Ready(());
+ }
+ defmt::info!("TX not complete, waiting for signal on mb {}", mb);
+ T::state().tx_waker.register(cx.waker());
+ Poll::Pending
+ })
+ .await;
+ }
+
+ unsafe fn tx_interrupt(_: *mut ()) {
+ defmt::info!("bxCAN TX interrupt fired!");
+ T::regs().tsr().write(|v| {
+ v.set_rqcp(0, true);
+ v.set_rqcp(1, true);
+ v.set_rqcp(2, true);
+ });
+ T::state().tx_waker.wake();
+ }
+
+ unsafe fn rx0_interrupt(_: *mut ()) {}
+
+ unsafe fn rx1_interrupt(_: *mut ()) {}
+
+ unsafe fn sce_interrupt(_: *mut ()) {}
}
impl<'d, T: Instance> Drop for Can<'d, T> {
@@ -80,14 +153,51 @@ impl<'d, T: Instance> DerefMut for Can<'d, T> {
}
pub(crate) mod sealed {
+ use embassy_sync::waitqueue::AtomicWaker;
+ pub struct State {
+ pub tx_waker: AtomicWaker,
+ pub rx0_waker: AtomicWaker,
+ pub rx1_waker: AtomicWaker,
+ pub sce_waker: AtomicWaker,
+ }
+
+ impl State {
+ pub const fn new() -> Self {
+ Self {
+ tx_waker: AtomicWaker::new(),
+ rx0_waker: AtomicWaker::new(),
+ rx1_waker: AtomicWaker::new(),
+ sce_waker: AtomicWaker::new(),
+ }
+ }
+ }
+
pub trait Instance {
const REGISTERS: *mut bxcan::RegisterBlock;
fn regs() -> &'static crate::pac::can::Can;
+ fn state() -> &'static State;
}
}
-pub trait Instance: sealed::Instance + RccPeripheral {}
+pub trait TXInstance {
+ type TXInterrupt: crate::interrupt::Interrupt;
+}
+
+pub trait RX0Instance {
+ type RX0Interrupt: crate::interrupt::Interrupt;
+}
+
+pub trait RX1Instance {
+ type RX1Interrupt: crate::interrupt::Interrupt;
+}
+
+pub trait SCEInstance {
+ type SCEInterrupt: crate::interrupt::Interrupt;
+}
+
+pub trait InterruptableInstance: TXInstance + RX0Instance + RX1Instance + SCEInstance {}
+pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {}
pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
@@ -103,10 +213,39 @@ foreach_peripheral!(
fn regs() -> &'static crate::pac::can::Can {
&crate::pac::$inst
}
+
+ fn state() -> &'static sealed::State {
+ static STATE: sealed::State = sealed::State::new();
+ &STATE
+ }
}
impl Instance for peripherals::$inst {}
+ foreach_interrupt!(
+ ($inst,can,CAN,TX,$irq:ident) => {
+ impl TXInstance for peripherals::$inst {
+ type TXInterrupt = crate::interrupt::$irq;
+ }
+ };
+ ($inst,can,CAN,RX0,$irq:ident) => {
+ impl RX0Instance for peripherals::$inst {
+ type RX0Interrupt = crate::interrupt::$irq;
+ }
+ };
+ ($inst,can,CAN,RX1,$irq:ident) => {
+ impl RX1Instance for peripherals::$inst {
+ type RX1Interrupt = crate::interrupt::$irq;
+ }
+ };
+ ($inst,can,CAN,SCE,$irq:ident) => {
+ impl SCEInstance for peripherals::$inst {
+ type SCEInterrupt = crate::interrupt::$irq;
+ }
+ };
+ );
+
+ impl InterruptableInstance for peripherals::$inst {}
};
);
@@ -147,3 +286,17 @@ foreach_peripheral!(
pin_trait!(RxPin, Instance);
pin_trait!(TxPin, Instance);
+
+trait Index {
+ fn index(&self) -> usize;
+}
+
+impl Index for bxcan::Mailbox {
+ fn index(&self) -> usize {
+ match self {
+ bxcan::Mailbox::Mailbox0 => 0,
+ bxcan::Mailbox::Mailbox1 => 1,
+ bxcan::Mailbox::Mailbox2 => 2,
+ }
+ }
+}
From 9876571887845f60958c148308ae8a59433cd809 Mon Sep 17 00:00:00 2001
From: Eric Yanush <>
Date: Mon, 20 Mar 2023 14:25:15 -0600
Subject: [PATCH 2/3] Strip out debug messages... oops
---
embassy-stm32/src/can/bxcan.rs | 7 -------
1 file changed, 7 deletions(-)
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index 7e5b1cfa..521049ec 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -80,7 +80,6 @@ impl<'d, T: Instance> Can<'d, T> {
}
pub async fn transmit_async(&mut self, frame: &Frame) {
- defmt::info!("Staring async frame transmission");
let tx_status = self.queue_transmit(frame).await;
self.wait_transission(tx_status.mailbox()).await;
}
@@ -88,10 +87,8 @@ impl<'d, T: Instance> Can<'d, T> {
async fn queue_transmit(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
poll_fn(|cx| {
if let Ok(status) = self.can.transmit(frame) {
- defmt::info!("Frame queued successfully in mb{}", status.mailbox());
return Poll::Ready(status);
}
- defmt::info!("Mailboxes full, waiting to queue");
T::state().tx_waker.register(cx.waker());
Poll::Pending
})
@@ -100,12 +97,9 @@ impl<'d, T: Instance> Can<'d, T> {
async fn wait_transission(&mut self, mb: bxcan::Mailbox) {
poll_fn(|cx| unsafe {
- defmt::info!("Waiting for tx to complete");
if T::regs().tsr().read().tme(mb.index()) {
- defmt::info!("TX complete for mb {}", mb);
return Poll::Ready(());
}
- defmt::info!("TX not complete, waiting for signal on mb {}", mb);
T::state().tx_waker.register(cx.waker());
Poll::Pending
})
@@ -113,7 +107,6 @@ impl<'d, T: Instance> Can<'d, T> {
}
unsafe fn tx_interrupt(_: *mut ()) {
- defmt::info!("bxCAN TX interrupt fired!");
T::regs().tsr().write(|v| {
v.set_rqcp(0, true);
v.set_rqcp(1, true);
From 8d7abeb06fbe3e19db3cae3f5220725969ecbb81 Mon Sep 17 00:00:00 2001
From: Eric Yanush <>
Date: Thu, 6 Apr 2023 08:20:34 -0600
Subject: [PATCH 3/3] Round out the async fns for can
---
embassy-stm32/Cargo.toml | 1 +
embassy-stm32/src/can/bxcan.rs | 252 ++++++++++++++++++++++++++++++---
2 files changed, 237 insertions(+), 16 deletions(-)
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 504caacb..5e45db36 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -68,6 +68,7 @@ stm32-fmc = "0.2.4"
seq-macro = "0.3.0"
cfg-if = "1.0.0"
embedded-io = { version = "0.4.0", features = ["async"], optional = true }
+heapless = { version = "0.7.5", default-features = false }
[dev-dependencies]
critical-section = { version = "1.1", features = ["std"] }
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index 521049ec..734efdc0 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -3,18 +3,39 @@ use core::ops::{Deref, DerefMut};
use core::task::Poll;
pub use bxcan;
-use bxcan::Frame;
+use bxcan::{Data, ExtendedId, Frame, Id, StandardId};
use embassy_hal_common::{into_ref, PeripheralRef};
use crate::gpio::sealed::AFType;
-use crate::interrupt::{Interrupt, InterruptExt};
+use crate::interrupt::InterruptExt;
+use crate::pac::can::vals::{Lec, RirIde};
use crate::rcc::RccPeripheral;
+use crate::time::Hertz;
use crate::{peripherals, Peripheral};
pub struct Can<'d, T: Instance> {
can: bxcan::Can