Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

11 add txrx to example #13

Merged
merged 6 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ readme = "README.md"
documentation = "https://docs.rs/mcp2517"

[dependencies]
byteorder = { version = "1.5.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 Down
24 changes: 24 additions & 0 deletions example/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[build]
# Set the default target to match the Cortex-M0+ in the RP2040
target = "thumbv6m-none-eabi"

# Target specific options
[target.thumbv6m-none-eabi]
# Pass some extra options to rustc, some of which get passed on to the linker.
#
# * linker argument --nmagic turns off page alignment of sections (which saves
# flash space)
# * linker argument -Tlink.x tells the linker to use link.x as the linker
# script. This is usually provided by the cortex-m-rt crate, and by default
# the version in that crate will include a file called `memory.x` which
# describes the particular memory layout for your specific chip.
# * inline-threshold=5 makes the compiler more aggressive and inlining functions
# * no-vectorize-loops turns off the loop vectorizer (seeing as the M0+ doesn't
# have SIMD)
rustflags = [
"-C", "link-arg=--nmagic",
"-C", "link-arg=-Tlink.x",
"-C", "no-vectorize-loops",
]

runner = "elf2uf2-rs"
12 changes: 11 additions & 1 deletion example/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ cortex-m = "0.7.7"
cortex-m-rt = "0.7.3"
rp-pico = "0.9.0"
rp2040-boot2 = "0.3.0"
embedded-can = "0.4.1"
bytes = { version = "1.6.0", default-features = false }
log = "0.4.21"
usb-device = "0.3.2"
usbd-serial = "0.2.2"
defmt = "0.3.8"
defmt-serial = "0.10.0"
static_cell = "2.1.0"
embedded-serial = "0.5.0"
fugit = { version = "0.3.7", features = ["defmt"] }

[patch.crates-io]
bytes = { git = "https://github.com/atlas-aero/rt-bytes.git", branch = "cfg_target_has_atomic_v1.6.0" }
bytes = { git = "https://github.com/atlas-aero/rt-bytes.git", branch = "cfg_target_has_atomic_v1.6.0" }
15 changes: 15 additions & 0 deletions example/memory.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
MEMORY {
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}

EXTERN(BOOT2_FIRMWARE)

SECTIONS {
/* ### Boot loader */
.boot2 ORIGIN(BOOT2) :
{
KEEP(*(.boot2));
} > BOOT2
} INSERT BEFORE .text;
132 changes: 110 additions & 22 deletions example/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,52 @@
#![no_std]
#![no_main]
extern crate alloc;

pub mod clock;
pub mod heap;
pub mod mutex;

use crate::clock::SystemClock;
use crate::heap::Heap;
use hal::clocks::Clock;
use hal::fugit::RateExtU32;
use hal::pac;
use bytes::Bytes;
use core::fmt::Write;
use embedded_can::{Id, StandardId};
use embedded_hal::delay::DelayNs;
use fugit::RateExtU32;
use mcp2517::can::Controller;
use panic_halt as _;
use rp2040_hal as hal;
use mcp2517::config::{
ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, RequestMode,
SystemClockDivisor,
};
use mcp2517::filter::Filter;
use mcp2517::message::{Can20, TxMessage};
use panic_halt as panic;
use rp_pico as bsp;

#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;
use bsp::{
entry,
hal::{
clocks::{init_clocks_and_plls, Clock},
gpio::FunctionSpi,
pac,
sio::Sio,
uart::*,
watchdog::Watchdog,
Spi, Timer,
},
};

const XTAL_FREQ_HZ: u32 = 12_000_000u32;

#[rp2040_hal::entry]
#[entry]
fn main() -> ! {
Heap::init();

let mut pac = pac::Peripherals::take().unwrap();
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
let mut watchdog = Watchdog::new(pac.WATCHDOG);

// Configure the clocks
let clocks = hal::clocks::init_clocks_and_plls(
let clocks = init_clocks_and_plls(
XTAL_FREQ_HZ,
pac.XOSC,
pac.CLOCKS,
Expand All @@ -39,27 +57,97 @@ fn main() -> ! {
)
.unwrap();

let sio = hal::Sio::new(pac.SIO);
let sio = Sio::new(pac.SIO);

let pins = hal::gpio::Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS);
let pins = bsp::Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS);

let spi_mosi = pins.gpio7.into_function::<hal::gpio::FunctionSpi>();
let spi_miso = pins.gpio4.into_function::<hal::gpio::FunctionSpi>();
let spi_sclk = pins.gpio6.into_function::<hal::gpio::FunctionSpi>();
let spi = hal::spi::Spi::<_, _, _, 8>::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk));
let spi_mosi = pins.gpio11.into_function::<FunctionSpi>();
let spi_miso = pins.gpio12.into_function::<FunctionSpi>();
let spi_sclk = pins.gpio10.into_function::<FunctionSpi>();
let spi = Spi::<_, _, _, 8>::new(pac.SPI1, (spi_mosi, spi_miso, spi_sclk));

