From ad1cbc116f6c09f70095a33620d4f4db5421db77 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 17 Sep 2024 11:46:14 +0200 Subject: [PATCH 1/7] #24 add CanController trait and rename controller struct --- example/src/main.rs | 4 +- src/can.rs | 172 +++++++++++++++++++++++--------------------- src/tests/can.rs | 13 ++-- 3 files changed, 100 insertions(+), 89 deletions(-) diff --git a/example/src/main.rs b/example/src/main.rs index 10fde8e..fac4d3f 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -13,7 +13,7 @@ use core::fmt::Write; use embedded_can::{Id, StandardId}; use embedded_hal::delay::DelayNs; use fugit::RateExtU32; -use mcp2517::can::Controller; +use mcp2517::can::{CanController, MCP2517}; use mcp2517::config::{ BitRateConfig, ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, RequestMode, SystemClockDivisor, @@ -93,7 +93,7 @@ fn main() -> ! { ) .unwrap(); - let mut can_controller: Controller<_, _, SystemClock> = Controller::new(spi, pin_cs); + let mut can_controller: MCP2517<_, _, SystemClock> = MCP2517::new(spi, pin_cs); // Setup clk config let clk_config = ClockConfiguration { diff --git a/src/can.rs b/src/can.rs index 1d9f7bd..9646003 100644 --- a/src/can.rs +++ b/src/can.rs @@ -79,7 +79,7 @@ impl From> for Error { } /// Main MCP2517 CAN controller device -pub struct Controller, CS: OutputPin, CLK: Clock> { +pub struct MCP2517, CS: OutputPin, CLK: Clock> { /// SPI bus bus: B, @@ -90,7 +90,96 @@ pub struct Controller, CS: OutputPin, CLK: Clock> { clock: PhantomData, } -impl, CS: OutputPin, CLK: Clock> Controller { +/// Trait for CAN controller +pub trait CanController { + type Error; + + /// Transmit CAN message + fn transmit>(&mut self, message: &TxMessage) -> Result<(), Self::Error>; + + /// Receive CAN message + fn receive(&mut self, data: &mut [u8; L]) -> Result<(), Self::Error>; +} + +impl, CS: OutputPin, CLK: Clock> CanController for MCP2517 { + type Error = Error; + + fn transmit>(&mut self, message: &TxMessage) -> Result<(), Self::Error> { + // make sure there is space for new message in TX FIFO + // read byte 0 of TX FIFO status register + let status_reg_addr = Self::fifo_status_register(FIFO_TX_INDEX); + + let mut txfifo_status_byte0 = self.read_register(status_reg_addr)?; + let mut txfifo_status_reg0 = FifoStatusReg0::from(txfifo_status_byte0); + + // block until there is room available for new message in TX FIFO + while !txfifo_status_reg0.tfnrfnif() { + txfifo_status_byte0 = self.read_register(status_reg_addr)?; + txfifo_status_reg0 = FifoStatusReg0::from(txfifo_status_byte0); + } + + // make sure length of payload is consistent with CAN operation mode + let operation_status = self.read_operation_status()?; + + if message.buff.len() > 8 && operation_status.mode != OperationMode::NormalCANFD { + return Err(Error::InvalidPayloadLength(message.buff.len())); + } + + // get address in which to write next message in TX FIFO (should not be read in configuration mode) + let user_address = self.read32(Self::fifo_user_address_register(FIFO_TX_INDEX))?; + + // calculate address of next Message Object according to + // Equation 4-1 in MCP251XXFD Family Reference Manual + let address = user_address + 0x400; + + // get address of TX FIFO control register byte 1 + let fifo_control_reg1 = Self::fifo_control_register(FIFO_TX_INDEX) + 1; + + // load message in TX FIFO + self.write_fifo::(address as u16, message)?; + + // Request transmission (set txreq) and set uinc in TX FIFO control register byte 1 + self.write_register(fifo_control_reg1, 0x03)?; + + // read TX FIFO control register byte 1 + let mut txfifo_control_byte1 = self.read_register(fifo_control_reg1)?; + let mut txfifo_control_reg = FifoControlReg1::from(txfifo_control_byte1); + + // block till txreq is cleared confirming that all messages in TX FIFO are transmitted + while txfifo_control_reg.txreq() { + txfifo_control_byte1 = self.read_register(fifo_control_reg1)?; + txfifo_control_reg = FifoControlReg1::from(txfifo_control_byte1); + } + Ok(()) + } + + fn receive(&mut self, data: &mut [u8; L]) -> Result<(), Self::Error> { + let fifo_status_reg = Self::fifo_status_register(FIFO_RX_INDEX); + + let mut rxfifo_status_byte0 = self.read_register(fifo_status_reg)?; + let mut rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); + + // block until fifo rx contains at least one message + while !rxfifo_status_reg0.tfnrfnif() { + rxfifo_status_byte0 = self.read_register(fifo_status_reg)?; + rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); + } + + let user_address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?; + + let address = 0x400 + user_address; + + // read message object + self.read_fifo(address as u16, data)?; + + // set UINC bit for incrementing the FIFO head by a single message + self.write_register(Self::fifo_control_register(FIFO_RX_INDEX) + 1, 1)?; + + Ok(()) + } +} + +impl, CS: OutputPin, CLK: Clock> MCP2517 { pub fn new(bus: B, pin_cs: CS) -> Self { Self { bus, @@ -264,85 +353,6 @@ impl, CS: OutputPin, CLK: Clock> Controller { Ok(()) } - /// Transmit CAN Message - pub fn transmit(&mut self, message: &TxMessage) -> Result<(), Error> - where - T: MessageType, - { - // make sure there is space for new message in TX FIFO - // read byte 0 of TX FIFO status register - let status_reg_addr = Self::fifo_status_register(FIFO_TX_INDEX); - - let mut txfifo_status_byte0 = self.read_register(status_reg_addr)?; - let mut txfifo_status_reg0 = FifoStatusReg0::from(txfifo_status_byte0); - - // block until there is room available for new message in TX FIFO - while !txfifo_status_reg0.tfnrfnif() { - txfifo_status_byte0 = self.read_register(status_reg_addr)?; - txfifo_status_reg0 = FifoStatusReg0::from(txfifo_status_byte0); - } - - // make sure length of payload is consistent with CAN operation mode - let operation_status = self.read_operation_status()?; - - if message.buff.len() > 8 && operation_status.mode != OperationMode::NormalCANFD { - return Err(Error::InvalidPayloadLength(message.buff.len())); - } - - // get address in which to write next message in TX FIFO (should not be read in configuration mode) - let user_address = self.read32(Self::fifo_user_address_register(FIFO_TX_INDEX))?; - - // calculate address of next Message Object according to - // Equation 4-1 in MCP251XXFD Family Reference Manual - let address = user_address + 0x400; - - // get address of TX FIFO control register byte 1 - let fifo_control_reg1 = Self::fifo_control_register(FIFO_TX_INDEX) + 1; - - // load message in TX FIFO - self.write_fifo::(address as u16, message)?; - - // Request transmission (set txreq) and set uinc in TX FIFO control register byte 1 - self.write_register(fifo_control_reg1, 0x03)?; - - // read TX FIFO control register byte 1 - let mut txfifo_control_byte1 = self.read_register(fifo_control_reg1)?; - let mut txfifo_control_reg = FifoControlReg1::from(txfifo_control_byte1); - - // block till txreq is cleared confirming that all messages in TX FIFO are transmitted - while txfifo_control_reg.txreq() { - txfifo_control_byte1 = self.read_register(fifo_control_reg1)?; - txfifo_control_reg = FifoControlReg1::from(txfifo_control_byte1); - } - Ok(()) - } - - /// Receive CAN Message - pub fn receive(&mut self, data: &mut [u8; L]) -> Result<(), Error> { - let fifo_status_reg = Self::fifo_status_register(FIFO_RX_INDEX); - - let mut rxfifo_status_byte0 = self.read_register(fifo_status_reg)?; - let mut rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); - - // block until fifo rx contains at least one message - while !rxfifo_status_reg0.tfnrfnif() { - rxfifo_status_byte0 = self.read_register(fifo_status_reg)?; - rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); - } - - let user_address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?; - - let address = 0x400 + user_address; - - // read message object - self.read_fifo(address as u16, data)?; - - // set UINC bit for incrementing the FIFO head by a single message - self.write_register(Self::fifo_control_register(FIFO_RX_INDEX) + 1, 1)?; - - Ok(()) - } - /// Insert message object in TX FIFO fn write_fifo( &mut self, diff --git a/src/tests/can.rs b/src/tests/can.rs index 2cc662d..6b22863 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -1,4 +1,5 @@ -use crate::can::{BusError, ConfigError, Controller, Error}; +use crate::can::CanController; +use crate::can::{BusError, ConfigError, Error, MCP2517}; use crate::config::{ BitRateConfig, ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, PayloadSize, RequestMode, RetransmissionAttempts, SystemClockDivisor, @@ -112,7 +113,7 @@ fn test_configure_correct() { pin_cs.expect_set_low().times(14).return_const(Ok(())); pin_cs.expect_set_high().times(14).return_const(Ok(())); - let mut controller = Controller::new(bus, pin_cs); + let mut controller = MCP2517::new(bus, pin_cs); controller .configure( &Configuration { @@ -168,7 +169,7 @@ fn test_configure_mode_timeout() { pin_cs.expect_set_low().times(3).return_const(Ok(())); pin_cs.expect_set_high().times(3).return_const(Ok(())); - let mut controller = Controller::new(bus, pin_cs); + let mut controller = MCP2517::new(bus, pin_cs); assert_eq!( ConfigError::ConfigurationModeTimeout, controller.configure(&Configuration::default(), &clock).unwrap_err() @@ -676,7 +677,7 @@ fn test_request_mode_timeout() { pin_cs.expect_set_low().times(15).return_const(Ok(())); pin_cs.expect_set_high().times(15).return_const(Ok(())); - let mut controller = Controller::new(bus, pin_cs); + let mut controller = MCP2517::new(bus, pin_cs); assert_eq!( ConfigError::RequestModeTimeout, controller.configure(&Configuration::default(), &clock).unwrap_err() @@ -947,8 +948,8 @@ pub(crate) struct Mocks { } impl Mocks { - pub fn into_controller(self) -> Controller { - Controller::new(self.bus, self.pin_cs) + pub fn into_controller(self) -> MCP2517 { + MCP2517::new(self.bus, self.pin_cs) } /// Simulates a SPI transfer fault From c67f7ba4d16edb967236ff3cbbc8713147eede8e Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 17 Sep 2024 15:05:30 +0200 Subject: [PATCH 2/7] #24 add error trait type --- src/can.rs | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/can.rs b/src/can.rs index 9646003..9a228ab 100644 --- a/src/can.rs +++ b/src/can.rs @@ -25,6 +25,8 @@ const FIFO_RX_INDEX: u8 = 1; /// FIFO index for transmitting CAN messages const FIFO_TX_INDEX: u8 = 2; +pub trait Mcp2517Error {} + /// General SPI Errors #[derive(Debug, PartialEq)] pub enum BusError { @@ -66,6 +68,8 @@ pub enum Error { InvalidBufferSize(usize), } +impl Mcp2517Error for Error {} + impl From> for Error { fn from(value: BusError) -> Self { Error::BusErr(value) @@ -92,13 +96,15 @@ pub struct MCP2517, CS: OutputPin, CLK: Clock> { /// Trait for CAN controller pub trait CanController { - type Error; + type Error: Mcp2517Error; /// Transmit CAN message fn transmit>(&mut self, message: &TxMessage) -> Result<(), Self::Error>; /// Receive CAN message fn receive(&mut self, data: &mut [u8; L]) -> Result<(), Self::Error>; + + fn set_filter_object(&mut self, filter: Filter) -> Result<(), Self::Error>; } impl, CS: OutputPin, CLK: Clock> CanController for MCP2517 { @@ -177,6 +183,27 @@ impl, CS: OutputPin, CLK: Clock> CanController for MCP2517 Result<(), Self::Error> { + let filter_object_reg = Self::filter_object_register(filter.index); + let filter_mask_reg = Self::filter_mask_register(filter.index); + + self.disable_filter(filter.index)?; + + let filter_value = u32::from(filter.filter_bits); + let mask_value = u32::from(filter.mask_bits); + + self.write32(filter_object_reg, filter_value)?; + + self.write32(filter_mask_reg, mask_value)?; + + let filter_control_reg = Self::filter_control_register_byte(filter.index); + + self.write_register(filter_control_reg, (1 << 7) | 1)?; + + Ok(()) + } } impl, CS: OutputPin, CLK: Clock> MCP2517 { @@ -297,27 +324,6 @@ impl, CS: OutputPin, CLK: Clock> MCP2517 { Ok(()) } - /// Set corresponding filter and mask registers - pub fn set_filter_object(&mut self, filter: Filter) -> Result<(), BusError> { - let filter_object_reg = Self::filter_object_register(filter.index); - let filter_mask_reg = Self::filter_mask_register(filter.index); - - self.disable_filter(filter.index)?; - - let filter_value = u32::from(filter.filter_bits); - let mask_value = u32::from(filter.mask_bits); - - self.write32(filter_object_reg, filter_value)?; - - self.write32(filter_mask_reg, mask_value)?; - - let filter_control_reg = Self::filter_control_register_byte(filter.index); - - self.write_register(filter_control_reg, (1 << 7) | 1)?; - - Ok(()) - } - /// Writes a single register byte fn write_register(&mut self, register: u16, value: u8) -> Result<(), BusError> { let mut buffer = self.cmd_buffer(register, Operation::Write); From b99afc6fc810c718e293aec8872c7486658b5f43 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Thu, 19 Sep 2024 15:17:23 +0200 Subject: [PATCH 3/7] #24 import CanController trait to test file --- src/tests/filter.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/filter.rs b/src/tests/filter.rs index f39be39..7ba2fb5 100644 --- a/src/tests/filter.rs +++ b/src/tests/filter.rs @@ -1,3 +1,4 @@ +use crate::can::CanController; use crate::filter::Filter; use crate::tests::can::Mocks; use embedded_can::{ExtendedId, Id, StandardId}; From e47bd169e806b0fd4bef2a809b983dcdfe3869d8 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 20 Sep 2024 11:15:30 +0200 Subject: [PATCH 4/7] #24 modify error in CanController trait to be specified by implementor --- src/can.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/can.rs b/src/can.rs index 9a228ab..37e2a8f 100644 --- a/src/can.rs +++ b/src/can.rs @@ -96,7 +96,7 @@ pub struct MCP2517, CS: OutputPin, CLK: Clock> { /// Trait for CAN controller pub trait CanController { - type Error: Mcp2517Error; + type Error; /// Transmit CAN message fn transmit>(&mut self, message: &TxMessage) -> Result<(), Self::Error>; From 9f1b89345db7b58b6617cdee05523ea4562e1b9f Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 20 Sep 2024 11:21:56 +0200 Subject: [PATCH 5/7] #24 remove unused Mcp2517Error trait --- src/can.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/can.rs b/src/can.rs index 37e2a8f..44057bb 100644 --- a/src/can.rs +++ b/src/can.rs @@ -25,8 +25,6 @@ const FIFO_RX_INDEX: u8 = 1; /// FIFO index for transmitting CAN messages const FIFO_TX_INDEX: u8 = 2; -pub trait Mcp2517Error {} - /// General SPI Errors #[derive(Debug, PartialEq)] pub enum BusError { @@ -68,8 +66,6 @@ pub enum Error { InvalidBufferSize(usize), } -impl Mcp2517Error for Error {} - impl From> for Error { fn from(value: BusError) -> Self { Error::BusErr(value) From 5457c89c32dd7b58411b6e583b4c7b547422fc33 Mon Sep 17 00:00:00 2001 From: HusseinAbdelhamid <154588556+HusseinAbdelhamid@users.noreply.github.com> Date: Mon, 23 Sep 2024 16:43:58 +0200 Subject: [PATCH 6/7] Update src/can.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing function documentation Co-authored-by: Marius Meißner --- src/can.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/can.rs b/src/can.rs index 44057bb..3904e83 100644 --- a/src/can.rs +++ b/src/can.rs @@ -99,7 +99,7 @@ pub trait CanController { /// Receive CAN message fn receive(&mut self, data: &mut [u8; L]) -> Result<(), Self::Error>; - + /// Set corresponding filter and mask registers fn set_filter_object(&mut self, filter: Filter) -> Result<(), Self::Error>; } From 92baca2be65700d21db3f95798d85a95a1a0624b Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 24 Sep 2024 09:30:49 +0200 Subject: [PATCH 7/7] #24 add portable-atomic dependency to example crate + remove static mut warning --- example/Cargo.toml | 1 + example/src/main.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/example/Cargo.toml b/example/Cargo.toml index 706996b..12e97da 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -23,6 +23,7 @@ rp-pico = "0.9.0" rp2040-boot2 = "0.3.0" embedded-can = "0.4.1" bytes = { version = "1.6.0", default-features = false } +portable-atomic = { version = "1.8.0", features = ["critical-section"] } log = "0.4.21" usb-device = "0.3.2" usbd-serial = "0.2.2" diff --git a/example/src/main.rs b/example/src/main.rs index fac4d3f..6bef75d 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -1,5 +1,6 @@ #![no_std] #![no_main] +#![allow(static_mut_refs)] extern crate alloc; pub mod clock;