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 10fde8e..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; @@ -13,7 +14,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 +94,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..3904e83 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,119 @@ 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>; + /// Set corresponding filter and mask registers + fn set_filter_object(&mut self, filter: Filter) -> 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(()) + } + + /// Set corresponding filter and mask registers + fn set_filter_object(&mut self, filter: Filter) -> 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 { pub fn new(bus: B, pin_cs: CS) -> Self { Self { bus, @@ -208,27 +320,6 @@ impl, CS: OutputPin, CLK: Clock> Controller { 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); @@ -264,85 +355,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 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};