Skip to content

Commit

Permalink
Merge pull request #14 from atlas-aero/5-add-docs-for-crate-usage
Browse files Browse the repository at this point in the history
5 add docs for crate usage
  • Loading branch information
marius-meissner authored Oct 15, 2024
2 parents 8885078 + 44823b6 commit 6c6181f
Show file tree
Hide file tree
Showing 11 changed files with 363 additions and 22 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea/*
target/*
example/target/*
Cargo.lock
Cargo.lock
.vscode/*
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ readme = "README.md"
documentation = "https://docs.rs/mcp2517"

[dependencies]
byteorder = { version = "1.5.0", default-features = false }
byteorder = { version = "^1.3.0", default-features = false }
bytes = { version = "1.6.0", default-features = false }
embedded-can = "0.4.1"
embedded-hal = { version = "0.2.7", features = ["unproven"] }
Expand All @@ -26,5 +26,10 @@ serde = { version = "1.0.197", features = ["derive"], default-features = false }
mockall = "0.11.0"

[features]
default = []
default = ["example"]
# Mocks for doc examples
example = []

strict = []


6 changes: 4 additions & 2 deletions example/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,14 @@ fn main() -> ! {
let can_id = Id::Standard(StandardId::new(0x55).unwrap());

// Create filter object for RX
let filter = Filter::new(can_id, 0).unwrap();
let mut filter = Filter::new(can_id, 0).unwrap();
// Set mask to match if only 2 LSB of ID match with filter
filter.set_mask_standard_id(0xFF);
let _ = can_controller.set_filter_object(filter);

// Create message frame
let message_type = Can20::<8> {};
let payload = [1, 2, 3, 4, 5, 6, 7, 8];
let payload = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8];
let pl_bytes = Bytes::copy_from_slice(&payload);
let can_message = TxMessage::new(message_type, pl_bytes, can_id).unwrap();

Expand Down
36 changes: 28 additions & 8 deletions src/can.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
//!# CAN Controller device
//!
//!```
//!# use mcp2517::can::MCP2517;
//!# use mcp2517::config::Configuration;
//!# use mcp2517::example::*;
//!#
//! let sys_clk = ExampleClock::default();
//! let spi_bus = ExampleSPIBus::default();
//! let cs_pin = ExampleCSPin{};
//!
//! // Initialize controller object
//! let mut can_controller = MCP2517::new(spi_bus,cs_pin);
//!
//! // Use default configuration settings
//! let can_config = Configuration::default();
//!
//! // Configure CAN controller
//! can_controller.configure(&can_config, &sys_clk).unwrap();
//! ```
use crate::can::BusError::{CSError, TransferError};
use crate::can::ConfigError::{ClockError, ConfigurationModeTimeout, RequestModeTimeout};
use crate::config::{ClockConfiguration, Configuration};
Expand Down Expand Up @@ -249,6 +269,14 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> MCP2517<B, CS, CLK> {
Ok(())
}

/// Disable corresponding filter
pub fn disable_filter(&mut self, filter_index: u8) -> Result<(), BusError<B::Error, CS::Error>> {
let filter_reg = Self::filter_control_register_byte(filter_index);
self.write_register(filter_reg, 0x00)?;

Ok(())
}

/// Reads and returns the operation status
pub fn read_operation_status(&mut self) -> Result<OperationStatus, BusError<B::Error, CS::Error>> {
let data = self.read_register(REGISTER_C1CON + 2)?;
Expand Down Expand Up @@ -312,14 +340,6 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> MCP2517<B, CS, CLK> {
Ok(())
}

/// Disable corresponding filter
pub fn disable_filter(&mut self, filter_index: u8) -> Result<(), BusError<B::Error, CS::Error>> {
let filter_reg = Self::filter_control_register_byte(filter_index);
self.write_register(filter_reg, 0x00)?;

Ok(())
}

/// Writes a single register byte
fn write_register(&mut self, register: u16, value: u8) -> Result<(), BusError<B::Error, CS::Error>> {
let mut buffer = self.cmd_buffer(register, Operation::Write);
Expand Down
50 changes: 50 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,53 @@
//! # CAN Module configuration
//! The [Configuration] struct provides an abstraction for configuring the CAN module registers.
//! ## Fifo configuration
//! The following example shows a FIFO buffer configuration. At the moment, there is one TX Fifo and one
//! RX Fifo. The configuration sets the max payload size of messages transmitted/received in both Fifo buffers
//! to 8 bytes. The number of message the RX Fifo buffer can hold is 10 while it is 32 for the TX Fifo.
//!
//! The priority for the messages in the TX Fifo are given the highest possible priority (32) and the retransmission
//! attemps are set to be unlimited.
//!```
//!# use mcp2517::config::{FifoConfiguration,PayloadSize,RetransmissionAttempts};
//!#
//! let fifo_config = FifoConfiguration{
//! pl_size: PayloadSize::EightBytes,
//! rx_size: 10,
//! tx_attempts: RetransmissionAttempts::Unlimited,
//! tx_enable: true,
//! tx_priority: 32,
//! tx_size: 32,
//! };
//!```
//! ## Clock configuration
//! The CAN system clock is determined through setting the `system_clock` and `pll`. In this example,
//! the pll setting used is to directly use the crystal oscillator without any multiplication, and the
//! `system_clock` divisor is set to 1. Meaning the frequency of the SYSCLK matches the crystal used.
//! The `clock_output` divisior is set to 2. So that the CLKO outputs half the freq of the crystal.
//! Refer to the [datasheet](https://ww1.microchip.com/downloads/en/DeviceDoc/MCP2517FD-External-CAN-FD-Controller-with-SPI-Interface-20005688B.pdf) section 5.0
//!
//!```
//!# use mcp2517::config::{ClockConfiguration, ClockOutputDivisor, PLLSetting, SystemClockDivisor};
//!#
//! let clock_config = ClockConfiguration{
//! clock_output: ClockOutputDivisor::DivideBy2,
//! system_clock: SystemClockDivisor::DivideBy1,
//! pll: PLLSetting::DirectXTALOscillator,
//! disable_clock: false,
//! };
//!```
//! ## Bit rate configuration
//! It is recommended to use a SYSCLK frequency of 20 MHz or 40 MHz for the MCP2517FD CAN chip.
//! Based on the SYSCLK frequency used and the baud rate chosen, the CiNBTCFG regsiter values are configured.
//!```
//!# use mcp2517::config::{BitRateConfig,CanBaudRate,SysClk};
//!#
//! let bit_rate_config = BitRateConfig{
//! sys_clk: SysClk::MHz20,
//! can_speed: CanBaudRate::Kpbs500
//! };
//!
//!
use crate::status::OperationMode;

/// Entire configuration currently supported
Expand Down
124 changes: 124 additions & 0 deletions src/example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//! # Mock dummy structure for doc examples
//!
//! This code can be removed by disabling the `example` feature
use alloc::vec;
use alloc::vec::Vec;
use core::cell::RefCell;
use core::convert::Infallible;
use embedded_hal::blocking::spi::Transfer;
use embedded_hal::digital::v2::OutputPin;
use embedded_time::clock::Error;
use embedded_time::duration::{Duration, Fraction};
use embedded_time::fixed_point::FixedPoint;
use embedded_time::timer::param::{Armed, OneShot};
use embedded_time::{Clock, Instant, Timer};

#[derive(Default)]
pub struct ExampleSPIBus {
read_calls: u32,
}

impl Transfer<u8> for ExampleSPIBus {
type Error = Infallible;

fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
// write command -> returns empty buffer
if (words[0] >> 4) == 0x2 {
return Ok(&[0u8; 3]);
}

// RAM read command
if words.len() == 8 && words == [0u8; 8] {
words.iter_mut().enumerate().for_each(|(i, val)| {
*val += (i + 1) as u8;
});
return Ok(&[0u8; 8]);
}

// SFR Read command
if words[0] >= 0x3 {
return match words[1] {
// addr: C1CON reg 2
0x2 => {
// configuration mode
if self.read_calls == 0 {
self.read_calls += 1;
return Ok(&[0, 0, 0b1001_0100]);
}

// return operation mode NormalCANFD mode (called in configure and during transmission)
Ok(&[0x0, 0x0, 0b0000_0000])
}
// C1FIFOSTA2
0x6C => Ok(&[0, 0, 0x1]),
// C1FIFOUA2 (2 extra bytes in beginning for cmd+addr)
0x70 => Ok(&[0, 0, 0, 0, 0x04, 0xA2]),
// C1FIFOCON2 register 1
0x69 => Ok(&[0, 0, 0]),
// C1FIFOSTA1
0x60 => Ok(&[0, 0, 0x1]),
// C1FIFOUA1
0x64 => Ok(&[0, 0, 0, 0x04, 0x7C]),

_ => Ok(&[0, 0, 0]),
};
}

Ok(&[0u8; 3])
}
}

pub struct ExampleCSPin {}

impl OutputPin for ExampleCSPin {
type Error = Infallible;

fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(())
}

fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}

#[derive(Debug, PartialEq, Eq)]
pub struct ExampleClock {
pub next_instants: RefCell<Vec<u64>>,
}

impl ExampleClock {
pub fn new(next_instants: Vec<u64>) -> Self {
Self {
next_instants: RefCell::new(next_instants),
}
}
}

impl Default for ExampleClock {
fn default() -> Self {
Self::new(vec![
100, // Config mode: Timer start,
200, // Config mode: First expiration check
10_000, // Request mode: Timer start
10_100, // Request mode: First expiration check
])
}
}

impl Clock for ExampleClock {
type T = u64;
const SCALING_FACTOR: Fraction = Fraction::new(1, 1_000_000);

fn try_now(&self) -> Result<Instant<Self>, Error> {
if self.next_instants.borrow().len() == 0 {
return Err(Error::Unspecified);
}

Ok(Instant::new(self.next_instants.borrow_mut().remove(0)))
}

fn new_timer<Dur: Duration + FixedPoint>(&self, duration: Dur) -> Timer<OneShot, Armed, Self, Dur> {
Timer::new(self, duration)
}
}
24 changes: 20 additions & 4 deletions src/filter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
//!# CAN Filter
//! The [Filter] object is used to create a CAN filter. The MCP2517FD CAN chip has 32 filter/mask registers.
//! Lower index of the filter means higher priority (highest priority =0, lowest priority = 31).
//!
//! ```
//!# use mcp2517::filter::Filter;
//!# use embedded_can::{Id,ExtendedId};
//!#
//! // ID to match
//! let id = Id::Extended(ExtendedId::new(0xC672).unwrap());
//! // Create filter with index 2
//! let mut filter = Filter::new(id,2).unwrap();
//! // Set mask MSB bits, so that only the MSB of the message ID needs to match the filter
//! filter.set_mask_extended_id(0xFF00);
//!
//!
use crate::message::{EXTENDED_IDENTIFIER_MASK, STANDARD_IDENTIFIER_MASK};
use crate::registers::{FilterMaskReg, FilterObjectReg};
use embedded_can::{ExtendedId, Id, StandardId};
Expand All @@ -6,15 +22,15 @@ use embedded_can::{ExtendedId, Id, StandardId};
#[derive(Default, Debug)]
pub struct Filter {
/// filter & mask index
pub index: u8,
pub(crate) index: u8,
/// mask register bitfield
pub mask_bits: FilterMaskReg,
pub(crate) mask_bits: FilterMaskReg,
/// filter register bitfield
pub filter_bits: FilterObjectReg,
pub(crate) filter_bits: FilterObjectReg,
}

impl Filter {
/// Create new filter from embedded_can::Id and index, no mask
/// Create new filter from [embedded_can::Id] and index, no mask
pub fn new(identifier: Id, index: u8) -> Option<Self> {
if index > 31 {
return None;
Expand Down
Loading

0 comments on commit 6c6181f

Please sign in to comment.