// Exchange the uninitialised SPI driver for an initialised one
let spi = spi.init(
&mut pac.RESETS,
clocks.peripheral_clock.freq(),
16.MHz(),
1.MHz(),
embedded_hal::spi::MODE_0,
);

// Configure GPIO5 as an CS pin
let pin_cs = pins.gpio5.into_push_pull_output();
let mut timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);
let sys_clk = SystemClock::default();
sys_clk.initialize(timer);

let _controller: Controller<_, _, SystemClock> = Controller::new(spi, pin_cs);
// Configure GPIO13 as an CS pin
let pin_cs = pins.gpio13.into_push_pull_output();

loop {}
// Enable uart to print to terminal
let mut uart = bsp::hal::uart::UartPeripheral::new(
pac.UART0,
(pins.gpio0.into_function(), pins.gpio1.into_function()),
&mut pac.RESETS,
)
.enable(
UartConfig::new(9600.Hz(), DataBits::Eight, None, StopBits::One),
clocks.peripheral_clock.freq(),
)
.unwrap();

let mut can_controller: Controller<_, _, SystemClock> = Controller::new(spi, pin_cs);

// Setup clk config
let clk_config = ClockConfiguration {
clock_output: ClockOutputDivisor::DivideBy1,
system_clock: SystemClockDivisor::DivideBy2,
pll: PLLSetting::DirectXTALOscillator,
disable_clock: false,
};

// Setup fifo config
let fifo_config = FifoConfiguration::default();

// Setup CAN Controller config
let config = Configuration {
clock: clk_config,
fifo: fifo_config,
mode: RequestMode::InternalLoopback,
};

if let Err(_) = can_controller.configure(&config, &sys_clk) {
panic!()
}

let can_id = Id::Standard(StandardId::new(0x55).unwrap());

// Create filter object for RX
let filter = Filter::new(can_id, 0).unwrap();
let _ = can_controller.set_filter_object(filter);

// Create message frame
let message_type = Can20 {};
let payload = [1, 2, 3, 4, 5, 6, 7, 8];
let pl_bytes = Bytes::copy_from_slice(&payload);
let can_message = TxMessage::new(message_type, pl_bytes, can_id).unwrap();

let mut receive_buffer = [0u8; 8];

loop {
can_controller.transmit(&can_message).unwrap();
uart.write_raw(b"can message sent\n\r").unwrap();

timer.delay_ms(500);

match can_controller.receive(&mut receive_buffer) {
Ok(_) => {
uart.write_fmt(format_args!("can message received\n\r")).unwrap();

for val in receive_buffer {
uart.write_fmt(format_args!("{val}\n\r")).unwrap();
}
}
Err(e) => uart.write_fmt(format_args!("error reading message {:?}\n\r", e)).unwrap(),
}

timer.delay_ms(500);
}
}
31 changes: 26 additions & 5 deletions src/can.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::filter::Filter;
use crate::message::{MessageType, TxMessage};
use crate::registers::{FifoControlReg1, FifoStatusReg0};
use crate::status::{OperationMode, OperationStatus, OscillatorStatus};
use byteorder::{BigEndian, ByteOrder, LittleEndian};
use core::marker::PhantomData;
use embedded_hal::blocking::spi::Transfer;
use embedded_hal::digital::v2::OutputPin;
Expand Down Expand Up @@ -102,7 +103,7 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> Controller<B, CS, CLK> {

self.write_register(
Self::fifo_control_register(FIFO_RX_INDEX) + 3,
config.fifo.as_rx_register(),
config.fifo.as_rx_register_3(),
)?;

self.write_register(
Expand Down Expand Up @@ -186,13 +187,15 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> Controller<B, CS, CLK> {

// Set FLTENm to enable filter
self.write_register(filter_control_reg, (1 << 7) | fifo_index)?;

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(())
}

Expand All @@ -207,8 +210,13 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> Controller<B, CS, CLK> {
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(())
}

Expand Down Expand Up @@ -273,7 +281,11 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> Controller<B, CS, CLK> {
}

// get address in which to write next message in TX FIFO (should not be read in configuration mode)
let address = self.read32(Self::fifo_user_address_register(FIFO_TX_INDEX))?;
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;
Expand Down Expand Up @@ -309,7 +321,10 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> Controller<B, CS, CLK> {
rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0);
}

let address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?;
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)?;

