mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 08:12:30 +00:00
Merge pull request #3012 from cschuhen/feature/fdcan_no_generics
Remove generic argument for STM32 FDCAN.
This commit is contained in:
commit
e9cb9badf7
@ -3,6 +3,7 @@ use core::future::poll_fn;
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_hal_internal::interrupt::InterruptExt;
|
||||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender};
|
use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender};
|
||||||
@ -40,7 +41,7 @@ pub struct IT0InterruptHandler<T: Instance> {
|
|||||||
// We use IT0 for everything currently
|
// We use IT0 for everything currently
|
||||||
impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let regs = T::regs();
|
let regs = T::registers().regs;
|
||||||
|
|
||||||
let ir = regs.ir().read();
|
let ir = regs.ir().read();
|
||||||
|
|
||||||
@ -140,22 +141,13 @@ pub enum OperatingMode {
|
|||||||
//TestMode,
|
//TestMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FDCAN Configuration instance instance
|
|
||||||
/// Create instance of this first
|
|
||||||
pub struct CanConfigurator<'d, T: Instance> {
|
|
||||||
config: crate::can::fd::config::FdCanConfig,
|
|
||||||
/// Reference to internals.
|
|
||||||
instance: FdcanInstance<'d, T>,
|
|
||||||
properties: Properties<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 {
|
fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 {
|
||||||
match mode {
|
match mode {
|
||||||
// Use timestamp from Rx FIFO to adjust timestamp reported to user
|
// Use timestamp from Rx FIFO to adjust timestamp reported to user
|
||||||
crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => {
|
crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => {
|
||||||
let freq = T::frequency();
|
let freq = T::frequency();
|
||||||
let prescale: u64 =
|
let prescale: u64 = ({ T::registers().regs.nbtp().read().nbrp() } + 1) as u64
|
||||||
({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64;
|
* ({ T::registers().regs.tscc().read().tcp() } + 1) as u64;
|
||||||
1_000_000_000 as u64 / (freq.0 as u64 * prescale)
|
1_000_000_000 as u64 / (freq.0 as u64 * prescale)
|
||||||
}
|
}
|
||||||
// For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use
|
// For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use
|
||||||
@ -164,6 +156,18 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// FDCAN Configuration instance instance
|
||||||
|
/// Create instance of this first
|
||||||
|
pub struct CanConfigurator<'d, T: Instance> {
|
||||||
|
config: crate::can::fd::config::FdCanConfig,
|
||||||
|
info: &'static Info,
|
||||||
|
state: &'static State,
|
||||||
|
/// Reference to internals.
|
||||||
|
_instance: FdcanInstance<'d, T>,
|
||||||
|
properties: Properties,
|
||||||
|
periph_clock: crate::time::Hertz,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> CanConfigurator<'d, T> {
|
impl<'d, T: Instance> CanConfigurator<'d, T> {
|
||||||
/// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
|
/// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
|
||||||
/// You must call [Fdcan::enable_non_blocking] to use the peripheral.
|
/// You must call [Fdcan::enable_non_blocking] to use the peripheral.
|
||||||
@ -196,16 +200,18 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
|||||||
T::IT1Interrupt::unpend(); // Not unsafe
|
T::IT1Interrupt::unpend(); // Not unsafe
|
||||||
T::IT1Interrupt::enable();
|
T::IT1Interrupt::enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
config,
|
config,
|
||||||
instance: FdcanInstance(peri),
|
info: T::info(),
|
||||||
properties: Properties::new(),
|
state: T::state(),
|
||||||
|
_instance: FdcanInstance(peri),
|
||||||
|
properties: Properties::new(T::info()),
|
||||||
|
periph_clock: T::frequency(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get driver properties
|
/// Get driver properties
|
||||||
pub fn properties(&self) -> &Properties<T> {
|
pub fn properties(&self) -> &Properties {
|
||||||
&self.properties
|
&self.properties
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +227,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
|||||||
|
|
||||||
/// Configures the bit timings calculated from supplied bitrate.
|
/// Configures the bit timings calculated from supplied bitrate.
|
||||||
pub fn set_bitrate(&mut self, bitrate: u32) {
|
pub fn set_bitrate(&mut self, bitrate: u32) {
|
||||||
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
|
let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
|
||||||
|
|
||||||
let nbtr = crate::can::fd::config::NominalBitTiming {
|
let nbtr = crate::can::fd::config::NominalBitTiming {
|
||||||
sync_jump_width: bit_timing.sync_jump_width,
|
sync_jump_width: bit_timing.sync_jump_width,
|
||||||
@ -234,7 +240,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
|||||||
|
|
||||||
/// Configures the bit timings for VBR data calculated from supplied bitrate. This also sets confit to allow can FD and VBR
|
/// Configures the bit timings for VBR data calculated from supplied bitrate. This also sets confit to allow can FD and VBR
|
||||||
pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) {
|
pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) {
|
||||||
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
|
let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
|
||||||
// Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M
|
// Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M
|
||||||
let nbtr = crate::can::fd::config::DataBitTiming {
|
let nbtr = crate::can::fd::config::DataBitTiming {
|
||||||
transceiver_delay_compensation,
|
transceiver_delay_compensation,
|
||||||
@ -248,62 +254,68 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Start in mode.
|
/// Start in mode.
|
||||||
pub fn start(self, mode: OperatingMode) -> Can<'d, T> {
|
pub fn start(self, mode: OperatingMode) -> Can<'d> {
|
||||||
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
|
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
T::mut_state().ns_per_timer_tick = ns_per_timer_tick;
|
let state = self.state as *const State;
|
||||||
|
unsafe {
|
||||||
|
let mut_state = state as *mut State;
|
||||||
|
(*mut_state).ns_per_timer_tick = ns_per_timer_tick;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
T::registers().into_mode(self.config, mode);
|
T::registers().into_mode(self.config, mode);
|
||||||
let ret = Can {
|
Can {
|
||||||
config: self.config,
|
config: self.config,
|
||||||
instance: self.instance,
|
info: self.info,
|
||||||
|
state: self.state,
|
||||||
|
instance: T::info().regs.regs,
|
||||||
_mode: mode,
|
_mode: mode,
|
||||||
properties: self.properties,
|
properties: Properties::new(T::info()),
|
||||||
};
|
}
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start, entering mode. Does same as start(mode)
|
/// Start, entering mode. Does same as start(mode)
|
||||||
pub fn into_normal_mode(self) -> Can<'d, T> {
|
pub fn into_normal_mode(self) -> Can<'d> {
|
||||||
self.start(OperatingMode::NormalOperationMode)
|
self.start(OperatingMode::NormalOperationMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start, entering mode. Does same as start(mode)
|
/// Start, entering mode. Does same as start(mode)
|
||||||
pub fn into_internal_loopback_mode(self) -> Can<'d, T> {
|
pub fn into_internal_loopback_mode(self) -> Can<'d> {
|
||||||
self.start(OperatingMode::InternalLoopbackMode)
|
self.start(OperatingMode::InternalLoopbackMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start, entering mode. Does same as start(mode)
|
/// Start, entering mode. Does same as start(mode)
|
||||||
pub fn into_external_loopback_mode(self) -> Can<'d, T> {
|
pub fn into_external_loopback_mode(self) -> Can<'d> {
|
||||||
self.start(OperatingMode::ExternalLoopbackMode)
|
self.start(OperatingMode::ExternalLoopbackMode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FDCAN Instance
|
/// FDCAN Instance
|
||||||
pub struct Can<'d, T: Instance> {
|
pub struct Can<'d> {
|
||||||
config: crate::can::fd::config::FdCanConfig,
|
config: crate::can::fd::config::FdCanConfig,
|
||||||
/// Reference to internals.
|
info: &'static Info,
|
||||||
instance: FdcanInstance<'d, T>,
|
state: &'static State,
|
||||||
|
instance: &'d crate::pac::can::Fdcan,
|
||||||
_mode: OperatingMode,
|
_mode: OperatingMode,
|
||||||
properties: Properties<T>,
|
properties: Properties,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Can<'d, T> {
|
impl<'d> Can<'d> {
|
||||||
/// Get driver properties
|
/// Get driver properties
|
||||||
pub fn properties(&self) -> &Properties<T> {
|
pub fn properties(&self) -> &Properties {
|
||||||
&self.properties
|
&self.properties
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flush one of the TX mailboxes.
|
/// Flush one of the TX mailboxes.
|
||||||
pub async fn flush(&self, idx: usize) {
|
pub async fn flush(&self, idx: usize) {
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
T::state().tx_mode.register(cx.waker());
|
self.state.tx_mode.register(cx.waker());
|
||||||
|
|
||||||
if idx > 3 {
|
if idx > 3 {
|
||||||
panic!("Bad mailbox");
|
panic!("Bad mailbox");
|
||||||
}
|
}
|
||||||
let idx = 1 << idx;
|
let idx = 1 << idx;
|
||||||
if !T::regs().txbrp().read().trp(idx) {
|
if !self.info.regs.regs.txbrp().read().trp(idx) {
|
||||||
return Poll::Ready(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,12 +329,12 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||||
/// transmitted, then tries again.
|
/// transmitted, then tries again.
|
||||||
pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
|
pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
|
||||||
T::state().tx_mode.write::<T>(frame).await
|
self.state.tx_mode.write(self.info, frame).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the next received message frame
|
/// Returns the next received message frame
|
||||||
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
||||||
T::state().rx_mode.read_classic::<T>().await
|
self.state.rx_mode.read_classic(self.info, self.state).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
||||||
@ -330,58 +342,61 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||||
/// transmitted, then tries again.
|
/// transmitted, then tries again.
|
||||||
pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
|
pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
|
||||||
T::state().tx_mode.write_fd::<T>(frame).await
|
self.state.tx_mode.write_fd(self.info, frame).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the next received message frame
|
/// Returns the next received message frame
|
||||||
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
|
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
|
||||||
T::state().rx_mode.read_fd::<T>().await
|
self.state.rx_mode.read_fd(self.info, self.state).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split instance into separate portions: Tx(write), Rx(read), common properties
|
/// Split instance into separate portions: Tx(write), Rx(read), common properties
|
||||||
pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>, Properties<T>) {
|
pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) {
|
||||||
(
|
(
|
||||||
CanTx {
|
CanTx {
|
||||||
|
info: self.info,
|
||||||
|
state: self.state,
|
||||||
config: self.config,
|
config: self.config,
|
||||||
_instance: self.instance,
|
_instance: self.instance,
|
||||||
_mode: self._mode,
|
_mode: self._mode,
|
||||||
},
|
},
|
||||||
CanRx {
|
CanRx {
|
||||||
_instance1: PhantomData::<T>,
|
info: self.info,
|
||||||
_instance2: T::regs(),
|
state: self.state,
|
||||||
|
_instance: self.instance,
|
||||||
_mode: self._mode,
|
_mode: self._mode,
|
||||||
},
|
},
|
||||||
self.properties,
|
self.properties,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Join split rx and tx portions back together
|
/// Join split rx and tx portions back together
|
||||||
pub fn join(tx: CanTx<'d, T>, rx: CanRx<'d, T>) -> Self {
|
pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self {
|
||||||
Can {
|
Can {
|
||||||
config: tx.config,
|
config: tx.config,
|
||||||
//_instance2: T::regs(),
|
info: tx.info,
|
||||||
|
state: tx.state,
|
||||||
instance: tx._instance,
|
instance: tx._instance,
|
||||||
_mode: rx._mode,
|
_mode: rx._mode,
|
||||||
properties: Properties::new(),
|
properties: Properties::new(tx.info),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a buffered instance of driver without CAN FD support. User must supply Buffers
|
/// Return a buffered instance of driver without CAN FD support. User must supply Buffers
|
||||||
pub fn buffered<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
|
pub fn buffered<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
|
||||||
&self,
|
self,
|
||||||
tx_buf: &'static mut TxBuf<TX_BUF_SIZE>,
|
tx_buf: &'static mut TxBuf<TX_BUF_SIZE>,
|
||||||
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
|
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
|
||||||
) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
|
) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||||
BufferedCan::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb)
|
BufferedCan::new(self.info, self.state, self.info.regs.regs, self._mode, tx_buf, rxb)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a buffered instance of driver with CAN FD support. User must supply Buffers
|
/// Return a buffered instance of driver with CAN FD support. User must supply Buffers
|
||||||
pub fn buffered_fd<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
|
pub fn buffered_fd<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
|
||||||
&self,
|
self,
|
||||||
tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>,
|
tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>,
|
||||||
rxb: &'static mut RxFdBuf<RX_BUF_SIZE>,
|
rxb: &'static mut RxFdBuf<RX_BUF_SIZE>,
|
||||||
) -> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
|
) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||||
BufferedCanFd::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb)
|
BufferedCanFd::new(self.info, self.state, self.info.regs.regs, self._mode, tx_buf, rxb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,52 +407,57 @@ pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<
|
|||||||
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
|
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
|
||||||
|
|
||||||
/// Buffered FDCAN Instance
|
/// Buffered FDCAN Instance
|
||||||
pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
||||||
_instance1: PhantomData<T>,
|
info: &'static Info,
|
||||||
_instance2: &'d crate::pac::can::Fdcan,
|
state: &'static State,
|
||||||
|
_instance: &'d crate::pac::can::Fdcan,
|
||||||
_mode: OperatingMode,
|
_mode: OperatingMode,
|
||||||
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
|
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
|
||||||
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
|
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
|
||||||
properties: Properties<T>,
|
properties: Properties,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||||
BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
|
|
||||||
{
|
|
||||||
fn new(
|
fn new(
|
||||||
_instance1: PhantomData<T>,
|
info: &'static Info,
|
||||||
_instance2: &'d crate::pac::can::Fdcan,
|
state: &'static State,
|
||||||
|
_instance: &'d crate::pac::can::Fdcan,
|
||||||
_mode: OperatingMode,
|
_mode: OperatingMode,
|
||||||
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
|
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
|
||||||
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
|
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
BufferedCan {
|
BufferedCan {
|
||||||
_instance1,
|
info,
|
||||||
_instance2,
|
state,
|
||||||
|
_instance,
|
||||||
_mode,
|
_mode,
|
||||||
tx_buf,
|
tx_buf,
|
||||||
rx_buf,
|
rx_buf,
|
||||||
properties: Properties::new(),
|
properties: Properties::new(info),
|
||||||
}
|
}
|
||||||
.setup()
|
.setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get driver properties
|
/// Get driver properties
|
||||||
pub fn properties(&self) -> &Properties<T> {
|
pub fn properties(&self) -> &Properties {
|
||||||
&self.properties
|
&self.properties
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(self) -> Self {
|
fn setup(self) -> Self {
|
||||||
// We don't want interrupts being processed while we change modes.
|
// We don't want interrupts being processed while we change modes.
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
let rx_inner = super::common::ClassicBufferedRxInner {
|
let rx_inner = super::common::ClassicBufferedRxInner {
|
||||||
rx_sender: self.rx_buf.sender().into(),
|
rx_sender: self.rx_buf.sender().into(),
|
||||||
};
|
};
|
||||||
let tx_inner = super::common::ClassicBufferedTxInner {
|
let tx_inner = super::common::ClassicBufferedTxInner {
|
||||||
tx_receiver: self.tx_buf.receiver().into(),
|
tx_receiver: self.tx_buf.receiver().into(),
|
||||||
};
|
};
|
||||||
T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner);
|
let state = self.state as *const State;
|
||||||
T::mut_state().tx_mode = TxMode::ClassicBuffered(tx_inner);
|
unsafe {
|
||||||
|
let mut_state = state as *mut State;
|
||||||
|
(*mut_state).rx_mode = RxMode::ClassicBuffered(rx_inner);
|
||||||
|
(*mut_state).tx_mode = TxMode::ClassicBuffered(tx_inner);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -445,7 +465,8 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
|||||||
/// Async write frame to TX buffer.
|
/// Async write frame to TX buffer.
|
||||||
pub async fn write(&mut self, frame: Frame) {
|
pub async fn write(&mut self, frame: Frame) {
|
||||||
self.tx_buf.send(frame).await;
|
self.tx_buf.send(frame).await;
|
||||||
T::IT0Interrupt::pend(); // Wake for Tx
|
self.info.interrupt0.pend(); // Wake for Tx
|
||||||
|
//T::IT0Interrupt::pend(); // Wake for Tx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Async read frame from RX buffer.
|
/// Async read frame from RX buffer.
|
||||||
@ -457,7 +478,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
|||||||
pub fn writer(&self) -> BufferedCanSender {
|
pub fn writer(&self) -> BufferedCanSender {
|
||||||
BufferedCanSender {
|
BufferedCanSender {
|
||||||
tx_buf: self.tx_buf.sender().into(),
|
tx_buf: self.tx_buf.sender().into(),
|
||||||
waker: T::IT0Interrupt::pend,
|
waker: self.info.tx_waker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,13 +488,15 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop
|
impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||||
for BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
let state = self.state as *const State;
|
||||||
T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
unsafe {
|
||||||
|
let mut_state = state as *mut State;
|
||||||
|
(*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||||
|
(*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -484,16 +507,6 @@ pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Resul
|
|||||||
/// User supplied buffer for TX buffering
|
/// User supplied buffer for TX buffering
|
||||||
pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
|
pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
|
||||||
|
|
||||||
/// Buffered FDCAN Instance
|
|
||||||
pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
|
||||||
_instance1: PhantomData<T>,
|
|
||||||
_instance2: &'d crate::pac::can::Fdcan,
|
|
||||||
_mode: OperatingMode,
|
|
||||||
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
|
|
||||||
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
|
|
||||||
properties: Properties<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sender that can be used for sending CAN frames.
|
/// Sender that can be used for sending CAN frames.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct BufferedFdCanSender {
|
pub struct BufferedFdCanSender {
|
||||||
@ -524,43 +537,58 @@ impl BufferedFdCanSender {
|
|||||||
/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
|
/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
|
||||||
pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>;
|
pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>;
|
||||||
|
|
||||||
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
/// Buffered FDCAN Instance
|
||||||
BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
|
pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
||||||
{
|
info: &'static Info,
|
||||||
|
state: &'static State,
|
||||||
|
_instance: &'d crate::pac::can::Fdcan,
|
||||||
|
_mode: OperatingMode,
|
||||||
|
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
|
||||||
|
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
|
||||||
|
properties: Properties,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||||
fn new(
|
fn new(
|
||||||
_instance1: PhantomData<T>,
|
info: &'static Info,
|
||||||
_instance2: &'d crate::pac::can::Fdcan,
|
state: &'static State,
|
||||||
|
_instance: &'d crate::pac::can::Fdcan,
|
||||||
_mode: OperatingMode,
|
_mode: OperatingMode,
|
||||||
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
|
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
|
||||||
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
|
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
BufferedCanFd {
|
BufferedCanFd {
|
||||||
_instance1,
|
info,
|
||||||
_instance2,
|
state,
|
||||||
|
_instance,
|
||||||
_mode,
|
_mode,
|
||||||
tx_buf,
|
tx_buf,
|
||||||
rx_buf,
|
rx_buf,
|
||||||
properties: Properties::new(),
|
properties: Properties::new(info),
|
||||||
}
|
}
|
||||||
.setup()
|
.setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get driver properties
|
/// Get driver properties
|
||||||
pub fn properties(&self) -> &Properties<T> {
|
pub fn properties(&self) -> &Properties {
|
||||||
&self.properties
|
&self.properties
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(self) -> Self {
|
fn setup(self) -> Self {
|
||||||
// We don't want interrupts being processed while we change modes.
|
// We don't want interrupts being processed while we change modes.
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
let rx_inner = super::common::FdBufferedRxInner {
|
let rx_inner = super::common::FdBufferedRxInner {
|
||||||
rx_sender: self.rx_buf.sender().into(),
|
rx_sender: self.rx_buf.sender().into(),
|
||||||
};
|
};
|
||||||
let tx_inner = super::common::FdBufferedTxInner {
|
let tx_inner = super::common::FdBufferedTxInner {
|
||||||
tx_receiver: self.tx_buf.receiver().into(),
|
tx_receiver: self.tx_buf.receiver().into(),
|
||||||
};
|
};
|
||||||
T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner);
|
let state = self.state as *const State;
|
||||||
T::mut_state().tx_mode = TxMode::FdBuffered(tx_inner);
|
unsafe {
|
||||||
|
let mut_state = state as *mut State;
|
||||||
|
(*mut_state).rx_mode = RxMode::FdBuffered(rx_inner);
|
||||||
|
(*mut_state).tx_mode = TxMode::FdBuffered(tx_inner);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -568,7 +596,8 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
|||||||
/// Async write frame to TX buffer.
|
/// Async write frame to TX buffer.
|
||||||
pub async fn write(&mut self, frame: FdFrame) {
|
pub async fn write(&mut self, frame: FdFrame) {
|
||||||
self.tx_buf.send(frame).await;
|
self.tx_buf.send(frame).await;
|
||||||
T::IT0Interrupt::pend(); // Wake for Tx
|
self.info.interrupt0.pend(); // Wake for Tx
|
||||||
|
//T::IT0Interrupt::pend(); // Wake for Tx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Async read frame from RX buffer.
|
/// Async read frame from RX buffer.
|
||||||
@ -580,7 +609,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
|||||||
pub fn writer(&self) -> BufferedFdCanSender {
|
pub fn writer(&self) -> BufferedFdCanSender {
|
||||||
BufferedFdCanSender {
|
BufferedFdCanSender {
|
||||||
tx_buf: self.tx_buf.sender().into(),
|
tx_buf: self.tx_buf.sender().into(),
|
||||||
waker: T::IT0Interrupt::pend,
|
waker: self.info.tx_waker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,38 +619,55 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop
|
impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||||
for BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
let state = self.state as *const State;
|
||||||
T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
unsafe {
|
||||||
|
let mut_state = state as *mut State;
|
||||||
|
(*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||||
|
(*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FDCAN Rx only Instance
|
/// FDCAN Rx only Instance
|
||||||
pub struct CanRx<'d, T: Instance> {
|
pub struct CanRx<'d> {
|
||||||
_instance1: PhantomData<T>,
|
info: &'static Info,
|
||||||
_instance2: &'d crate::pac::can::Fdcan,
|
state: &'static State,
|
||||||
|
_instance: &'d crate::pac::can::Fdcan,
|
||||||
_mode: OperatingMode,
|
_mode: OperatingMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'d> CanRx<'d> {
|
||||||
|
/// Returns the next received message frame
|
||||||
|
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
||||||
|
self.state.rx_mode.read_classic(&self.info, &self.state).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the next received message frame
|
||||||
|
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
|
||||||
|
self.state.rx_mode.read_fd(&self.info, &self.state).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// FDCAN Tx only Instance
|
/// FDCAN Tx only Instance
|
||||||
pub struct CanTx<'d, T: Instance> {
|
pub struct CanTx<'d> {
|
||||||
|
info: &'static Info,
|
||||||
|
state: &'static State,
|
||||||
config: crate::can::fd::config::FdCanConfig,
|
config: crate::can::fd::config::FdCanConfig,
|
||||||
_instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>);
|
_instance: &'d crate::pac::can::Fdcan,
|
||||||
_mode: OperatingMode,
|
_mode: OperatingMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'c, 'd, T: Instance> CanTx<'d, T> {
|
impl<'c, 'd> CanTx<'d> {
|
||||||
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
||||||
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
||||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||||
/// transmitted, then tries again.
|
/// transmitted, then tries again.
|
||||||
pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
|
pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
|
||||||
T::state().tx_mode.write::<T>(frame).await
|
self.state.tx_mode.write(self.info, frame).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
||||||
@ -629,19 +675,7 @@ impl<'c, 'd, T: Instance> CanTx<'d, T> {
|
|||||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||||
/// transmitted, then tries again.
|
/// transmitted, then tries again.
|
||||||
pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
|
pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
|
||||||
T::state().tx_mode.write_fd::<T>(frame).await
|
self.state.tx_mode.write_fd(self.info, frame).await
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'c, 'd, T: Instance> CanRx<'d, T> {
|
|
||||||
/// Returns the next received message frame
|
|
||||||
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
|
||||||
T::state().rx_mode.read_classic::<T>().await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the next received message frame
|
|
||||||
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
|
|
||||||
T::state().rx_mode.read_fd::<T>().await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,7 +696,7 @@ impl RxMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_interrupt<T: Instance>(&self, fifonr: usize) {
|
fn on_interrupt<T: Instance>(&self, fifonr: usize) {
|
||||||
T::regs().ir().write(|w| w.set_rfn(fifonr, true));
|
T::registers().regs.ir().write(|w| w.set_rfn(fifonr, true));
|
||||||
match self {
|
match self {
|
||||||
RxMode::NonBuffered(waker) => {
|
RxMode::NonBuffered(waker) => {
|
||||||
waker.wake();
|
waker.wake();
|
||||||
@ -696,7 +730,6 @@ impl RxMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
|
|
||||||
fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> {
|
fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> {
|
||||||
if let Some((frame, ts)) = T::registers().read(0) {
|
if let Some((frame, ts)) = T::registers().read(0) {
|
||||||
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
|
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
|
||||||
@ -712,14 +745,18 @@ impl RxMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> {
|
fn read<F: CanHeader>(
|
||||||
if let Some((msg, ts)) = T::registers().read(0) {
|
&self,
|
||||||
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
|
info: &'static Info,
|
||||||
|
state: &'static State,
|
||||||
|
) -> Option<Result<(F, Timestamp), BusError>> {
|
||||||
|
if let Some((msg, ts)) = info.regs.read(0) {
|
||||||
|
let ts = info.calc_timestamp(state.ns_per_timer_tick, ts);
|
||||||
Some(Ok((msg, ts)))
|
Some(Ok((msg, ts)))
|
||||||
} else if let Some((msg, ts)) = T::registers().read(1) {
|
} else if let Some((msg, ts)) = info.regs.read(1) {
|
||||||
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
|
let ts = info.calc_timestamp(state.ns_per_timer_tick, ts);
|
||||||
Some(Ok((msg, ts)))
|
Some(Ok((msg, ts)))
|
||||||
} else if let Some(err) = T::registers().curr_error() {
|
} else if let Some(err) = info.regs.curr_error() {
|
||||||
// TODO: this is probably wrong
|
// TODO: this is probably wrong
|
||||||
Some(Err(err))
|
Some(Err(err))
|
||||||
} else {
|
} else {
|
||||||
@ -727,11 +764,16 @@ impl RxMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_async<T: Instance, F: CanHeader>(&self) -> Result<(F, Timestamp), BusError> {
|
async fn read_async<F: CanHeader>(
|
||||||
poll_fn(|cx| {
|
&self,
|
||||||
T::state().err_waker.register(cx.waker());
|
info: &'static Info,
|
||||||
|
state: &'static State,
|
||||||
|
) -> Result<(F, Timestamp), BusError> {
|
||||||
|
//let _ = self.read::<F>(info, state);
|
||||||
|
poll_fn(move |cx| {
|
||||||
|
state.err_waker.register(cx.waker());
|
||||||
self.register(cx.waker());
|
self.register(cx.waker());
|
||||||
match self.read::<T, _>() {
|
match self.read::<_>(info, state) {
|
||||||
Some(result) => Poll::Ready(result),
|
Some(result) => Poll::Ready(result),
|
||||||
None => Poll::Pending,
|
None => Poll::Pending,
|
||||||
}
|
}
|
||||||
@ -739,15 +781,15 @@ impl RxMode {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
|
async fn read_classic(&self, info: &'static Info, state: &'static State) -> Result<Envelope, BusError> {
|
||||||
match self.read_async::<T, _>().await {
|
match self.read_async::<_>(info, state).await {
|
||||||
Ok((frame, ts)) => Ok(Envelope { ts, frame }),
|
Ok((frame, ts)) => Ok(Envelope { ts, frame }),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_fd<T: Instance>(&self) -> Result<FdEnvelope, BusError> {
|
async fn read_fd(&self, info: &'static Info, state: &'static State) -> Result<FdEnvelope, BusError> {
|
||||||
match self.read_async::<T, _>().await {
|
match self.read_async::<_>(info, state).await {
|
||||||
Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }),
|
Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
@ -776,11 +818,11 @@ impl TxMode {
|
|||||||
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
||||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||||
/// transmitted, then tries again.
|
/// transmitted, then tries again.
|
||||||
async fn write_generic<T: Instance, F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> Option<F> {
|
async fn write_generic<F: embedded_can::Frame + CanHeader>(&self, info: &'static Info, frame: &F) -> Option<F> {
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
self.register(cx.waker());
|
self.register(cx.waker());
|
||||||
|
|
||||||
if let Ok(dropped) = T::registers().write(frame) {
|
if let Ok(dropped) = info.regs.write(frame) {
|
||||||
return Poll::Ready(dropped);
|
return Poll::Ready(dropped);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,68 +837,70 @@ impl TxMode {
|
|||||||
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
||||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||||
/// transmitted, then tries again.
|
/// transmitted, then tries again.
|
||||||
async fn write<T: Instance>(&self, frame: &Frame) -> Option<Frame> {
|
async fn write(&self, info: &'static Info, frame: &Frame) -> Option<Frame> {
|
||||||
self.write_generic::<T, _>(frame).await
|
self.write_generic::<_>(info, frame).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
||||||
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
||||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||||
/// transmitted, then tries again.
|
/// transmitted, then tries again.
|
||||||
async fn write_fd<T: Instance>(&self, frame: &FdFrame) -> Option<FdFrame> {
|
async fn write_fd(&self, info: &'static Info, frame: &FdFrame) -> Option<FdFrame> {
|
||||||
self.write_generic::<T, _>(frame).await
|
self.write_generic::<_>(info, frame).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Common driver properties, including filters and error counters
|
/// Common driver properties, including filters and error counters
|
||||||
pub struct Properties<T> {
|
pub struct Properties {
|
||||||
|
info: &'static Info,
|
||||||
// phantom pointer to ensure !Sync
|
// phantom pointer to ensure !Sync
|
||||||
instance: PhantomData<*const T>,
|
//instance: PhantomData<*const T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> Properties<T> {
|
impl Properties {
|
||||||
fn new() -> Self {
|
fn new(info: &'static Info) -> Self {
|
||||||
Self {
|
Self {
|
||||||
instance: Default::default(),
|
info,
|
||||||
|
//instance: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a standard address CAN filter in the specified slot in FDCAN memory.
|
/// Set a standard address CAN filter in the specified slot in FDCAN memory.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_standard_filter(&self, slot: StandardFilterSlot, filter: StandardFilter) {
|
pub fn set_standard_filter(&self, slot: StandardFilterSlot, filter: StandardFilter) {
|
||||||
T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter);
|
self.info.regs.msg_ram_mut().filters.flssa[slot as usize].activate(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the full array of standard address CAN filters in FDCAN memory.
|
/// Set the full array of standard address CAN filters in FDCAN memory.
|
||||||
/// Overwrites all standard address filters in memory.
|
/// Overwrites all standard address filters in memory.
|
||||||
pub fn set_standard_filters(&self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
|
pub fn set_standard_filters(&self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
|
||||||
for (i, f) in filters.iter().enumerate() {
|
for (i, f) in filters.iter().enumerate() {
|
||||||
T::registers().msg_ram_mut().filters.flssa[i].activate(*f);
|
self.info.regs.msg_ram_mut().filters.flssa[i].activate(*f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set an extended address CAN filter in the specified slot in FDCAN memory.
|
/// Set an extended address CAN filter in the specified slot in FDCAN memory.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_extended_filter(&self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
|
pub fn set_extended_filter(&self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
|
||||||
T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter);
|
self.info.regs.msg_ram_mut().filters.flesa[slot as usize].activate(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the full array of extended address CAN filters in FDCAN memory.
|
/// Set the full array of extended address CAN filters in FDCAN memory.
|
||||||
/// Overwrites all extended address filters in memory.
|
/// Overwrites all extended address filters in memory.
|
||||||
pub fn set_extended_filters(&self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
|
pub fn set_extended_filters(&self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
|
||||||
for (i, f) in filters.iter().enumerate() {
|
for (i, f) in filters.iter().enumerate() {
|
||||||
T::registers().msg_ram_mut().filters.flesa[i].activate(*f);
|
self.info.regs.msg_ram_mut().filters.flesa[i].activate(*f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the CAN RX error counter
|
/// Get the CAN RX error counter
|
||||||
pub fn rx_error_count(&self) -> u8 {
|
pub fn rx_error_count(&self) -> u8 {
|
||||||
T::regs().ecr().read().rec()
|
self.info.regs.regs.ecr().read().rec()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the CAN TX error counter
|
/// Get the CAN TX error counter
|
||||||
pub fn tx_error_count(&self) -> u8 {
|
pub fn tx_error_count(&self) -> u8 {
|
||||||
T::regs().ecr().read().tec()
|
self.info.regs.regs.ecr().read().tec()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current bus error mode
|
/// Get the current bus error mode
|
||||||
@ -864,7 +908,7 @@ impl<T: Instance> Properties<T> {
|
|||||||
// This read will clear LEC and DLEC. This is not ideal, but protocol
|
// This read will clear LEC and DLEC. This is not ideal, but protocol
|
||||||
// error reporting in this driver should have a big ol' FIXME on it
|
// error reporting in this driver should have a big ol' FIXME on it
|
||||||
// anyway!
|
// anyway!
|
||||||
let psr = T::regs().psr().read();
|
let psr = self.info.regs.regs.psr().read();
|
||||||
match (psr.bo(), psr.ep()) {
|
match (psr.bo(), psr.ep()) {
|
||||||
(false, false) => BusErrorMode::ErrorActive,
|
(false, false) => BusErrorMode::ErrorActive,
|
||||||
(false, true) => BusErrorMode::ErrorPassive,
|
(false, true) => BusErrorMode::ErrorPassive,
|
||||||
@ -892,10 +936,37 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Info {
|
||||||
|
regs: Registers,
|
||||||
|
interrupt0: crate::interrupt::Interrupt,
|
||||||
|
_interrupt1: crate::interrupt::Interrupt,
|
||||||
|
tx_waker: fn(),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Info {
|
||||||
|
#[cfg(feature = "time")]
|
||||||
|
fn calc_timestamp(&self, ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
|
||||||
|
let now_embassy = embassy_time::Instant::now();
|
||||||
|
if ns_per_timer_tick == 0 {
|
||||||
|
return now_embassy;
|
||||||
|
}
|
||||||
|
let cantime = { self.regs.regs.tscv().read().tsc() };
|
||||||
|
let delta = cantime.overflowing_sub(ts_val).0 as u64;
|
||||||
|
let ns = ns_per_timer_tick * delta as u64;
|
||||||
|
now_embassy - embassy_time::Duration::from_nanos(ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "time"))]
|
||||||
|
fn calc_timestamp(&self, _ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
|
||||||
|
ts_val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trait SealedInstance {
|
trait SealedInstance {
|
||||||
const MSG_RAM_OFFSET: usize;
|
const MSG_RAM_OFFSET: usize;
|
||||||
|
|
||||||
fn regs() -> &'static crate::pac::can::Fdcan;
|
fn info() -> &'static Info;
|
||||||
|
//fn regs() -> &'static crate::pac::can::Fdcan;
|
||||||
fn registers() -> crate::can::fd::peripheral::Registers;
|
fn registers() -> crate::can::fd::peripheral::Registers;
|
||||||
fn state() -> &'static State;
|
fn state() -> &'static State;
|
||||||
unsafe fn mut_state() -> &'static mut State;
|
unsafe fn mut_state() -> &'static mut State;
|
||||||
@ -915,12 +986,20 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static {
|
|||||||
pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>);
|
pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>);
|
||||||
|
|
||||||
macro_rules! impl_fdcan {
|
macro_rules! impl_fdcan {
|
||||||
($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => {
|
($inst:ident,
|
||||||
|
//$irq0:ident, $irq1:ident,
|
||||||
|
$msg_ram_inst:ident, $msg_ram_offset:literal) => {
|
||||||
impl SealedInstance for peripherals::$inst {
|
impl SealedInstance for peripherals::$inst {
|
||||||
const MSG_RAM_OFFSET: usize = $msg_ram_offset;
|
const MSG_RAM_OFFSET: usize = $msg_ram_offset;
|
||||||
|
|
||||||
fn regs() -> &'static crate::pac::can::Fdcan {
|
fn info() -> &'static Info {
|
||||||
&crate::pac::$inst
|
static INFO: Info = Info {
|
||||||
|
regs: Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: $msg_ram_offset},
|
||||||
|
interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ,
|
||||||
|
_interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ,
|
||||||
|
tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend,
|
||||||
|
};
|
||||||
|
&INFO
|
||||||
}
|
}
|
||||||
fn registers() -> Registers {
|
fn registers() -> Registers {
|
||||||
Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET}
|
Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET}
|
||||||
@ -939,7 +1018,7 @@ macro_rules! impl_fdcan {
|
|||||||
if ns_per_timer_tick == 0 {
|
if ns_per_timer_tick == 0 {
|
||||||
return now_embassy;
|
return now_embassy;
|
||||||
}
|
}
|
||||||
let cantime = { Self::regs().tscv().read().tsc() };
|
let cantime = { Self::registers().regs.tscv().read().tsc() };
|
||||||
let delta = cantime.overflowing_sub(ts_val).0 as u64;
|
let delta = cantime.overflowing_sub(ts_val).0 as u64;
|
||||||
let ns = ns_per_timer_tick * delta as u64;
|
let ns = ns_per_timer_tick * delta as u64;
|
||||||
now_embassy - embassy_time::Duration::from_nanos(ns)
|
now_embassy - embassy_time::Duration::from_nanos(ns)
|
||||||
|
@ -9,9 +9,7 @@ use common::*;
|
|||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::bind_interrupts;
|
use embassy_stm32::bind_interrupts;
|
||||||
use embassy_stm32::can::filter::Mask32;
|
use embassy_stm32::can::filter::Mask32;
|
||||||
use embassy_stm32::can::{
|
use embassy_stm32::can::{Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
|
||||||
Can, Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler,
|
|
||||||
};
|
|
||||||
use embassy_stm32::gpio::{Input, Pull};
|
use embassy_stm32::gpio::{Input, Pull};
|
||||||
use embassy_stm32::peripherals::CAN1;
|
use embassy_stm32::peripherals::CAN1;
|
||||||
use embassy_time::Duration;
|
use embassy_time::Duration;
|
||||||
@ -20,6 +18,10 @@ use {defmt_rtt as _, panic_probe as _};
|
|||||||
mod can_common;
|
mod can_common;
|
||||||
use can_common::*;
|
use can_common::*;
|
||||||
|
|
||||||
|
type Can<'d> = embassy_stm32::can::Can<'d, embassy_stm32::peripherals::CAN1>;
|
||||||
|
type CanTx<'d> = embassy_stm32::can::CanTx<'d, embassy_stm32::peripherals::CAN1>;
|
||||||
|
type CanRx<'d> = embassy_stm32::can::CanRx<'d, embassy_stm32::peripherals::CAN1>;
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
CAN1_RX0 => Rx0InterruptHandler<CAN1>;
|
CAN1_RX0 => Rx0InterruptHandler<CAN1>;
|
||||||
CAN1_RX1 => Rx1InterruptHandler<CAN1>;
|
CAN1_RX1 => Rx1InterruptHandler<CAN1>;
|
||||||
|
@ -8,7 +8,8 @@ pub struct TestOptions {
|
|||||||
pub max_buffered: u8,
|
pub max_buffered: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) {
|
pub async fn run_can_tests<'d>(can: &mut crate::Can<'d>, options: &TestOptions) {
|
||||||
|
//pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) {
|
||||||
let mut i: u8 = 0;
|
let mut i: u8 = 0;
|
||||||
loop {
|
loop {
|
||||||
//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();
|
//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();
|
||||||
@ -79,11 +80,7 @@ pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, opti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_split_can_tests<'d, T: can::Instance>(
|
pub async fn run_split_can_tests<'d>(tx: &mut crate::CanTx<'d>, rx: &mut crate::CanRx<'d>, options: &TestOptions) {
|
||||||
tx: &mut can::CanTx<'d, T>,
|
|
||||||
rx: &mut can::CanRx<'d, T>,
|
|
||||||
options: &TestOptions,
|
|
||||||
) {
|
|
||||||
for i in 0..options.max_buffered {
|
for i in 0..options.max_buffered {
|
||||||
// Try filling up the RX FIFO0 buffers
|
// Try filling up the RX FIFO0 buffers
|
||||||
//let tx_frame = if 0 != (i & 0x01) {
|
//let tx_frame = if 0 != (i & 0x01) {
|
||||||
|
@ -15,6 +15,10 @@ use {defmt_rtt as _, panic_probe as _};
|
|||||||
mod can_common;
|
mod can_common;
|
||||||
use can_common::*;
|
use can_common::*;
|
||||||
|
|
||||||
|
type Can<'d> = can::Can<'d>;
|
||||||
|
type CanTx<'d> = can::CanTx<'d>;
|
||||||
|
type CanRx<'d> = can::CanRx<'d>;
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs2 {
|
bind_interrupts!(struct Irqs2 {
|
||||||
FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>;
|
FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>;
|
||||||
FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>;
|
FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>;
|
||||||
|
Loading…
Reference in New Issue
Block a user