From b7c6c26da812ec23dc1c831f1e201bda429a46c2 Mon Sep 17 00:00:00 2001 From: Guinea Wheek Date: Fri, 10 May 2024 15:35:56 -0700 Subject: [PATCH 1/5] add error interrupt support --- src/lib.rs | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 255a097..97c586c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,10 +109,11 @@ pub unsafe trait FilterOwner: Instance { /// This trait must only be implemented when there is actually an associated slave instance. pub unsafe trait MasterInstance: FilterOwner {} -// TODO: what to do with these? -/* -#[derive(Debug, Copy, Clone, Eq, PartialEq, Format)] -pub enum Error { +/// Enum of error status codes from the error status register. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub enum Error{ + None, Stuff, Form, Acknowledgement, @@ -120,7 +121,60 @@ pub enum Error { BitDominant, Crc, Software, -}*/ +} + +/// The peripheral's current error status. +/// +/// This is returned when clearing an error status interrupt. +#[derive(Clone, PartialEq, Eq)] +#[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] +pub struct ErrorStatus { + pub(crate) recv_count: u8, + pub(crate) txmt_count: u8, + pub(crate) code: Error, + pub(crate) bus_off: bool, + pub(crate) err_passive: bool, + pub(crate) err_warning: bool, +} + +impl ErrorStatus { + /// The receive error counter. + #[inline] + pub fn receive_counter(&self) -> u8 { + self.recv_count + } + + /// The transmit error counter. + #[inline] + pub fn transmit_counter(&self) -> u8 { + self.recv_count + } + + /// The last error code. + #[inline] + pub fn last_error(&self) -> Error { + self.code + } + + /// Returns true if the peripheral is currently in bus-off. + #[inline] + pub fn bus_off(&self) -> bool { + self.bus_off + } + + /// Returns true if the error passive limit has been reached. + #[inline] + pub fn error_passive(&self) -> bool { + self.err_passive + } + + /// Returns true if the error warning limit has been reached. + #[inline] + pub fn error_warning(&self) -> bool { + self.err_warning + } +} + /// Error that indicates that an incoming message has been lost due to buffer overrun. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -650,6 +704,35 @@ where while self.clear_request_completed_flag().is_some() {} } + /// Clears the error interrupt flag ([`Interrupt::Error`]). + /// + /// This will return an [`ErrorStatus`] containing information on the error. + pub fn clear_error_interrupt(&mut self) -> ErrorStatus { + let can = self.registers(); + let esr = can.esr.read(); + + let stat = ErrorStatus { + recv_count: esr.rec().bits, + txmt_count: esr.tec().bits, + code: (match esr.lec().bits { + 0b000 => Error::None, + 0b001 => Error::Stuff, + 0b010 => Error::Form, + 0b011 => Error::Acknowledgement, + 0b100 => Error::BitRecessive, + 0b101 => Error::BitDominant, + 0b110 => Error::Crc, + 0b111 => Error::Software, + _ => unreachable!(), + }), + bus_off: esr.boff().bits, + err_passive: esr.epvf().bits, + err_warning: esr.ewgf().bits + }; + can.msr.write(|w| w.erri().set_bit()); + stat + } + /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. /// /// Frames are transmitted to the bus based on their priority (see [`FramePriority`]). From 3da606d804ca2c51ec9aebfdb81e71963f455f4d Mon Sep 17 00:00:00 2001 From: Guinea Wheek Date: Mon, 3 Jun 2024 21:49:04 -0700 Subject: [PATCH 2/5] add error_status --- src/lib.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 97c586c..98de568 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -708,10 +708,18 @@ where /// /// This will return an [`ErrorStatus`] containing information on the error. pub fn clear_error_interrupt(&mut self) -> ErrorStatus { + let can = self.registers(); + let stat = self.error_status(); + can.msr.write(|w| w.erri().set_bit()); + stat + } + + /// Reads the error status register's data as an [`ErrorStatus`]. + pub fn error_status(&self) -> ErrorStatus { let can = self.registers(); let esr = can.esr.read(); - let stat = ErrorStatus { + ErrorStatus { recv_count: esr.rec().bits, txmt_count: esr.tec().bits, code: (match esr.lec().bits { @@ -728,9 +736,7 @@ where bus_off: esr.boff().bits, err_passive: esr.epvf().bits, err_warning: esr.ewgf().bits - }; - can.msr.write(|w| w.erri().set_bit()); - stat + } } /// Puts a CAN frame in a free transmit mailbox for transmission on the bus. From 1a731723c0b66af83db54a8aa82a7d75f2bb758b Mon Sep 17 00:00:00 2001 From: Guinea Wheek Date: Mon, 3 Jun 2024 23:11:46 -0700 Subject: [PATCH 3/5] Add the other error flags --- src/interrupt.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 21 +++++++++++++-------- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/interrupt.rs b/src/interrupt.rs index 17aacf8..c5af51e 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -64,6 +64,47 @@ pub enum Interrupt { /// Behavior is otherwise identical to [`Self::Fifo0Overrun`]. Fifo1Overrun = 1 << 6, + /// Fires the **SCE** interrupt when the error warning limit (receive or transmit error counter + /// >= 96) has been reached. + /// + /// [`Interrupt::Error`] must also be enabled for the interrupt to fire. + /// + /// The interrupt handler must clear the interrupt condition by calling + /// [`Can::clear_error_interrupt`]. + ErrorWarning = 1 << 8, + + /// Fires the **SCE** interrupt when the peripheral enters the error passive state. + /// + /// [`Interrupt::Error`] must also be enabled for the interrupt to fire. + /// + /// The interrupt handler must clear the interrupt condition by calling + /// [`Can::clear_error_interrupt`]. + ErrorPassive = 1 << 9, + + /// Fires the **SCE** interrupt when the peripheral has entered bus-off. + /// + /// [`Interrupt::Error`] must also be enabled for the interrupt to fire. + /// + /// The interrupt handler must clear the interrupt condition by calling + /// [`Can::clear_error_interrupt`]. + BusOff = 1 << 10, + + /// Fires the **SCE** interrupt when the peripheral updates the last error code. + /// + /// [`Interrupt::Error`] must also be enabled for the interrupt to fire. + /// + /// The interrupt handler must clear the interrupt condition by calling + /// [`Can::clear_error_interrupt`]. + LastErrorCode = 1 << 11, + + /// Fires the **SCE** interrupt when the peripheral enters an error state. + /// + /// The error states that will cause the interrupt to fire are determined by the subset of + /// [`Interrupt::ErrorWarning`], [`Interrupt::ErrorPassive`], [`Interrupt::BusOff`], and + /// [`Interrupt::LastErrorCode`] that are enabled along with this flag. + /// + /// The interrupt handler must clear the interrupt condition by calling + /// [`Can::clear_error_interrupt`]. Error = 1 << 15, /// Fires the **SCE** interrupt when an incoming CAN frame is detected while the peripheral is @@ -90,6 +131,10 @@ bitflags::bitflags! { const FIFO1_MESSAGE_PENDING = 1 << 4; const FIFO1_FULL = 1 << 5; const FIFO1_OVERRUN = 1 << 6; + const ERROR_WARNING = 1 << 8; + const ERROR_PASSIVE = 1 << 9; + const BUS_OFF = 1 << 10; + const LAST_ERROR_CODE = 1 << 11; const ERROR = 1 << 15; const WAKEUP = 1 << 16; const SLEEP = 1 << 17; diff --git a/src/lib.rs b/src/lib.rs index 98de568..def1b37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,7 +112,7 @@ pub unsafe trait MasterInstance: FilterOwner {} /// Enum of error status codes from the error status register. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] -pub enum Error{ +pub enum Error { None, Stuff, Form, @@ -124,8 +124,6 @@ pub enum Error{ } /// The peripheral's current error status. -/// -/// This is returned when clearing an error status interrupt. #[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] pub struct ErrorStatus { @@ -157,18 +155,24 @@ impl ErrorStatus { } /// Returns true if the peripheral is currently in bus-off. + /// + /// This occurs when the transmit error counter overflows past 255. #[inline] pub fn bus_off(&self) -> bool { self.bus_off } /// Returns true if the error passive limit has been reached. + /// + /// This occurs when the receive or transmit error counters exceed 127. #[inline] pub fn error_passive(&self) -> bool { self.err_passive } /// Returns true if the error warning limit has been reached. + /// + /// This occurs when the receive or transmit error counters are greater than or equal 96. #[inline] pub fn error_warning(&self) -> bool { self.err_warning @@ -706,15 +710,16 @@ where /// Clears the error interrupt flag ([`Interrupt::Error`]). /// - /// This will return an [`ErrorStatus`] containing information on the error. - pub fn clear_error_interrupt(&mut self) -> ErrorStatus { + /// To read the error status, use [`Can::error_status`] to get the [`ErrorStatus`] before + /// clearing the interrupt flag. + pub fn clear_error_interrupt(&mut self) { let can = self.registers(); - let stat = self.error_status(); can.msr.write(|w| w.erri().set_bit()); - stat } - /// Reads the error status register's data as an [`ErrorStatus`]. + /// Reads the error status register's data. + /// + /// This does not clear the error interrupt flag. pub fn error_status(&self) -> ErrorStatus { let can = self.registers(); let esr = can.esr.read(); From a2126ba09c161e0a4558fc1652e1e9abfbfee9e8 Mon Sep 17 00:00:00 2001 From: Guinea Wheek Date: Mon, 3 Jun 2024 23:18:39 -0700 Subject: [PATCH 4/5] run cargo fmt --- src/interrupt.rs | 20 ++++++++++---------- src/lib.rs | 11 +++++------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/interrupt.rs b/src/interrupt.rs index c5af51e..f02a8cf 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -66,41 +66,41 @@ pub enum Interrupt { /// Fires the **SCE** interrupt when the error warning limit (receive or transmit error counter /// >= 96) has been reached. - /// + /// /// [`Interrupt::Error`] must also be enabled for the interrupt to fire. - /// + /// /// The interrupt handler must clear the interrupt condition by calling /// [`Can::clear_error_interrupt`]. ErrorWarning = 1 << 8, /// Fires the **SCE** interrupt when the peripheral enters the error passive state. - /// + /// /// [`Interrupt::Error`] must also be enabled for the interrupt to fire. - /// + /// /// The interrupt handler must clear the interrupt condition by calling /// [`Can::clear_error_interrupt`]. ErrorPassive = 1 << 9, /// Fires the **SCE** interrupt when the peripheral has entered bus-off. - /// + /// /// [`Interrupt::Error`] must also be enabled for the interrupt to fire. - /// + /// /// The interrupt handler must clear the interrupt condition by calling /// [`Can::clear_error_interrupt`]. BusOff = 1 << 10, /// Fires the **SCE** interrupt when the peripheral updates the last error code. - /// + /// /// [`Interrupt::Error`] must also be enabled for the interrupt to fire. - /// + /// /// The interrupt handler must clear the interrupt condition by calling /// [`Can::clear_error_interrupt`]. LastErrorCode = 1 << 11, /// Fires the **SCE** interrupt when the peripheral enters an error state. - /// + /// /// The error states that will cause the interrupt to fire are determined by the subset of - /// [`Interrupt::ErrorWarning`], [`Interrupt::ErrorPassive`], [`Interrupt::BusOff`], and + /// [`Interrupt::ErrorWarning`], [`Interrupt::ErrorPassive`], [`Interrupt::BusOff`], and /// [`Interrupt::LastErrorCode`] that are enabled along with this flag. /// /// The interrupt handler must clear the interrupt condition by calling diff --git a/src/lib.rs b/src/lib.rs index def1b37..561181b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,7 +155,7 @@ impl ErrorStatus { } /// Returns true if the peripheral is currently in bus-off. - /// + /// /// This occurs when the transmit error counter overflows past 255. #[inline] pub fn bus_off(&self) -> bool { @@ -163,7 +163,7 @@ impl ErrorStatus { } /// Returns true if the error passive limit has been reached. - /// + /// /// This occurs when the receive or transmit error counters exceed 127. #[inline] pub fn error_passive(&self) -> bool { @@ -171,7 +171,7 @@ impl ErrorStatus { } /// Returns true if the error warning limit has been reached. - /// + /// /// This occurs when the receive or transmit error counters are greater than or equal 96. #[inline] pub fn error_warning(&self) -> bool { @@ -179,7 +179,6 @@ impl ErrorStatus { } } - /// Error that indicates that an incoming message has been lost due to buffer overrun. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "unstable-defmt", derive(defmt::Format))] @@ -709,7 +708,7 @@ where } /// Clears the error interrupt flag ([`Interrupt::Error`]). - /// + /// /// To read the error status, use [`Can::error_status`] to get the [`ErrorStatus`] before /// clearing the interrupt flag. pub fn clear_error_interrupt(&mut self) { @@ -740,7 +739,7 @@ where }), bus_off: esr.boff().bits, err_passive: esr.epvf().bits, - err_warning: esr.ewgf().bits + err_warning: esr.ewgf().bits, } } From 1cc3ea094252c7a294cabd3af85426935d45cbdc Mon Sep 17 00:00:00 2001 From: Guinea Wheek Date: Fri, 25 Oct 2024 21:50:01 -0700 Subject: [PATCH 5/5] Update comment to reflect addition of error state handling --- src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 561181b..080fd5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,10 +15,6 @@ //! - Implements the [`embedded-hal`] traits for interoperability. //! - Support for both RX FIFOs (as [`Rx0`] and [`Rx1`]). //! -//! # Limitations -//! -//! - Support for querying error states and handling error interrupts is incomplete. -//! //! # Cargo Features //! //! | Feature | Description |