From ad3bf090dea210d4a8cd9a007434afd62897e270 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Sun, 20 Dec 2020 17:10:48 -0500 Subject: [PATCH 1/7] support more CAN config; fix length for tx --- src/can.rs | 84 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 28 deletions(-) diff --git a/src/can.rs b/src/can.rs index c149c633e..76dc0efc1 100644 --- a/src/can.rs +++ b/src/can.rs @@ -24,6 +24,36 @@ use core::sync::atomic::{AtomicU8, Ordering}; const EXID_MASK: u32 = 0b1_1111_1111_1100_0000_0000_0000_0000; const MAX_EXTENDED_ID: u32 = 0x1FFF_FFFF; +/// Options the CAN bus. This is primarily used to set bus timings, but also controls options like enabling loopback or silent mode for debugging. +/// See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks. +/// +/// Use `CanBitRateOpts::default()` to get 250kbps at 32mhz system clock +pub struct CanOpts { + pub brp: u16, + pub sjw: u8, + pub ts1: u8, + pub ts2: u8, + pub lbkm: bool, +} + +impl CanOpts { + pub fn new(brp: u16, sjw: u8, ts1: u8, ts2: u8, lbkm: bool) -> CanOpts { + CanOpts { + brp, + sjw, + ts1, + ts2, + lbkm, + } + } +} + +impl Default for CanOpts { + fn default() -> Self { + CanOpts::new(4, 0, 10, 3, false) + } +} + /// A CAN identifier, which can be either 11 or 27 (extended) bits. /// u16 and u32 respectively are used here despite the fact that the upper bits are unused. #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -252,13 +282,13 @@ impl CanFilterData { } impl Can { - /// Initialize the CAN Peripheral - pub fn new( + pub fn new_with_opts( can: stm32::CAN, rx: gpioa::PA11, tx: gpioa::PA12, apb1: &mut APB1, - ) -> Self { + opts: CanOpts, + ) -> Can { apb1.enr().modify(|_, w| w.canen().enabled()); can.mcr.modify(|_, w| w.sleep().clear_bit()); can.mcr.modify(|_, w| w.inrq().set_bit()); @@ -266,28 +296,13 @@ impl Can { // Wait for INAK to confirm we have entered initialization mode while !can.msr.read().inak().bit_is_set() {} - // TODO: actually calculate baud params - - // Our baud rate calc here is aiming for roughly 4000uS total bit time or about 250kbps - // Though we actually allow closer to 5500uS total given the sjw setting - // Calculations for timing value from http://www.bittiming.can-wiki.info/#bxCAN - - // Baud rate prescaler defines time quanta - // tq = (BRP[9:0]+1) x tPCLK - let brp: u16 = 4; - - // Resynchronization jump width: number of quanta segments may be expanded to resync - // tRJW = tq x (SJW[1:0] + 1) - let sjw = 0; - - // Time seg 2 - // tBS2 = tq x (TS2[2:0] + 1) - let ts2 = 3; - - // Time seg 1 - // tBS1 = tq x (TS1[3:0] + 1) - let ts1 = 10; - + let CanOpts { + brp, + sjw, + ts1, + ts2, + lbkm, + } = opts; can.btr.modify(|_, w| unsafe { w.brp() .bits(brp) @@ -297,8 +312,8 @@ impl Can { .bits(ts1) .ts2() .bits(ts2) - //.lbkm() - //.set_bit() + .lbkm() + .bit(lbkm) }); // Leave initialization mode by clearing INRQ and switch to normal mode @@ -312,6 +327,15 @@ impl Can { _tx: tx, } } + /// Initialize the CAN Peripheral + pub fn new( + can: stm32::CAN, + rx: gpioa::PA11, + tx: gpioa::PA12, + apb1: &mut APB1, + ) -> Self { + Can::new_with_opts(can, rx, tx, apb1, CanOpts::default()) + } /// Enable CAN event interrupts for `Event` pub fn listen(&mut self, event: Event) { @@ -407,7 +431,7 @@ impl embedded_hal_can::Transmitter for CanTransmitter { // NOTE(unsafe): full 8bit write is unsafe via the svd2rust api tx.tdtr - .modify(|_, w| unsafe { w.dlc().bits(data.len() as u8) }); + .modify(|_, w| unsafe { w.dlc().bits(frame.dlc as u8) }); tx.tir.modify(|_, w| w.rtr().clear_bit()); } else { @@ -579,4 +603,8 @@ impl CanFrame { data: [0; 8], } } + + pub fn len(&self) -> usize { + self.dlc + } } From 0032d8ce3126bb97ae1eeffdef237146da8ed254 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Sun, 20 Dec 2020 20:15:01 -0500 Subject: [PATCH 2/7] size range must be inclusive --- src/can.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/can.rs b/src/can.rs index 76dc0efc1..421e4c5cb 100644 --- a/src/can.rs +++ b/src/can.rs @@ -578,7 +578,7 @@ impl CanFrame { /// /// This function will panic if length of `data` is greater than `8` pub fn new_data(id: CanId, data: &[u8]) -> CanFrame { - crate::assert!((0..8).contains(&data.len())); + crate::assert!((0..=8).contains(&data.len())); let mut frame = Self { id, From 61697299b4abd4628a4c8cd4fabdb290bd85e437 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Sun, 10 Jan 2021 15:14:39 -0500 Subject: [PATCH 3/7] use buidler pattern --- src/can.rs | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/can.rs b/src/can.rs index 421e4c5cb..7aa79b7ed 100644 --- a/src/can.rs +++ b/src/can.rs @@ -37,20 +37,45 @@ pub struct CanOpts { } impl CanOpts { - pub fn new(brp: u16, sjw: u8, ts1: u8, ts2: u8, lbkm: bool) -> CanOpts { - CanOpts { - brp, - sjw, - ts1, - ts2, - lbkm, - } + pub fn new() -> CanOpts { + CanOpts::default() + } + + pub fn brp(mut self, brp: u16) -> Self { + self.brp = brp; + self + } + + pub fn sjw(mut self, sjw: u8) -> Self { + self.sjw = sjw; + self + } + + pub fn ts1(mut self, ts1: u8) -> Self { + self.ts1 = ts1; + self + } + + pub fn ts2(mut self, ts2: u8) -> Self { + self.ts2 = ts2; + self + } + + pub fn lbkm(mut self, lbkm: bool) -> Self { + self.lbkm = lbkm; + self } } impl Default for CanOpts { fn default() -> Self { - CanOpts::new(4, 0, 10, 3, false) + CanOpts { + brp: 4, + sjw: 0, + ts1: 10, + ts2: 3, + lbkm: false, + } } } From d24402b26267c9711a3dafb1dd21c22b5903d5d3 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Sun, 10 Jan 2021 15:15:19 -0500 Subject: [PATCH 4/7] fix doc comment --- src/can.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/can.rs b/src/can.rs index 7aa79b7ed..a40ad509d 100644 --- a/src/can.rs +++ b/src/can.rs @@ -27,7 +27,7 @@ const MAX_EXTENDED_ID: u32 = 0x1FFF_FFFF; /// Options the CAN bus. This is primarily used to set bus timings, but also controls options like enabling loopback or silent mode for debugging. /// See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks. /// -/// Use `CanBitRateOpts::default()` to get 250kbps at 32mhz system clock +/// Use `CanOpts::default()` to get 250kbps at 32mhz system clock pub struct CanOpts { pub brp: u16, pub sjw: u8, From 0eb802ff413e0d25a06a692f2f94f75e7dffd661 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Sun, 10 Jan 2021 15:18:23 -0500 Subject: [PATCH 5/7] use LBKM enum --- src/can.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/can.rs b/src/can.rs index a40ad509d..269d16a5d 100644 --- a/src/can.rs +++ b/src/can.rs @@ -20,6 +20,7 @@ use crate::stm32; use nb::{self, Error}; use core::sync::atomic::{AtomicU8, Ordering}; +use stm32::can::btr::LBKM_A; const EXID_MASK: u32 = 0b1_1111_1111_1100_0000_0000_0000_0000; const MAX_EXTENDED_ID: u32 = 0x1FFF_FFFF; @@ -33,7 +34,7 @@ pub struct CanOpts { pub sjw: u8, pub ts1: u8, pub ts2: u8, - pub lbkm: bool, + pub lbkm: LBKM_A, } impl CanOpts { @@ -61,7 +62,7 @@ impl CanOpts { self } - pub fn lbkm(mut self, lbkm: bool) -> Self { + pub fn lbkm(mut self, lbkm: LBKM_A) -> Self { self.lbkm = lbkm; self } @@ -74,7 +75,7 @@ impl Default for CanOpts { sjw: 0, ts1: 10, ts2: 3, - lbkm: false, + lbkm: LBKM_A::DISABLED, } } } @@ -338,7 +339,7 @@ impl Can { .ts2() .bits(ts2) .lbkm() - .bit(lbkm) + .variant(lbkm) }); // Leave initialization mode by clearing INRQ and switch to normal mode From f9270cb64d24d2127841cc6b35a1daa3d29d109a Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Sat, 16 Jan 2021 11:39:22 -0500 Subject: [PATCH 6/7] clippy --- src/can.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/can.rs b/src/can.rs index 269d16a5d..8a01f5725 100644 --- a/src/can.rs +++ b/src/can.rs @@ -30,38 +30,44 @@ const MAX_EXTENDED_ID: u32 = 0x1FFF_FFFF; /// /// Use `CanOpts::default()` to get 250kbps at 32mhz system clock pub struct CanOpts { - pub brp: u16, - pub sjw: u8, - pub ts1: u8, - pub ts2: u8, - pub lbkm: LBKM_A, + brp: u16, + sjw: u8, + ts1: u8, + ts2: u8, + lbkm: LBKM_A, } impl CanOpts { + /// Create new `CanOpts` using the default settings from `CanOpts::default()` to get 250kbps at 32mhz system clock. pub fn new() -> CanOpts { CanOpts::default() } + /// Set the Baud Rate Prescaler. See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks. pub fn brp(mut self, brp: u16) -> Self { self.brp = brp; self } + /// Set the Resynchronisation Jump Width. See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks. pub fn sjw(mut self, sjw: u8) -> Self { self.sjw = sjw; self } + /// Set Time Segment One. See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks. pub fn ts1(mut self, ts1: u8) -> Self { self.ts1 = ts1; self } + /// Set Time Segment Two. See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks. pub fn ts2(mut self, ts2: u8) -> Self { self.ts2 = ts2; self } + /// Enable or disable loopback mode on the CAN device. This is useful for debugging. pub fn lbkm(mut self, lbkm: LBKM_A) -> Self { self.lbkm = lbkm; self @@ -308,6 +314,7 @@ impl CanFilterData { } impl Can { + /// Initialize the CAN peripheral using the options specified by `opts`. pub fn new_with_opts( can: stm32::CAN, rx: gpioa::PA11, @@ -619,7 +626,7 @@ impl CanFrame { /// /// # Panics /// - /// This function will panic if `dlc` is not inside the vliad range `0..=8`. + /// This function will panic if `dlc` is not inside the valid range `0..=8`. pub fn new_remote(id: CanId, dlc: usize) -> CanFrame { assert!((0..=8).contains(&dlc)); @@ -630,7 +637,13 @@ impl CanFrame { } } + /// Length of the frame data pub fn len(&self) -> usize { self.dlc } + + /// Is this frame empty. This usually indicates a remote frame. + pub fn is_empty(&self) -> bool { + self.dlc == 0 + } } From 30ac7f23b15b104891f2379ea64168b4a30c632f Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Thu, 4 Mar 2021 21:49:08 -0500 Subject: [PATCH 7/7] small comment fixes --- CHANGELOG.md | 4 ++++ src/can.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baec06ab4..735d4099c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + +- Added support for more CAN bit rates and modes. ([#186](https://github.com/stm32-rs/stm32f3xx-hal/pull/186) + ## [v0.6.1] - 2020-12-10 ### Changed diff --git a/src/can.rs b/src/can.rs index 8a01f5725..31d57080a 100644 --- a/src/can.rs +++ b/src/can.rs @@ -20,7 +20,7 @@ use crate::stm32; use nb::{self, Error}; use core::sync::atomic::{AtomicU8, Ordering}; -use stm32::can::btr::LBKM_A; +pub use stm32::can::btr::LBKM_A; const EXID_MASK: u32 = 0b1_1111_1111_1100_0000_0000_0000_0000; const MAX_EXTENDED_ID: u32 = 0x1FFF_FFFF; @@ -360,7 +360,7 @@ impl Can { _tx: tx, } } - /// Initialize the CAN Peripheral + /// Initialize the CAN Peripheral using default options from `CanOpts::default()` pub fn new( can: stm32::CAN, rx: gpioa::PA11,