#![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()),
}
}
}
#[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 {
self.is_extended_format()
}
fn is_remote_frame(&self) -> bool {
self.is_remote_request()
}
fn id(&self) -> embedded_can::Id {
self.identifier().into()
}
fn dlc(&self) -> usize {
self.data_length_code()
}
fn data(&self) -> &[u8] {
self.data()
}
}
#[derive(Clone, Copy)]
pub struct EspTwaiFrame {
bytes: [u8; 13],
}
impl EspTwaiFrame {
#[inline(always)]
fn info(&self) -> u8 {
self.bytes[0]
}
#[inline(always)]
fn is_extended_format(&self) -> bool {
self.info() & (0b1 << 7) != 0
}
pub fn is_remote_request(&self) -> bool {
self.info() & (0b1 << 6) != 0
}
pub fn is_self_reception(&self) -> bool {
self.info() & (0b1 << 4) != 0
}
pub fn data_length_code(&self) -> usize {
(self.info() & 0b1111) as usize
}
pub fn data_length(&self) -> usize {
match self.is_remote_request() {
true => 0,
false => core::cmp::min(self.data_length_code(), 8),
}
}
#[inline]
pub fn identifier(&self) -> Id {
let bytes = self.bytes;
match self.is_extended_format() {
false => {
let raw_id: u16 = ((bytes[1] as u16) << 3) | ((bytes[2] as u16) >> 5);
unsafe { StandardId::new_unchecked(raw_id).into() }
}
true => {
let raw_id: u32 = ((bytes[1] as u32) << 21)
| ((bytes[2] as u32) << 13)
| ((bytes[3] as u32) << 5)
| ((bytes[4] as u32) >> 3);
unsafe { ExtendedId::new_unchecked(raw_id).into() }
}
}
}
#[inline(always)]
fn data_offset(&self) -> usize {
match self.is_extended_format() {
false => 0x3,
true => 0x5,
}
}
#[inline]
pub fn data(&self) -> &[u8] {
let data_start = self.data_offset();
let data_end = data_start + self.data_length();
&self.bytes[data_start..data_end]
}
fn as_slice(&self) -> &[u8] {
let len = self.data_offset() + self.data_length();
&self.bytes[0..len]
}
pub(super) fn new_from_registers(register_block: &RegisterBlock) -> Self {
let mut bytes: [u8; 13] = [0; 13];
unsafe {
copy_from_data_register(&mut bytes, register_block.data(0).as_ptr());
}
Self { bytes }
}
fn new_from_parameters(
id: impl Into<Id>,
remote_request: bool,
self_reception: bool,
dlc: usize,
data: &[u8],
) -> Result<Self, EspTwaiError> {
let data_len = data.len();
if data_len > 8 || (remote_request & (data_len > 0)) {
return Err(EspTwaiError::InvalidDataLength(data_len as u8));
}
if dlc > 15 || ((data_len < 8) & (dlc != data_len)) || ((data_len == 8) & (dlc < 8)) {
return Err(EspTwaiError::NonCompliantDlc(dlc as u8));
}
let mut bytes = [0u8; 13];
let (extended_format, data_start): (u8, usize) = match id.into() {
Id::Standard(id) => {
let raw = id.as_raw();
bytes[1] = (raw >> 3) as u8;
bytes[2] = (raw << 5) as u8;
(0, 3)
}
Id::Extended(id) => {
let raw = id.as_raw();
bytes[1] = (raw >> 21) as u8;
bytes[2] = (raw >> 13) as u8;
bytes[3] = (raw >> 5) as u8;
bytes[4] = (raw << 3) as u8;
(1, 5)
}
};
let ff = extended_format << 7;
let rtr = (remote_request as u8) << 6;
let sr = (self_reception as u8) << 4;
let dlc = (dlc as u8) & 0b1111;
bytes[0] = ff | rtr | sr | dlc;
let data_end = data_start + data_len;
bytes[data_start..data_end].copy_from_slice(data);
Ok(Self { bytes })
}
pub fn new(id: impl Into<Id>, data: &[u8]) -> Option<Self> {
Self::new_from_parameters(id.into(), false, false, data.len(), data).ok()
}
pub fn new_remote(id: impl Into<Id>, dlc: usize) -> Option<Self> {
Self::new_from_parameters(id.into(), true, false, dlc, &[]).ok()
}
pub fn new_self_reception(id: impl Into<Id>, data: &[u8]) -> Option<Self> {
Self::new_from_parameters(id.into(), false, true, data.len(), data).ok()
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for EspTwaiFrame {
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(
f,
"EspTwaiFrame {{ id: {1=u32}, EFF: {0=7..8}, RTR: {0=6..7}, SR: {0=4..5}, DLC: {0=0..4}, data: {2=[u8]:#x}, raw: {3=[u8]:#x} }}",
self.info(),
match self.identifier() {
Id::Standard(id) => id.as_raw() as u32,
Id::Extended(id) => id.as_raw(),
},
self.data(),
self.as_slice(),
);
}
}
impl core::fmt::Debug for EspTwaiFrame {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("EspTwaiFrame")
.field(
"id",
&match self.identifier() {
Id::Standard(id) => id.as_raw() as u32,
Id::Extended(id) => id.as_raw(),
},
)
.field("EFF", &(self.is_extended_format() as u8))
.field("RTR", &(self.is_remote_request() as u8))
.field("SR", &(self.is_self_reception() as u8))
.field("DLC", &self.data_length_code())
.field("data", &format_args!("{:02x?}", self.data()))
.field("raw", &format_args!("{:02x?}", self.as_slice()))
.finish()
}
}
#[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)))]
{
assert!(crate::soc::clocks::apb_clk_frequency() == 80_000_000);
}
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()
}
#[instability::unstable]
pub fn initiate_recovery(&mut self) {
if self.is_bus_off() {
self.regs().mode().modify(|_, w| w.reset_mode().set_bit());
self.regs().mode().modify(|_, w| w.reset_mode().clear_bit());
}
}
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_clear() {
if is_error_passive(self.regs()) {
self.regs().cmd().write(|w| w.abort_tx().set_bit());
return nb::Result::Err(nb::Error::Other(EspTwaiError::TransmissionAborted));
}
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_clear() {
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,
)));
}
let frame = EspTwaiFrame::new_from_registers(self.regs());
release_receive_fifo(self.regs());
Ok(frame)
}
}
#[derive(Debug, EnumSetType)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
#[instability::unstable]
pub enum TwaiInterrupt {
Receive,
Transmit,
BusError,
ArbitrationLost,
ErrorPassive,
ErrorWarning,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EspTwaiError {
BusOff,
TransmissionAborted,
NonCompliantDlc(u8),
InvalidDataLength(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),
TwaiInterrupt::ErrorWarning => w.err_warn_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 release_receive_fifo(register_block: &RegisterBlock) {
register_block.cmd().write(|w| w.release_buf().set_bit());
}
fn is_error_passive(register_block: &RegisterBlock) -> bool {
register_block.tx_err_cnt().read().tx_err_cnt().bits() >= 128
|| register_block.rx_err_cnt().read().rx_err_cnt().bits() >= 128
}
fn write_frame(register_block: &RegisterBlock, frame: &EspTwaiFrame) {
unsafe {
copy_to_data_register(register_block.data(0).as_ptr(), frame.as_slice());
}
match frame.is_self_reception() {
false => register_block.cmd().write(|w| w.tx_req().set_bit()),
true => register_block.cmd().write(|w| w.self_rx_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_select! {
any(esp32, esp32c3, esp32s2, esp32s3) => InputSignal::TWAI_RX,
_ => InputSignal::TWAI0_RX,
}
}
fn output_signal(&self) -> OutputSignal {
cfg_select! {
any(esp32, esp32c3, esp32s2, esp32s3) => OutputSignal::TWAI_TX,
_ => 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::*;
use crate::rtc_cntl::WakeLock;
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,
_wake_lock: WakeLock,
}
impl<'d, 'f> TransmitFuture<'d, 'f> {
pub fn new(twai: AnyTwai<'d>, frame: &'f EspTwaiFrame) -> Self {
Self {
twai,
frame,
in_flight: false,
_wake_lock: WakeLock::new(),
}
}
}
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_clear() {
if is_error_passive(regs) {
regs.cmd().write(|w| w.abort_tx().set_bit());
return Poll::Ready(Err(EspTwaiError::TransmissionAborted));
}
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 int_raw = register_block.int_raw().read();
let int_ena_reg = register_block.int_ena();
let int_ena = int_ena_reg.read();
if int_raw.err_warn_int_st().bit_is_set() {
let status = register_block.status().read();
if status.bus_off_st().bit_is_set() && status.err_st().bit_is_set() {
register_block.cmd().write(|w| w.abort_tx().set_bit());
let _ = async_state.rx_queue.try_send(Err(EspTwaiError::BusOff));
async_state.tx_waker.wake();
async_state.err_waker.wake();
}
}
if int_raw.rx_int_st().bit_is_set() {
let status_reg = register_block.status();
let rx_queue = &async_state.rx_queue;
while register_block
.rx_message_cnt()
.read()
.rx_message_counter()
.bits()
> 0
{
let msg = if status_reg.read().miss_st().bit_is_set() {
release_receive_fifo(register_block);
Err(EspTwaiError::EmbeddedHAL(ErrorKind::Overrun))
} else {
let frame = EspTwaiFrame::new_from_registers(register_block);
release_receive_fifo(register_block);
Ok(frame)
};
if rx_queue.try_send(msg).is_err() {
break;
}
}
}
if int_raw.tx_int_st().bit_is_set() {
async_state.tx_waker.wake();
}
if int_raw.err_warn_int_st().bit_is_set()
|| int_raw.err_passive_int_st().bit_is_set()
|| int_raw.bus_err_int_st().bit_is_set()
{
let _ = register_block.err_code_cap().read();
async_state.err_waker.wake();
async_state.tx_waker.wake();
}
unsafe {
int_ena_reg.modify(|_, w| w.bits(int_ena.bits() & (!int_raw.bits() | 1)));
}
}
}