#![cfg_attr(docsrs, procmacros::doc_replace)]
#, "/api-reference/peripherals/twai.html#twai-protocol-summary)")]
use core::marker::PhantomData;
use enumset::{EnumSet, EnumSetType};
use procmacros::handler;
use self::filter::{Filter, FilterType};
use crate::{
Async,
Blocking,
DriverMode,
gpio::{
DriveMode,
InputConfig,
InputSignal,
OutputConfig,
OutputSignal,
Pull,
interconnect::{PeripheralInput, PeripheralOutput},
},
interrupt::InterruptHandler,
pac::twai0::RegisterBlock,
system::{Cpu, PeripheralGuard},
twai::filter::SingleStandardFilter,
};
pub mod filter;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[non_exhaustive]
pub enum ErrorKind {
Overrun,
Bit,
Stuff,
Crc,
Form,
Acknowledge,
Other,
}
macro_rules! impl_display {
($($kind:ident => $msg:expr),* $(,)?) => {
impl core::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
$(Self::$kind => write!(f, $msg)),*
}
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for ErrorKind {
fn format(&self, f: defmt::Formatter<'_>) {
match self {
$(Self::$kind => defmt::write!(f, $msg)),*
}
}
}
};
}
impl_display! {
Overrun => "The peripheral receive buffer was overrun",
Bit => "Bit value that is monitored differs from the bit value sent",
Stuff => "Sixth consecutive equal bits detected",
Crc => "Calculated CRC sequence does not equal the received one",
Form => "A fixed-form bit field contains one or more illegal bits",
Acknowledge => "Transmitted frame was not acknowledged",
Other => "A different error occurred. The original error may contain more information",
}
#[instability::unstable]
impl From<ErrorKind> for embedded_can::ErrorKind {
fn from(value: ErrorKind) -> Self {
match value {
ErrorKind::Overrun => embedded_can::ErrorKind::Overrun,
ErrorKind::Bit => embedded_can::ErrorKind::Bit,
ErrorKind::Stuff => embedded_can::ErrorKind::Stuff,
ErrorKind::Crc => embedded_can::ErrorKind::Crc,
ErrorKind::Form => embedded_can::ErrorKind::Form,
ErrorKind::Acknowledge => embedded_can::ErrorKind::Acknowledge,
ErrorKind::Other => embedded_can::ErrorKind::Other,
}
}
}
#[instability::unstable]
impl embedded_can::Error for ErrorKind {
fn kind(&self) -> embedded_can::ErrorKind {
(*self).into()
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TwaiMode {
Normal,
SelfTest,
ListenOnly,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StandardId(u16);
impl StandardId {
pub const ZERO: Self = StandardId(0);
pub const MAX: Self = StandardId(0x7FF);
#[inline]
pub fn new(raw: u16) -> Option<Self> {
if raw <= 0x7FF {
Some(StandardId(raw))
} else {
None
}
}
#[inline]
pub const unsafe fn new_unchecked(raw: u16) -> Self {
StandardId(raw)
}
#[inline]
pub fn as_raw(&self) -> u16 {
self.0
}
}
#[instability::unstable]
impl From<StandardId> for embedded_can::StandardId {
fn from(value: StandardId) -> Self {
embedded_can::StandardId::new(value.as_raw()).unwrap()
}
}
#[instability::unstable]
impl From<embedded_can::StandardId> for StandardId {
fn from(value: embedded_can::StandardId) -> Self {
StandardId::new(value.as_raw()).unwrap()
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ExtendedId(u32);
impl ExtendedId {
pub const ZERO: Self = ExtendedId(0);
pub const MAX: Self = ExtendedId(0x1FFF_FFFF);
#[inline]
pub fn new(raw: u32) -> Option<Self> {
if raw <= 0x1FFF_FFFF {
Some(ExtendedId(raw))
} else {
None
}
}
#[inline]
pub const unsafe fn new_unchecked(raw: u32) -> Self {
ExtendedId(raw)
}
#[inline]
pub fn as_raw(&self) -> u32 {
self.0
}
pub fn standard_id(&self) -> StandardId {
StandardId((self.0 >> 18) as u16)
}
}
#[instability::unstable]
impl From<ExtendedId> for embedded_can::ExtendedId {
fn from(value: ExtendedId) -> Self {
embedded_can::ExtendedId::new(value.0).unwrap()
}
}
#[instability::unstable]
impl From<embedded_can::ExtendedId> for ExtendedId {
fn from(value: embedded_can::ExtendedId) -> Self {
ExtendedId::new(value.as_raw()).unwrap()
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Id {
Standard(StandardId),
Extended(ExtendedId),
}
impl From<StandardId> for Id {
#[inline]
fn from(id: StandardId) -> Self {
Id::Standard(id)
}
}
impl From<ExtendedId> for Id {
#[inline]
fn from(id: ExtendedId) -> Self {
Id::Extended(id)
}
}
#[instability::unstable]
impl From<Id> for embedded_can::Id {
fn from(value: Id) -> Self {
match value {
Id::Standard(id) => embedded_can::Id::Standard(id.into()),
Id::Extended(id) => embedded_can::Id::Extended(id.into()),
}
}
}
#[instability::unstable]
impl From<embedded_can::Id> for Id {
fn from(value: embedded_can::Id) -> Self {
match value {
embedded_can::Id::Standard(id) => Id::Standard(id.into()),
embedded_can::Id::Extended(id) => Id::Extended(id.into()),
}
}
}
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct EspTwaiFrame {
id: Id,
dlc: usize,
data: [u8; 8],
is_remote: bool,
self_reception: bool,
}
impl EspTwaiFrame {
pub fn new(id: impl Into<Id>, data: &[u8]) -> Option<Self> {
if data.len() > 8 {
return None;
}
let mut d: [u8; 8] = [0; 8];
d[..data.len()].copy_from_slice(data);
Some(EspTwaiFrame {
id: id.into(),
data: d,
dlc: data.len(),
is_remote: false,
self_reception: false,
})
}
pub fn new_remote(id: impl Into<Id>, dlc: usize) -> Option<Self> {
if dlc > 8 {
return None;
}
Some(EspTwaiFrame {
id: id.into(),
data: [0; 8],
dlc,
is_remote: true,
self_reception: false,
})
}
pub fn new_self_reception(id: impl Into<Id>, data: &[u8]) -> Option<Self> {
if data.len() > 8 {
return None;
}
let mut d: [u8; 8] = [0; 8];
d[..data.len()].copy_from_slice(data);
Some(EspTwaiFrame {
id: id.into(),
data: d,
dlc: data.len(),
is_remote: false,
self_reception: true,
})
}
unsafe fn new_from_data_registers(
id: impl Into<Id>,
registers: *const u32,
dlc: usize,
) -> Self {
let mut data: [u8; 8] = [0; 8];
unsafe {
copy_from_data_register(&mut data[..dlc], registers);
}
Self {
id: id.into(),
data,
dlc,
is_remote: false,
self_reception: false,
}
}
}
#[instability::unstable]
impl embedded_can::Frame for EspTwaiFrame {
fn new(id: impl Into<embedded_can::Id>, data: &[u8]) -> Option<Self> {
Self::new(id.into(), data)
}
fn new_remote(id: impl Into<embedded_can::Id>, dlc: usize) -> Option<Self> {
Self::new_remote(id.into(), dlc)
}
fn is_extended(&self) -> bool {
matches!(self.id, Id::Extended(_))
}
fn is_remote_frame(&self) -> bool {
self.is_remote
}
fn id(&self) -> embedded_can::Id {
self.id.into()
}
fn dlc(&self) -> usize {
self.dlc
}
fn data(&self) -> &[u8] {
match self.is_remote {
true => &[],
false => &self.data[0..self.dlc],
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TimingConfig {
pub baud_rate_prescaler: u16,
pub sync_jump_width: u8,
pub tseg_1: u8,
pub tseg_2: u8,
pub triple_sample: bool,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BaudRate {
B125K,
B250K,
B500K,
B1000K,
Custom(TimingConfig),
}
impl BaudRate {
const fn timing(self) -> TimingConfig {
#[cfg(not(esp32h2))]
let timing = match self {
Self::B125K => TimingConfig {
baud_rate_prescaler: 32,
sync_jump_width: 3,
tseg_1: 15,
tseg_2: 4,
triple_sample: false,
},
Self::B250K => TimingConfig {
baud_rate_prescaler: 16,
sync_jump_width: 3,
tseg_1: 15,
tseg_2: 4,
triple_sample: false,
},
Self::B500K => TimingConfig {
baud_rate_prescaler: 8,
sync_jump_width: 3,
tseg_1: 15,
tseg_2: 4,
triple_sample: false,
},
Self::B1000K => TimingConfig {
baud_rate_prescaler: 4,
sync_jump_width: 3,
tseg_1: 15,
tseg_2: 4,
triple_sample: false,
},
Self::Custom(timing_config) => timing_config,
};
#[cfg(esp32h2)]
let timing = match self {
Self::B125K => TimingConfig {
baud_rate_prescaler: 16,
sync_jump_width: 3,
tseg_1: 11,
tseg_2: 4,
triple_sample: false,
},
Self::B250K => TimingConfig {
baud_rate_prescaler: 8,
sync_jump_width: 3,
tseg_1: 11,
tseg_2: 4,
triple_sample: false,
},
Self::B500K => TimingConfig {
baud_rate_prescaler: 4,
sync_jump_width: 3,
tseg_1: 11,
tseg_2: 4,
triple_sample: false,
},
Self::B1000K => TimingConfig {
baud_rate_prescaler: 2,
sync_jump_width: 3,
tseg_1: 11,
tseg_2: 4,
triple_sample: false,
},
Self::Custom(timing_config) => timing_config,
};
#[cfg(esp32c6)]
let timing = TimingConfig {
baud_rate_prescaler: timing.baud_rate_prescaler / 2,
..timing
};
timing
}
}
pub struct TwaiConfiguration<'d, Dm: DriverMode> {
twai: AnyTwai<'d>,
filter: Option<(FilterType, [u8; 8])>,
phantom: PhantomData<Dm>,
mode: TwaiMode,
_guard: PeripheralGuard,
}
impl<'d, Dm> TwaiConfiguration<'d, Dm>
where
Dm: DriverMode,
{
fn new_internal(
twai: AnyTwai<'d>,
rx_pin: impl PeripheralInput<'d>,
tx_pin: impl PeripheralOutput<'d>,
baud_rate: BaudRate,
no_transceiver: bool,
mode: TwaiMode,
) -> Self {
let rx_pin = rx_pin.into();
let tx_pin = tx_pin.into();
let guard = PeripheralGuard::new(twai.peripheral());
let mut this = TwaiConfiguration {
twai,
filter: None, phantom: PhantomData,
mode,
_guard: guard,
};
this.set_filter(
const { SingleStandardFilter::new(b"xxxxxxxxxxx", b"x", [b"xxxxxxxx", b"xxxxxxxx"]) },
);
this.regs().mode().write(|w| w.reset_mode().set_bit());
#[cfg(esp32)]
this.regs()
.clock_divider()
.modify(|_, w| w.ext_mode().set_bit());
let tx_config = if no_transceiver {
OutputConfig::default()
.with_drive_mode(DriveMode::OpenDrain)
.with_pull(Pull::Up)
} else {
OutputConfig::default()
};
tx_pin.apply_output_config(&tx_config);
rx_pin.apply_input_config(&InputConfig::default().with_pull(if no_transceiver {
Pull::Up
} else {
Pull::None
}));
tx_pin.set_output_enable(true);
rx_pin.set_input_enable(true);
this.twai.output_signal().connect_to(&tx_pin);
this.twai.input_signal().connect_to(&rx_pin);
this.set_mode(TwaiMode::ListenOnly);
this.regs()
.tx_err_cnt()
.write(|w| unsafe { w.tx_err_cnt().bits(0) });
this.regs()
.rx_err_cnt()
.write(|w| unsafe { w.rx_err_cnt().bits(0) });
this.regs()
.err_warning_limit()
.write(|w| unsafe { w.err_warning_limit().bits(96) });
this.set_baud_rate(baud_rate);
this
}
fn regs(&self) -> &RegisterBlock {
self.twai.register_block()
}
fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) {
for core in Cpu::other() {
crate::interrupt::disable(core, self.twai.interrupt());
}
crate::interrupt::bind_handler(self.twai.interrupt(), handler);
}
fn set_baud_rate(&mut self, baud_rate: BaudRate) {
#[cfg(not(any(esp32h2, esp32c6)))]
{
let apb_clock = crate::clock::Clocks::get().apb_clock;
assert!(apb_clock.as_mhz() == 80);
}
let timing = baud_rate.timing();
#[cfg_attr(not(esp32), allow(unused_mut))]
let mut prescaler = timing.baud_rate_prescaler;
#[cfg(esp32)]
{
if timing.baud_rate_prescaler > 128 {
self.regs().int_ena().modify(|_, w| w.brp_div().set_bit());
prescaler = timing.baud_rate_prescaler / 2;
} else {
self.regs().int_ena().modify(|_, w| w.brp_div().clear_bit());
}
}
let prescale = (prescaler / 2) - 1;
let sjw = timing.sync_jump_width - 1;
let tseg_1 = timing.tseg_1 - 1;
let tseg_2 = timing.tseg_2 - 1;
let triple_sample = timing.triple_sample;
self.regs().bus_timing_0().modify(|_, w| unsafe {
w.baud_presc().bits(prescale as _);
w.sync_jump_width().bits(sjw)
});
self.regs().bus_timing_1().modify(|_, w| unsafe {
w.time_seg1().bits(tseg_1);
w.time_seg2().bits(tseg_2);
w.time_samp().bit(triple_sample)
});
self.regs()
.clock_divider()
.modify(|_, w| w.clock_off().set_bit());
}
pub fn set_filter(&mut self, filter: impl Filter) {
self.filter = Some((filter.filter_type(), filter.to_registers()));
}
fn apply_filter(&self) {
let Some((filter_type, registers)) = self.filter.as_ref() else {
return;
};
self.regs()
.mode()
.modify(|_, w| w.rx_filter_mode().bit(*filter_type == FilterType::Single));
unsafe {
copy_to_data_register(self.regs().data(0).as_ptr(), registers);
}
}
pub fn set_error_warning_limit(&mut self, limit: u8) {
self.regs()
.err_warning_limit()
.write(|w| unsafe { w.err_warning_limit().bits(limit) });
}
fn set_mode(&self, mode: TwaiMode) {
self.regs().mode().modify(|_, w| {
w.self_test_mode().bit(mode == TwaiMode::SelfTest);
w.listen_only_mode().bit(mode == TwaiMode::ListenOnly)
});
}
pub fn start(self) -> Twai<'d, Dm> {
self.apply_filter();
self.set_mode(self.mode);
self.regs()
.tx_err_cnt()
.write(|w| unsafe { w.tx_err_cnt().bits(0) });
let rec =
if cfg!(any(esp32, esp32s2, esp32s3, esp32c3)) && self.mode == TwaiMode::ListenOnly {
128
} else {
0
};
self.regs()
.rx_err_cnt()
.write(|w| unsafe { w.rx_err_cnt().bits(rec) });
let _ = self.regs().int_raw().read();
self.regs().mode().modify(|_, w| w.reset_mode().clear_bit());
Twai {
rx: TwaiRx {
twai: unsafe { self.twai.clone_unchecked() },
phantom: PhantomData,
_guard: PeripheralGuard::new(self.twai.peripheral()),
},
tx: TwaiTx {
twai: unsafe { self.twai.clone_unchecked() },
phantom: PhantomData,
_guard: PeripheralGuard::new(self.twai.peripheral()),
},
twai: unsafe { self.twai.clone_unchecked() },
phantom: PhantomData,
}
}
}
impl<'d> TwaiConfiguration<'d, Blocking> {
pub fn new(
peripheral: impl Instance + 'd,
rx_pin: impl PeripheralInput<'d>,
tx_pin: impl PeripheralOutput<'d>,
baud_rate: BaudRate,
mode: TwaiMode,
) -> Self {
Self::new_internal(peripheral.degrade(), rx_pin, tx_pin, baud_rate, false, mode)
}
pub fn new_no_transceiver(
peripheral: impl Instance + 'd,
rx_pin: impl PeripheralInput<'d>,
tx_pin: impl PeripheralOutput<'d>,
baud_rate: BaudRate,
mode: TwaiMode,
) -> Self {
Self::new_internal(peripheral.degrade(), rx_pin, tx_pin, baud_rate, true, mode)
}
pub fn into_async(mut self) -> TwaiConfiguration<'d, Async> {
self.set_interrupt_handler(self.twai.async_handler());
TwaiConfiguration {
twai: self.twai,
filter: self.filter,
phantom: PhantomData,
mode: self.mode,
_guard: self._guard,
}
}
#[instability::unstable]
pub fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
self.internal_set_interrupt_handler(handler);
}
}
impl<'d> TwaiConfiguration<'d, Async> {
pub fn into_blocking(self) -> TwaiConfiguration<'d, Blocking> {
use crate::{interrupt, system::Cpu};
interrupt::disable(Cpu::current(), self.twai.interrupt());
TwaiConfiguration {
twai: self.twai,
filter: self.filter,
phantom: PhantomData,
mode: self.mode,
_guard: self._guard,
}
}
}
impl crate::private::Sealed for TwaiConfiguration<'_, Blocking> {}
#[instability::unstable]
impl crate::interrupt::InterruptConfigurable for TwaiConfiguration<'_, Blocking> {
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
self.internal_set_interrupt_handler(handler);
}
}
pub struct Twai<'d, Dm: DriverMode> {
twai: AnyTwai<'d>,
tx: TwaiTx<'d, Dm>,
rx: TwaiRx<'d, Dm>,
phantom: PhantomData<Dm>,
}
impl<'d, Dm> Twai<'d, Dm>
where
Dm: DriverMode,
{
fn regs(&self) -> &RegisterBlock {
self.twai.register_block()
}
fn mode(&self) -> TwaiMode {
let mode = self.regs().mode().read();
if mode.self_test_mode().bit_is_set() {
TwaiMode::SelfTest
} else if mode.listen_only_mode().bit_is_set() {
TwaiMode::ListenOnly
} else {
TwaiMode::Normal
}
}
pub fn stop(self) -> TwaiConfiguration<'d, Dm> {
self.regs().mode().modify(|_, w| w.reset_mode().set_bit());
let mode = self.mode();
let guard = PeripheralGuard::new(self.twai.peripheral());
TwaiConfiguration {
twai: self.twai,
filter: None, phantom: PhantomData,
mode,
_guard: guard,
}
}
pub fn receive_error_count(&self) -> u8 {
self.regs().rx_err_cnt().read().rx_err_cnt().bits()
}
pub fn transmit_error_count(&self) -> u8 {
self.regs().tx_err_cnt().read().tx_err_cnt().bits()
}
pub fn is_bus_off(&self) -> bool {
self.regs().status().read().bus_off_st().bit_is_set()
}
pub fn num_available_messages(&self) -> u8 {
self.regs()
.rx_message_cnt()
.read()
.rx_message_counter()
.bits()
}
pub fn clear_receive_fifo(&self) {
while self.num_available_messages() > 0 {
release_receive_fifo(self.regs());
}
}
pub fn transmit(&mut self, frame: &EspTwaiFrame) -> nb::Result<(), EspTwaiError> {
self.tx.transmit(frame)
}
pub fn receive(&mut self) -> nb::Result<EspTwaiFrame, EspTwaiError> {
self.rx.receive()
}
pub fn split(self) -> (TwaiRx<'d, Dm>, TwaiTx<'d, Dm>) {
(self.rx, self.tx)
}
}
pub struct TwaiTx<'d, Dm: DriverMode> {
twai: AnyTwai<'d>,
phantom: PhantomData<Dm>,
_guard: PeripheralGuard,
}
impl<Dm> TwaiTx<'_, Dm>
where
Dm: DriverMode,
{
fn regs(&self) -> &RegisterBlock {
self.twai.register_block()
}
pub fn transmit(&mut self, frame: &EspTwaiFrame) -> nb::Result<(), EspTwaiError> {
let status = self.regs().status().read();
if status.bus_off_st().bit_is_set() {
return nb::Result::Err(nb::Error::Other(EspTwaiError::BusOff));
}
if !status.tx_buf_st().bit_is_set() {
return nb::Result::Err(nb::Error::WouldBlock);
}
write_frame(self.regs(), frame);
Ok(())
}
}
pub struct TwaiRx<'d, Dm: DriverMode> {
twai: AnyTwai<'d>,
phantom: PhantomData<Dm>,
_guard: PeripheralGuard,
}
impl<Dm> TwaiRx<'_, Dm>
where
Dm: DriverMode,
{
fn regs(&self) -> &RegisterBlock {
self.twai.register_block()
}
pub fn receive(&mut self) -> nb::Result<EspTwaiFrame, EspTwaiError> {
let status = self.regs().status().read();
if status.bus_off_st().bit_is_set() {
return nb::Result::Err(nb::Error::Other(EspTwaiError::BusOff));
}
if !status.rx_buf_st().bit_is_set() {
return nb::Result::Err(nb::Error::WouldBlock);
}
if status.miss_st().bit_is_set() {
return nb::Result::Err(nb::Error::Other(EspTwaiError::EmbeddedHAL(
ErrorKind::Overrun,
)));
}
Ok(read_frame(self.regs())?)
}
}
#[derive(Debug, EnumSetType)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
#[instability::unstable]
pub enum TwaiInterrupt {
Receive,
Transmit,
BusError,
ArbitrationLost,
ErrorPassive,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EspTwaiError {
BusOff,
NonCompliantDlc(u8),
EmbeddedHAL(ErrorKind),
}
#[instability::unstable]
impl embedded_can::Error for EspTwaiError {
fn kind(&self) -> embedded_can::ErrorKind {
if let Self::EmbeddedHAL(kind) = self {
(*kind).into()
} else {
embedded_can::ErrorKind::Other
}
}
}
#[inline(always)]
unsafe fn copy_from_data_register(dest: &mut [u8], src: *const u32) {
for (i, dest) in dest.iter_mut().enumerate() {
unsafe {
*dest = src.add(i).read_volatile() as u8;
}
}
}
#[inline(always)]
unsafe fn copy_to_data_register(dest: *mut u32, src: &[u8]) {
for (i, src) in src.iter().enumerate() {
unsafe {
dest.add(i).write_volatile(*src as u32);
}
}
}
#[instability::unstable]
impl<Dm> embedded_can::nb::Can for Twai<'_, Dm>
where
Dm: DriverMode,
{
type Frame = EspTwaiFrame;
type Error = EspTwaiError;
fn transmit(&mut self, frame: &Self::Frame) -> nb::Result<Option<Self::Frame>, Self::Error> {
self.tx.transmit(frame)?;
nb::Result::Ok(None)
}
fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error> {
self.rx.receive()
}
}
#[doc(hidden)]
pub trait PrivateInstance: crate::private::Sealed {
fn peripheral(&self) -> crate::system::Peripheral;
fn input_signal(&self) -> InputSignal;
fn output_signal(&self) -> OutputSignal;
fn interrupt(&self) -> crate::peripherals::Interrupt;
fn async_handler(&self) -> InterruptHandler;
fn register_block(&self) -> &RegisterBlock;
fn enable_interrupts(&self, interrupts: EnumSet<TwaiInterrupt>, enable: bool) {
self.register_block().int_ena().modify(|_, w| {
for interrupt in interrupts {
match interrupt {
TwaiInterrupt::Receive => w.rx_int_ena().bit(enable),
TwaiInterrupt::Transmit => w.tx_int_ena().bit(enable),
TwaiInterrupt::BusError => w.bus_err_int_ena().bit(enable),
TwaiInterrupt::ArbitrationLost => w.arb_lost_int_ena().bit(enable),
TwaiInterrupt::ErrorPassive => w.err_passive_int_ena().bit(enable),
};
}
w
});
}
fn listen(&mut self, interrupts: impl Into<EnumSet<TwaiInterrupt>>) {
self.enable_interrupts(interrupts.into(), true);
}
fn unlisten(&mut self, interrupts: impl Into<EnumSet<TwaiInterrupt>>) {
self.enable_interrupts(interrupts.into(), false);
}
fn async_state(&self) -> &asynch::TwaiAsyncState;
}
fn read_frame(register_block: &RegisterBlock) -> Result<EspTwaiFrame, EspTwaiError> {
let data_0 = register_block.data(0).read().tx_byte().bits();
let is_standard_format = data_0 & (0b1 << 7) == 0;
let is_data_frame = data_0 & (0b1 << 6) == 0;
let self_reception = data_0 & (0b1 << 4) != 0;
let dlc = data_0 & 0b1111;
if dlc > 8 {
release_receive_fifo(register_block);
return Err(EspTwaiError::NonCompliantDlc(dlc));
}
let dlc = dlc as usize;
let (id, data_ptr) = if is_standard_format {
let data_1 = register_block.data(1).read().tx_byte().bits();
let data_2 = register_block.data(2).read().tx_byte().bits();
let raw_id: u16 = ((data_1 as u16) << 3) | ((data_2 as u16) >> 5);
let id = Id::from(StandardId::new(raw_id).unwrap());
(id, register_block.data(3).as_ptr())
} else {
let data_1 = register_block.data(1).read().tx_byte().bits();
let data_2 = register_block.data(2).read().tx_byte().bits();
let data_3 = register_block.data(3).read().tx_byte().bits();
let data_4 = register_block.data(4).read().tx_byte().bits();
let raw_id: u32 = ((data_1 as u32) << 21)
| ((data_2 as u32) << 13)
| ((data_3 as u32) << 5)
| ((data_4 as u32) >> 3);
let id = Id::from(ExtendedId::new(raw_id).unwrap());
(id, register_block.data(5).as_ptr())
};
let mut frame = if is_data_frame {
unsafe { EspTwaiFrame::new_from_data_registers(id, data_ptr, dlc) }
} else {
EspTwaiFrame::new_remote(id, dlc).unwrap()
};
frame.self_reception = self_reception;
release_receive_fifo(register_block);
Ok(frame)
}
fn release_receive_fifo(register_block: &RegisterBlock) {
register_block.cmd().write(|w| w.release_buf().set_bit());
}
fn write_frame(register_block: &RegisterBlock, frame: &EspTwaiFrame) {
let frame_format: u8 = matches!(frame.id, Id::Extended(_)) as u8;
let self_reception: u8 = frame.self_reception as u8;
let rtr_bit: u8 = frame.is_remote as u8;
let dlc_bits: u8 = frame.dlc as u8 & 0b1111;
let data_0: u8 = (frame_format << 7) | (rtr_bit << 6) | (self_reception << 4) | dlc_bits;
register_block
.data(0)
.write(|w| unsafe { w.tx_byte().bits(data_0) });
let data_ptr = match frame.id {
Id::Standard(id) => {
let id = id.as_raw();
register_block
.data(1)
.write(|w| unsafe { w.tx_byte().bits((id >> 3) as u8) });
register_block
.data(2)
.write(|w| unsafe { w.tx_byte().bits((id << 5) as u8) });
register_block.data(3).as_ptr()
}
Id::Extended(id) => {
let id = id.as_raw();
register_block
.data(1)
.write(|w| unsafe { w.tx_byte().bits((id >> 21) as u8) });
register_block
.data(2)
.write(|w| unsafe { w.tx_byte().bits((id >> 13) as u8) });
register_block
.data(3)
.write(|w| unsafe { w.tx_byte().bits((id >> 5) as u8) });
register_block
.data(4)
.write(|w| unsafe { w.tx_byte().bits((id << 3) as u8) });
register_block.data(5).as_ptr()
}
};
unsafe {
copy_to_data_register(
data_ptr,
match frame.is_remote {
true => &[], false => &frame.data[0..frame.dlc],
},
)
}
if frame.self_reception {
register_block.cmd().write(|w| w.self_rx_req().set_bit());
} else {
register_block.cmd().write(|w| w.tx_req().set_bit());
}
}
impl PrivateInstance for crate::peripherals::TWAI0<'_> {
fn peripheral(&self) -> crate::system::Peripheral {
crate::system::Peripheral::Twai0
}
fn input_signal(&self) -> InputSignal {
cfg_if::cfg_if! {
if #[cfg(any(esp32, esp32c3, esp32s2, esp32s3))] {
InputSignal::TWAI_RX
} else {
InputSignal::TWAI0_RX
}
}
}
fn output_signal(&self) -> OutputSignal {
cfg_if::cfg_if! {
if #[cfg(any(esp32, esp32c3, esp32s2, esp32s3))] {
OutputSignal::TWAI_TX
} else {
OutputSignal::TWAI0_TX
}
}
}
fn interrupt(&self) -> crate::peripherals::Interrupt {
crate::peripherals::Interrupt::TWAI0
}
fn async_handler(&self) -> InterruptHandler {
#[handler]
fn twai0() {
let twai = unsafe { crate::peripherals::TWAI0::steal() };
asynch::handle_interrupt(twai.register_block(), twai.async_state());
}
twai0
}
#[inline(always)]
fn register_block(&self) -> &RegisterBlock {
crate::peripherals::TWAI0::regs()
}
fn async_state(&self) -> &asynch::TwaiAsyncState {
static STATE: asynch::TwaiAsyncState = asynch::TwaiAsyncState::new();
&STATE
}
}
#[cfg(soc_has_twai1)]
impl PrivateInstance for crate::peripherals::TWAI1<'_> {
fn peripheral(&self) -> crate::system::Peripheral {
crate::system::Peripheral::Twai1
}
fn input_signal(&self) -> InputSignal {
InputSignal::TWAI1_RX
}
fn output_signal(&self) -> OutputSignal {
OutputSignal::TWAI1_TX
}
fn interrupt(&self) -> crate::peripherals::Interrupt {
crate::peripherals::Interrupt::TWAI1
}
fn async_handler(&self) -> InterruptHandler {
#[handler]
fn twai1() {
let twai = unsafe { crate::peripherals::TWAI1::steal() };
asynch::handle_interrupt(twai.register_block(), twai.async_state());
}
twai1
}
#[inline(always)]
fn register_block(&self) -> &RegisterBlock {
crate::peripherals::TWAI1::regs()
}
fn async_state(&self) -> &asynch::TwaiAsyncState {
static STATE: asynch::TwaiAsyncState = asynch::TwaiAsyncState::new();
&STATE
}
}
crate::any_peripheral! {
pub peripheral AnyTwai<'d> {
#[cfg(soc_has_twai0)]
Twai0(crate::peripherals::TWAI0<'d>),
#[cfg(soc_has_twai1)]
Twai1(crate::peripherals::TWAI1<'d>),
}
}
impl PrivateInstance for AnyTwai<'_> {
delegate::delegate! {
to match &self.0 {
#[cfg(soc_has_twai0)]
any::Inner::Twai0(twai) => twai,
#[cfg(soc_has_twai1)]
any::Inner::Twai1(twai) => twai,
} {
fn peripheral(&self) -> crate::system::Peripheral;
fn input_signal(&self) -> InputSignal;
fn output_signal(&self) -> OutputSignal;
fn interrupt(&self) -> crate::peripherals::Interrupt;
fn async_handler(&self) -> InterruptHandler;
fn register_block(&self) -> &RegisterBlock;
fn async_state(&self) -> &asynch::TwaiAsyncState;
}
}
}
pub trait Instance: PrivateInstance + any::Degrade {}
#[cfg(soc_has_twai0)]
impl Instance for crate::peripherals::TWAI0<'_> {}
#[cfg(soc_has_twai1)]
impl Instance for crate::peripherals::TWAI1<'_> {}
impl Instance for AnyTwai<'_> {}
mod asynch {
use core::{future::poll_fn, task::Poll};
use embassy_sync::{channel::Channel, waitqueue::AtomicWaker};
use esp_sync::RawMutex;
use super::*;
pub struct TwaiAsyncState {
pub tx_waker: AtomicWaker,
pub err_waker: AtomicWaker,
pub rx_queue: Channel<RawMutex, Result<EspTwaiFrame, EspTwaiError>, 32>,
}
impl Default for TwaiAsyncState {
fn default() -> Self {
Self::new()
}
}
impl TwaiAsyncState {
pub const fn new() -> Self {
Self {
tx_waker: AtomicWaker::new(),
err_waker: AtomicWaker::new(),
rx_queue: Channel::new(),
}
}
}
impl Twai<'_, Async> {
pub async fn transmit_async(&mut self, frame: &EspTwaiFrame) -> Result<(), EspTwaiError> {
self.tx.transmit_async(frame).await
}
pub async fn receive_async(&mut self) -> Result<EspTwaiFrame, EspTwaiError> {
self.rx.receive_async().await
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct TransmitFuture<'d, 'f> {
twai: AnyTwai<'d>,
frame: &'f EspTwaiFrame,
in_flight: bool,
}
impl<'d, 'f> TransmitFuture<'d, 'f> {
pub fn new(twai: AnyTwai<'d>, frame: &'f EspTwaiFrame) -> Self {
Self {
twai,
frame,
in_flight: false,
}
}
}
impl core::future::Future for TransmitFuture<'_, '_> {
type Output = Result<(), EspTwaiError>;
fn poll(
mut self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
self.twai.async_state().tx_waker.register(cx.waker());
self.twai.listen(EnumSet::all());
let regs = self.twai.register_block();
let status = regs.status().read();
if status.bus_off_st().bit_is_set() {
return Poll::Ready(Err(EspTwaiError::BusOff));
}
if !status.tx_buf_st().bit_is_set() {
return Poll::Pending;
}
if !self.in_flight {
write_frame(regs, self.frame);
self.in_flight = true;
return Poll::Pending;
}
Poll::Ready(Ok(()))
}
}
impl Drop for TransmitFuture<'_, '_> {
fn drop(&mut self) {
self.twai
.register_block()
.cmd()
.write(|w| w.abort_tx().set_bit());
}
}
impl TwaiTx<'_, Async> {
pub async fn transmit_async(&mut self, frame: &EspTwaiFrame) -> Result<(), EspTwaiError> {
TransmitFuture::new(self.twai.reborrow(), frame).await
}
}
impl TwaiRx<'_, Async> {
pub async fn receive_async(&mut self) -> Result<EspTwaiFrame, EspTwaiError> {
poll_fn(|cx| {
self.twai.async_state().err_waker.register(cx.waker());
self.twai.listen(EnumSet::all());
if let Poll::Ready(result) = self.twai.async_state().rx_queue.poll_receive(cx) {
return Poll::Ready(result);
}
let status = self.regs().status().read();
if status.bus_off_st().bit_is_set() {
return Poll::Ready(Err(EspTwaiError::BusOff));
}
Poll::Pending
})
.await
}
}
pub(super) fn handle_interrupt(register_block: &RegisterBlock, async_state: &TwaiAsyncState) {
let intr_status = register_block.int_raw().read();
let int_ena_reg = register_block.int_ena();
let tx_int_status = intr_status.tx_int_st();
let rx_int_status = intr_status.rx_int_st();
let intr_enable = int_ena_reg.read();
if tx_int_status.bit_is_set() {
async_state.tx_waker.wake();
}
if rx_int_status.bit_is_set() {
let status = register_block.status().read();
let rx_queue = &async_state.rx_queue;
if status.bus_off_st().bit_is_set() {
let _ = rx_queue.try_send(Err(EspTwaiError::BusOff));
if !status.tx_buf_st().bit_is_set() {
register_block.cmd().write(|w| w.abort_tx().set_bit());
async_state.tx_waker.wake();
}
}
if status.miss_st().bit_is_set() {
let _ = rx_queue.try_send(Err(EspTwaiError::EmbeddedHAL(ErrorKind::Overrun)));
release_receive_fifo(register_block);
} else {
match read_frame(register_block) {
Ok(frame) => {
let _ = rx_queue.try_send(Ok(frame));
}
Err(e) => warn!("Error reading frame: {:?}", e),
}
}
}
if intr_status.bits() & 0b10110100 > 0 {
let _ = register_block.err_code_cap().read();
async_state.err_waker.wake();
}
unsafe {
int_ena_reg.modify(|_, w| w.bits(intr_enable.bits() & (!intr_status.bits() | 1)));
}
}
}