-
Notifications
You must be signed in to change notification settings - Fork 40
Add Support for FlexCAN(1/2) #171
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
base: v0.5
Are you sure you want to change the base?
Changes from 48 commits
a0fcb3b
e7c6bef
567623f
001e975
7072a37
d37b511
0696fe1
0e67341
14aabd7
2bda636
e75e127
f4f8bf3
0a52f37
d9719aa
bb4cb3b
0aeaa05
69e83be
75222f7
603f406
e5fb282
c27a696
900262d
5dd2488
ca785ef
95ffd35
b360ab3
39d0a9f
72a74fa
d7f8975
9c8957a
1d054b6
f83953d
b19ad1e
bcc75a1
8f64296
4e089d9
129454a
2e2536d
ddee7ba
ee48bd4
11a129c
91d5e38
c2b0b52
3664cff
ea66169
027f291
d5e4b4f
6a37344
1a0f321
132a670
dbe45d4
5a1ba4b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| /// CAN clock root | ||
| use crate::ral::{self, ccm::CCM}; | ||
|
|
||
| /// Returns the can clock divider. | ||
| #[inline(always)] | ||
| pub fn divider(ccm: &CCM) -> u32 { | ||
| ral::read_reg!(ral::ccm, ccm, CSCMR2, CAN_CLK_PODF) + 1 | ||
| } | ||
|
|
||
| /// The smallest flexcan clock divider. | ||
| pub const MIN_DIVIDER: u32 = 1; | ||
| /// The largest flexcan clock divider. | ||
| pub const MAX_DIVIDER: u32 = 64; | ||
|
|
||
| /// Set the flexcan clock divider | ||
| #[inline(always)] | ||
| pub fn set_divider(ccm: &mut CCM, divider: u32) { | ||
| let podf = divider.clamp(MIN_DIVIDER, MAX_DIVIDER) - 1; | ||
| ral::modify_reg!(ral::ccm, ccm, CSCMR2, CAN_CLK_PODF: podf); | ||
| } | ||
|
|
||
| /// Flexcan clock selections. | ||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| #[repr(u32)] | ||
| pub enum Selection { | ||
| /// Derive from pll3_sw_clk divided clock (60M) | ||
| PLL3Div8 = 0, | ||
| /// Derive from the crystal oscillator. | ||
| Oscillator = 1, | ||
| /// Derive from pll3_sw_clk divided clock (80M) | ||
| PLL3Div6 = 2, | ||
| /// Disable flexcan clock | ||
| Disable = 3, | ||
| } | ||
|
|
||
| /// Returns the Flexcan clock selection. | ||
| #[inline(always)] | ||
| pub fn selection(ccm: &CCM) -> Selection { | ||
| match ral::read_reg!(ral::ccm, ccm, CSCMR2, CAN_CLK_SEL) { | ||
| 0 => Selection::PLL3Div8, | ||
| 1 => Selection::Oscillator, | ||
| 2 => Selection::PLL3Div6, | ||
| 3 => Selection::Disable, | ||
| _ => unreachable!(), | ||
| } | ||
| } | ||
|
|
||
| /// Set the Flexcan clock selection. | ||
| #[inline(always)] | ||
| pub fn set_selection(ccm: &mut CCM, selection: Selection) { | ||
| ral::modify_reg!(ral::ccm, ccm, CSCMR2, CAN_CLK_SEL: selection as u32); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| use crate::ccm::clock_gate::{locator, Gate::*, Locator, Register::*}; | ||
| use crate::ral; | ||
| /// Returns the FlexCAN clock gate locator. | ||
| #[inline(always)] | ||
| pub const fn can<const N: u8>() -> Locator | ||
| where | ||
| ral::can::Instance<N>: ral::Valid, | ||
| { | ||
| [locator(CCGR0, CG7), locator(CCGR0, CG9)][if N == ral::SOLE_INSTANCE { | ||
| N as usize | ||
| } else { | ||
| N as usize - 1 | ||
| }] | ||
| } | ||
|
|
||
| /// Returns the FlexCAN Peripheral Engine gate locator. | ||
| #[inline(always)] | ||
| pub const fn can_pe<const N: u8>() -> Locator | ||
| where | ||
| ral::can::Instance<N>: ral::Valid, | ||
| { | ||
| [locator(CCGR0, CG8), locator(CCGR0, CG10)][if N == ral::SOLE_INSTANCE { | ||
| N as usize | ||
| } else { | ||
| N as usize - 1 | ||
| }] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| //! `embedded_hal` trait impls. | ||
|
|
||
| use super::{Data, Error, Frame, CAN}; | ||
|
|
||
| use embedded_can; | ||
| pub(crate) use embedded_can::ErrorKind; | ||
| pub use embedded_can::{ExtendedId, Id, StandardId}; | ||
|
|
||
| impl<P, const M: u8> embedded_can::nb::Can for CAN<P, M> { | ||
| type Frame = Frame; | ||
|
|
||
| type Error = Error; | ||
|
|
||
| fn transmit(&mut self, frame: &Self::Frame) -> nb::Result<Option<Self::Frame>, Self::Error> { | ||
| match self.transmit(frame) { | ||
| Ok(_status) => Ok(Some(frame.clone())), | ||
| Err(nb::Error::WouldBlock) => Err(nb::Error::WouldBlock), | ||
| Err(nb::Error::Other(e)) => Err(nb::Error::Other(e)), | ||
| } | ||
| } | ||
|
|
||
| fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error> { | ||
| match self.read_mailboxes() { | ||
| Some(d) => Ok(d.frame), | ||
| None => Err(nb::Error::Other(Error::NoRxData)), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl embedded_can::Error for Error { | ||
| fn kind(&self) -> embedded_can::ErrorKind { | ||
| match self { | ||
| Self::NoRxData => embedded_can::ErrorKind::Other, | ||
| Self::NoTxMailbox => embedded_can::ErrorKind::Other, | ||
| Self::EmbeddedHal(e) => e.kind(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl embedded_can::Frame for Frame { | ||
| fn new(id: impl Into<Id>, data: &[u8]) -> Option<Self> { | ||
| let id = match id.into() { | ||
| Id::Standard(id) => unsafe { Id::Standard(StandardId::new_unchecked(id.as_raw())) }, | ||
| Id::Extended(id) => unsafe { Id::Extended(ExtendedId::new_unchecked(id.as_raw())) }, | ||
| }; | ||
|
|
||
| let data = Data::new(data)?; | ||
| Some(Frame::new_data(id, data)) | ||
| } | ||
|
|
||
| fn new_remote(id: impl Into<Id>, dlc: usize) -> Option<Self> { | ||
| let id = match id.into() { | ||
| Id::Standard(id) => unsafe { Id::Standard(StandardId::new_unchecked(id.as_raw())) }, | ||
| Id::Extended(id) => unsafe { Id::Extended(ExtendedId::new_unchecked(id.as_raw())) }, | ||
| }; | ||
|
|
||
| if dlc <= 8 { | ||
| Some(Frame::new_remote(id, dlc as u8)) | ||
| } else { | ||
| None | ||
| } | ||
| } | ||
|
|
||
| #[inline] | ||
| fn is_extended(&self) -> bool { | ||
| self.is_extended() | ||
| } | ||
|
|
||
| #[inline] | ||
| fn is_remote_frame(&self) -> bool { | ||
| self.is_remote_frame() | ||
| } | ||
|
|
||
| #[inline] | ||
| fn id(&self) -> Id { | ||
| match self.id() { | ||
| Id::Standard(id) => unsafe { Id::Standard(StandardId::new_unchecked(id.as_raw())) }, | ||
| Id::Extended(id) => unsafe { Id::Extended(ExtendedId::new_unchecked(id.as_raw())) }, | ||
| } | ||
| } | ||
|
|
||
| #[inline] | ||
| fn dlc(&self) -> usize { | ||
| self.dlc().into() | ||
| } | ||
|
|
||
| fn data(&self) -> &[u8] { | ||
| if let Some(data) = self.data() { | ||
| data | ||
| } else { | ||
| &[] | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| //! Filter bank API. | ||
|
|
||
| /// Decodes value of the ID Extended (IDE) and Remote Transmission Request (RTR) bits | ||
| /// | ||
| /// TODO: Break this up into seperate RTR and IDE structs | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the plan to address these TODOs? I see the options as
Question and options applies to other TODOs listed in documentation. I'd prefer option 1, or option 2 if it can happen soon after we merge. (In this instance, I haven't thought if separation is appropriate. I'll change my consideration if the answer is option 1.) |
||
| #[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] | ||
| pub enum FlexCanIde { | ||
| /// IDE = 0, RTR = 0 | ||
| #[default] | ||
| None = 0, | ||
| /// IDE = 1, RTR = 0 | ||
| Ext = 1, | ||
| /// IDE = 0, RTR = 1 | ||
| Rtr = 2, | ||
| /// IDE = 1, RTR = 1 | ||
| Std = 3, | ||
| /// Unused(?) variant | ||
| Inactive, | ||
| } | ||
|
|
||
| /// Filter enable/disable. | ||
| #[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] | ||
| pub enum FlexCanFlten { | ||
| /// Accept all CAN frames (filtering is disabled) | ||
| AcceptAll = 0, | ||
| /// Reject all CAN frames that do not match the filter exactly | ||
| #[default] | ||
| RejectAll = 1, | ||
| } | ||
|
|
||
| /// FlexCAN Filter. | ||
| #[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] | ||
| pub struct FlexCanFilter { | ||
| /// Mailbox ID that this filter will apply to | ||
| pub filter_id: u8, | ||
| /// Frame ID | ||
| pub id: u32, | ||
| /// Extended ID Bit (IDE) | ||
| pub ide: FlexCanIde, | ||
| /// Remote Frame Bit (RTR) | ||
| pub remote: FlexCanIde, | ||
| } | ||
|
|
||
| impl FlexCanFilter { | ||
| /// Create a new [`FlexCanFilter`]. | ||
| pub fn new(filter_id: u8, id: u32, ide: FlexCanIde, remote: FlexCanIde) -> Self { | ||
| Self { | ||
| filter_id, | ||
| id, | ||
| ide, | ||
| remote, | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for other / future reviewers: This variant is not documented in the 1020 reference manual. It's also not a constant known to the 1020 SVD. Nevertheless, I say we keep this as-is; we cover the full bit width of the field.