#![doc(html_root_url = "https://docs.rs/bxcan/0.8.0")]
#![doc(test(attr(deny(unused_imports, unused_must_use))))]
#![no_std]
#![allow(clippy::unnecessary_operation)]
mod embedded_hal;
pub mod filter;
mod frame;
mod id;
mod interrupt;
#[allow(clippy::all)] mod pac;
pub use id::{ExtendedId, Id, StandardId};
pub use crate::frame::{Data, Frame, FramePriority};
pub use crate::interrupt::{Interrupt, Interrupts};
pub use crate::pac::can::RegisterBlock;
use crate::filter::MasterFilters;
use core::cmp::{Ord, Ordering};
use core::convert::{Infallible, TryInto};
use core::marker::PhantomData;
use core::mem;
use core::ptr::NonNull;
use self::pac::generic::*;
pub unsafe trait Instance {
const REGISTERS: *mut RegisterBlock;
}
pub unsafe trait FilterOwner: Instance {
const NUM_FILTER_BANKS: u8;
}
pub unsafe trait MasterInstance: FilterOwner {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))]
pub struct OverrunError {
_priv: (),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))]
struct IdReg(u32);
impl IdReg {
const STANDARD_SHIFT: u32 = 21;
const EXTENDED_SHIFT: u32 = 3;
const IDE_MASK: u32 = 0x0000_0004;
const RTR_MASK: u32 = 0x0000_0002;
fn new_standard(id: StandardId) -> Self {
Self(u32::from(id.as_raw()) << Self::STANDARD_SHIFT)
}
fn new_extended(id: ExtendedId) -> IdReg {
Self(id.as_raw() << Self::EXTENDED_SHIFT | Self::IDE_MASK)
}
fn from_register(reg: u32) -> IdReg {
Self(reg & 0xFFFF_FFFE)
}
#[must_use = "returns a new IdReg without modifying `self`"]
fn with_rtr(self, rtr: bool) -> IdReg {
if rtr {
Self(self.0 | Self::RTR_MASK)
} else {
Self(self.0 & !Self::RTR_MASK)
}
}
fn to_id(self) -> Id {
if self.is_extended() {
Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) })
} else {
Id::Standard(unsafe {
StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16)
})
}
}
fn is_extended(self) -> bool {
self.0 & Self::IDE_MASK != 0
}
fn is_standard(self) -> bool {
!self.is_extended()
}
fn rtr(self) -> bool {
self.0 & Self::RTR_MASK != 0
}
}
impl Ord for IdReg {
fn cmp(&self, other: &Self) -> Ordering {
let rtr = self.rtr().cmp(&other.rtr()).reverse();
let id_a = self.to_id();
let id_b = other.to_id();
match (id_a, id_b) {
(Id::Standard(a), Id::Standard(b)) => {
a.as_raw().cmp(&b.as_raw()).reverse().then(rtr)
}
(Id::Extended(a), Id::Extended(b)) => a.as_raw().cmp(&b.as_raw()).reverse().then(rtr),
(Id::Standard(a), Id::Extended(b)) => {
a.as_raw()
.cmp(&b.standard_id().as_raw())
.reverse()
.then(Ordering::Greater)
}
(Id::Extended(a), Id::Standard(b)) => a
.standard_id()
.as_raw()
.cmp(&b.as_raw())
.reverse()
.then(Ordering::Less),
}
}
}
impl PartialOrd for IdReg {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"]
pub struct CanConfig<'a, I: Instance> {
can: &'a mut Can<I>,
}
impl<I: Instance> CanConfig<'_, I> {
pub fn set_bit_timing(self, btr: u32) -> Self {
self.can.set_bit_timing(btr);
self
}
pub fn set_loopback(self, enabled: bool) -> Self {
let can = self.can.registers();
can.btr.modify(|_, w| w.lbkm().bit(enabled));
self
}
pub fn set_silent(self, enabled: bool) -> Self {
let can = self.can.registers();
can.btr.modify(|_, w| w.silm().bit(enabled));
self
}
pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
let can = self.can.registers();
can.mcr.modify(|_, w| w.nart().bit(!enabled));
self
}
pub fn enable(mut self) {
self.leave_init_mode();
match nb::block!(self.can.enable_non_blocking()) {
Ok(()) => {}
Err(void) => match void {},
}
mem::forget(self);
}
pub fn leave_disabled(mut self) {
self.leave_init_mode();
}
fn leave_init_mode(&mut self) {
let can = self.can.registers();
can.mcr
.modify(|_, w| w.sleep().set_bit().inrq().clear_bit());
loop {
let msr = can.msr.read();
if msr.slak().bit_is_set() && msr.inak().bit_is_clear() {
break;
}
}
}
}
impl<I: Instance> Drop for CanConfig<'_, I> {
#[inline]
fn drop(&mut self) {
self.leave_init_mode();
}
}
#[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"]
pub struct CanBuilder<I: Instance> {
can: Can<I>,
}
impl<I: Instance> CanBuilder<I> {
pub fn set_bit_timing(mut self, btr: u32) -> Self {
self.can.set_bit_timing(btr);
self
}
pub fn set_loopback(self, enabled: bool) -> Self {
let can = self.can.registers();
can.btr.modify(|_, w| w.lbkm().bit(enabled));
self
}
pub fn set_silent(self, enabled: bool) -> Self {
let can = self.can.registers();
can.btr.modify(|_, w| w.silm().bit(enabled));
self
}
pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
let can = self.can.registers();
can.mcr.modify(|_, w| w.nart().bit(!enabled));
self
}
pub fn enable(mut self) -> Can<I> {
self.leave_init_mode();
match nb::block!(self.can.enable_non_blocking()) {
Ok(()) => self.can,
Err(void) => match void {},
}
}
pub fn leave_disabled(mut self) -> Can<I> {
self.leave_init_mode();
self.can
}
fn leave_init_mode(&mut self) {
let can = self.can.registers();
can.mcr
.modify(|_, w| w.sleep().set_bit().inrq().clear_bit());
loop {
let msr = can.msr.read();
if msr.slak().bit_is_set() && msr.inak().bit_is_clear() {
break;
}
}
}
}
pub struct Can<I: Instance> {
instance: I,
}
impl<I> Can<I>
where
I: Instance,
{
pub fn builder(instance: I) -> CanBuilder<I> {
let can_builder = CanBuilder {
can: Can { instance },
};
let can_reg = can_builder.can.registers();
can_reg
.mcr
.modify(|_, w| w.sleep().clear_bit().inrq().set_bit());
loop {
let msr = can_reg.msr.read();
if msr.slak().bit_is_clear() && msr.inak().bit_is_set() {
break;
}
}
can_builder
}
fn registers(&self) -> &RegisterBlock {
unsafe { &*I::REGISTERS }
}
fn set_bit_timing(&mut self, btr: u32) {
const MASK: u32 = 0x037F_03FF;
let can = self.registers();
can.btr.modify(|r, w| unsafe {
let mode_bits = r.bits() & 0xC000_0000;
w.bits(mode_bits | (btr & MASK))
});
}
pub fn instance(&mut self) -> &mut I {
&mut self.instance
}
pub fn free(self) -> I {
self.registers().mcr.write(|w| w.reset().set_bit());
self.instance
}
pub fn modify_config(&mut self) -> CanConfig<'_, I> {
let can = self.registers();
can.mcr
.modify(|_, w| w.sleep().clear_bit().inrq().set_bit());
loop {
let msr = can.msr.read();
if msr.slak().bit_is_clear() && msr.inak().bit_is_set() {
break;
}
}
CanConfig { can: self }
}
pub fn set_automatic_wakeup(&mut self, enabled: bool) {
let can = self.registers();
can.mcr.modify(|_, w| w.awum().bit(enabled));
}
pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> {
let can = self.registers();
let msr = can.msr.read();
if msr.slak().bit_is_set() {
can.mcr
.modify(|_, w| w.abom().set_bit().sleep().clear_bit());
Err(nb::Error::WouldBlock)
} else {
Ok(())
}
}
pub fn sleep(&mut self) {
let can = self.registers();
can.mcr
.modify(|_, w| w.sleep().set_bit().inrq().clear_bit());
loop {
let msr = can.msr.read();
if msr.slak().bit_is_set() && msr.inak().bit_is_clear() {
break;
}
}
}
pub fn wakeup(&mut self) {
let can = self.registers();
can.mcr
.modify(|_, w| w.sleep().clear_bit().inrq().clear_bit());
loop {
let msr = can.msr.read();
if msr.slak().bit_is_clear() && msr.inak().bit_is_clear() {
break;
}
}
}
pub fn enable_interrupt(&mut self, interrupt: Interrupt) {
self.enable_interrupts(Interrupts::from_bits_truncate(interrupt as u32))
}
pub fn enable_interrupts(&mut self, interrupts: Interrupts) {
self.registers()
.ier
.modify(|r, w| unsafe { w.bits(r.bits() | interrupts.bits()) })
}
pub fn disable_interrupt(&mut self, interrupt: Interrupt) {
self.disable_interrupts(Interrupts::from_bits_truncate(interrupt as u32))
}
pub fn disable_interrupts(&mut self, interrupts: Interrupts) {
self.registers()
.ier
.modify(|r, w| unsafe { w.bits(r.bits() & !interrupts.bits()) })
}
pub fn clear_sleep_interrupt(&self) {
let can = self.registers();
can.msr.write(|w| w.slaki().set_bit());
}
pub fn clear_wakeup_interrupt(&self) {
let can = self.registers();
can.msr.write(|w| w.wkui().set_bit());
}
pub fn clear_request_completed_flag(&mut self) -> Option<Mailbox> {
let can = self.registers();
let tsr = can.tsr.read();
if tsr.rqcp0().bit_is_set() {
can.tsr.modify(|_, w| w.rqcp0().set_bit());
Some(Mailbox::Mailbox0)
} else if tsr.rqcp1().bit_is_set() {
can.tsr.modify(|_, w| w.rqcp1().set_bit());
Some(Mailbox::Mailbox1)
} else if tsr.rqcp2().bit_is_set() {
can.tsr.modify(|_, w| w.rqcp2().set_bit());
Some(Mailbox::Mailbox2)
} else {
None
}
}
pub fn clear_tx_interrupt(&mut self) {
while self.clear_request_completed_flag().is_some() {}
}
pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
unsafe { Tx::<I>::conjure().transmit(frame) }
}
pub fn is_transmitter_idle(&self) -> bool {
unsafe { Tx::<I>::conjure().is_idle() }
}
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
unsafe { Tx::<I>::conjure().abort(mailbox) }
}
pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> {
let mut rx0 = unsafe { Rx0::<I>::conjure() };
let mut rx1 = unsafe { Rx1::<I>::conjure() };
match rx0.receive() {
Err(nb::Error::WouldBlock) => rx1.receive(),
result => result,
}
}
pub fn rx0(&mut self) -> &mut Rx0<I> {
unsafe { Rx0::conjure_by_ref() }
}
pub fn rx1(&mut self) -> &mut Rx1<I> {
unsafe { Rx1::conjure_by_ref() }
}
pub fn split_by_ref(&mut self) -> (&mut Tx<I>, &mut Rx0<I>, &mut Rx1<I>) {
let tx = unsafe { Tx::conjure_by_ref() };
let rx0 = unsafe { Rx0::conjure_by_ref() };
let rx1 = unsafe { Rx1::conjure_by_ref() };
(tx, rx0, rx1)
}
pub fn split(self) -> (Tx<I>, Rx0<I>, Rx1<I>) {
unsafe { (Tx::conjure(), Rx0::conjure(), Rx1::conjure()) }
}
}
impl<I: FilterOwner> Can<I> {
pub fn modify_filters(&mut self) -> MasterFilters<'_, I> {
unsafe { MasterFilters::new() }
}
}
pub struct Tx<I> {
_can: PhantomData<I>,
}
#[inline]
const fn ok_mask(idx: usize) -> u32 {
0x02 << (8 * idx)
}
#[inline]
const fn abort_mask(idx: usize) -> u32 {
0x80 << (8 * idx)
}
impl<I> Tx<I>
where
I: Instance,
{
unsafe fn conjure() -> Self {
Self { _can: PhantomData }
}
unsafe fn conjure_by_ref<'a>() -> &'a mut Self {
[()][core::mem::size_of::<Self>()];
&mut *NonNull::dangling().as_ptr()
}
fn registers(&self) -> &RegisterBlock {
unsafe { &*I::REGISTERS }
}
pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
let can = self.registers();
let tsr = can.tsr.read();
let idx = tsr.code().bits() as usize;
let frame_is_pending =
tsr.tme0().bit_is_clear() || tsr.tme1().bit_is_clear() || tsr.tme2().bit_is_clear();
let pending_frame = if frame_is_pending {
self.check_priority(0, frame.id)?;
self.check_priority(1, frame.id)?;
self.check_priority(2, frame.id)?;
let all_frames_are_pending =
tsr.tme0().bit_is_clear() && tsr.tme1().bit_is_clear() && tsr.tme2().bit_is_clear();
if all_frames_are_pending {
self.read_pending_mailbox(idx)
} else {
None
}
} else {
None
};
self.write_mailbox(idx, frame);
let mailbox = match idx {
0 => Mailbox::Mailbox0,
1 => Mailbox::Mailbox1,
2 => Mailbox::Mailbox2,
_ => unreachable!(),
};
Ok(TransmitStatus {
dequeued_frame: pending_frame,
mailbox,
})
}
fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> {
let can = self.registers();
assert!(idx < 3);
let tir = &can.tx[idx].tir.read();
if tir.txrq().bit_is_set() && id <= IdReg::from_register(tir.bits()) {
return Err(nb::Error::WouldBlock);
}
Ok(())
}
fn write_mailbox(&mut self, idx: usize, frame: &Frame) {
let can = self.registers();
debug_assert!(idx < 3);
let mb = unsafe { &can.tx.get_unchecked(idx) };
mb.tdtr
.write(|w| unsafe { w.dlc().bits(frame.dlc() as u8) });
mb.tdlr.write(|w| unsafe {
w.bits(u32::from_ne_bytes(
frame.data.bytes[0..4].try_into().unwrap(),
))
});
mb.tdhr.write(|w| unsafe {
w.bits(u32::from_ne_bytes(
frame.data.bytes[4..8].try_into().unwrap(),
))
});
mb.tir
.write(|w| unsafe { w.bits(frame.id.0).txrq().set_bit() });
}
fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> {
if self.abort_by_index(idx) {
let can = self.registers();
debug_assert!(idx < 3);
let mb = unsafe { &can.tx.get_unchecked(idx) };
let mut pending_frame = Frame {
id: IdReg(mb.tir.read().bits()),
data: Data::empty(),
};
pending_frame.data.bytes[0..4].copy_from_slice(&mb.tdlr.read().bits().to_ne_bytes());
pending_frame.data.bytes[4..8].copy_from_slice(&mb.tdhr.read().bits().to_ne_bytes());
pending_frame.data.len = mb.tdtr.read().dlc().bits();
Some(pending_frame)
} else {
None
}
}
fn abort_by_index(&mut self, idx: usize) -> bool {
let can = self.registers();
can.tsr.write(|w| unsafe { w.bits(abort_mask(idx)) });
loop {
let tsr = can.tsr.read().bits();
if tsr & abort_mask(idx) == 0 {
break tsr & ok_mask(idx) == 0;
}
}
}
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
let tsr = self.registers().tsr.read();
let mailbox_empty = match mailbox {
Mailbox::Mailbox0 => tsr.tme0().bit_is_set(),
Mailbox::Mailbox1 => tsr.tme1().bit_is_set(),
Mailbox::Mailbox2 => tsr.tme2().bit_is_set(),
};
if mailbox_empty {
false
} else {
self.abort_by_index(mailbox as usize)
}
}
pub fn is_idle(&self) -> bool {
let can = self.registers();
let tsr = can.tsr.read();
tsr.tme0().bit_is_set() && tsr.tme1().bit_is_set() && tsr.tme2().bit_is_set()
}
pub fn clear_interrupt_flags(&mut self) {
let can = self.registers();
can.tsr
.write(|w| w.rqcp2().set_bit().rqcp1().set_bit().rqcp0().set_bit());
}
}
pub struct Rx0<I> {
_can: PhantomData<I>,
}
impl<I> Rx0<I>
where
I: Instance,
{
unsafe fn conjure() -> Self {
Self { _can: PhantomData }
}
unsafe fn conjure_by_ref<'a>() -> &'a mut Self {
[()][core::mem::size_of::<Self>()];
&mut *NonNull::dangling().as_ptr()
}
pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> {
receive_fifo(self.registers(), 0)
}
fn registers(&self) -> &RegisterBlock {
unsafe { &*I::REGISTERS }
}
}
pub struct Rx1<I> {
_can: PhantomData<I>,
}
impl<I> Rx1<I>
where
I: Instance,
{
unsafe fn conjure() -> Self {
Self { _can: PhantomData }
}
unsafe fn conjure_by_ref<'a>() -> &'a mut Self {
[()][core::mem::size_of::<Self>()];
&mut *NonNull::dangling().as_ptr()
}
pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> {
receive_fifo(self.registers(), 1)
}
fn registers(&self) -> &RegisterBlock {
unsafe { &*I::REGISTERS }
}
}
fn receive_fifo(can: &RegisterBlock, fifo_nr: usize) -> nb::Result<Frame, OverrunError> {
assert!(fifo_nr < 2);
let rfr = &can.rfr[fifo_nr];
let rx = &can.rx[fifo_nr];
let rfr_read = rfr.read();
if rfr_read.fmp().bits() == 0 {
return Err(nb::Error::WouldBlock);
}
if rfr_read.fovr().bit_is_set() {
rfr.write(|w| w.fovr().set_bit());
return Err(nb::Error::Other(OverrunError { _priv: () }));
}
let mut frame = Frame {
id: IdReg(rx.rir.read().bits()),
data: [0; 8].into(),
};
frame.data[0..4].copy_from_slice(&rx.rdlr.read().bits().to_ne_bytes());
frame.data[4..8].copy_from_slice(&rx.rdhr.read().bits().to_ne_bytes());
frame.data.len = rx.rdtr.read().dlc().bits();
rfr.write(|w| w.rfom().set_bit());
Ok(frame)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))]
pub enum Fifo {
Fifo0 = 0,
Fifo1 = 1,
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))]
pub enum Mailbox {
Mailbox0 = 0,
Mailbox1 = 1,
Mailbox2 = 2,
}
pub struct TransmitStatus {
dequeued_frame: Option<Frame>,
mailbox: Mailbox,
}
impl TransmitStatus {
#[inline]
pub fn dequeued_frame(&self) -> Option<&Frame> {
self.dequeued_frame.as_ref()
}
#[inline]
pub fn mailbox(&self) -> Mailbox {
self.mailbox
}
}