Expand All @@ -335,12 +350,17 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> Controller<B, CS, CLK> {

// copy message data into mutable buffer
let mut data = [0u8; L];
data.copy_from_slice(message.buff.as_ref());
data.copy_from_slice(&message.buff);

buffer[0] = (command >> 8) as u8;
buffer[1] = (command & 0xFF) as u8;
buffer[2..].copy_from_slice(&message.header.into_bytes());

for word in buffer[2..].chunks_exact_mut(4) {
let num = BigEndian::read_u32(word);
LittleEndian::write_u32(word, num);
}

self.pin_cs.set_low().map_err(CSError)?;
self.bus.transfer(&mut buffer).map_err(TransferError)?;
self.bus.transfer(&mut data).map_err(TransferError)?;
Expand All @@ -351,8 +371,9 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> Controller<B, CS, CLK> {

/// Read message from RX FIFO
fn read_fifo(&mut self, register: u16, data: &mut [u8]) -> Result<(), Error<B::Error, CS::Error>> {
let payload_address = register + 8;
let mut buffer = [0u8; 2];
let command = (register & 0x0FFF) | ((Operation::Read as u16) << 12);
let command = (payload_address & 0x0FFF) | ((Operation::Read as u16) << 12);

buffer[0] = (command >> 8) as u8;
buffer[1] = (command & 0xFF) as u8;
Expand Down
9 changes: 7 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,15 @@ impl Default for FifoConfiguration {
}

impl FifoConfiguration {
/// Encodes the configuration to RX FIFO configuration register byte
pub(crate) fn as_rx_register(&self) -> u8 {
/// Encodes the configuration for the third RX fifo control register byte
pub(crate) fn as_rx_register_3(&self) -> u8 {
(Self::limit_size(self.rx_size) - 1) | ((self.pl_size as u8) << 5)
}

/// Encodes the configuration for the first TX configuration register byte
pub(crate) fn as_tx_register_0(&self) -> u8 {
// bit 7 -> tx enable
// bit 0 -> tx fifo not full interrupt flag enable
match self.tx_enable {
true => 0b1000_0000,
false => 0b0000_0000,
Expand Down Expand Up @@ -234,6 +236,8 @@ pub enum RequestMode {
InternalLoopback,
/// External loop back mode
ExternalLoopback,
/// Listen only mode
ListenOnly,
/// CAN 2.0 mode, possible error frames on CAN FD frames
NormalCAN2_0,
}
Expand All @@ -250,6 +254,7 @@ impl RequestMode {
RequestMode::NormalCANFD => OperationMode::NormalCANFD,
RequestMode::InternalLoopback => OperationMode::InternalLoopback,
RequestMode::ExternalLoopback => OperationMode::ExternalLoopback,
RequestMode::ListenOnly => OperationMode::ListenOnly,
RequestMode::NormalCAN2_0 => OperationMode::NormalCAN2_0,
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/registers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ pub struct FilterObjectReg {
__: B1,
/// Extended ID enable bit
/// If MIDE 1, setting this bit matches Extended ID only
/// if MIDE 1, clearing this bit matches Standard ID only
/// If MIDE 0, clearing this bit matches Standard ID only
pub exide: bool,
/// Standard ID filter bit
pub sid11: bool,
Expand Down
Loading
Loading