aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-03-14 09:34:40 +0000
committerGitHub <[email protected]>2024-03-14 09:34:40 +0000
commitbbcab556c8a4514cd9ceda49d64c5644c82ba9e8 (patch)
tree7e53d8dc09183ce4a51e19b56022a34af710e7f3
parent35f284ec22848d7085e00f377136fd66067ca756 (diff)
parent535e4c20e88f131189241bcf1625ff7c32e0443b (diff)
Merge pull request #2693 from cschuhen/feature/bxcan_use_frame
Use the same Frame struct for BXCAN and FDCAN.
-rw-r--r--embassy-stm32/src/can/bx/frame.rs248
-rw-r--r--embassy-stm32/src/can/bx/id.rs113
-rw-r--r--embassy-stm32/src/can/bx/mod.rs105
-rw-r--r--embassy-stm32/src/can/bxcan.rs17
-rw-r--r--embassy-stm32/src/can/enums.rs12
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs7
-rw-r--r--embassy-stm32/src/can/frame.rs170
-rw-r--r--examples/stm32f1/src/bin/can.rs6
-rw-r--r--examples/stm32f4/src/bin/can.rs4
-rw-r--r--examples/stm32f7/src/bin/can.rs2
-rw-r--r--tests/stm32/src/bin/can.rs4
11 files changed, 186 insertions, 502 deletions
diff --git a/embassy-stm32/src/can/bx/frame.rs b/embassy-stm32/src/can/bx/frame.rs
deleted file mode 100644
index 828f375be..000000000
--- a/embassy-stm32/src/can/bx/frame.rs
+++ /dev/null
@@ -1,248 +0,0 @@
1#[cfg(test)]
2use core::cmp::Ordering;
3use core::ops::{Deref, DerefMut};
4
5use crate::can::bx::{Id, IdReg};
6
7/// A CAN data or remote frame.
8#[derive(Clone, Debug, Eq)]
9//#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10#[cfg_attr(feature = "defmt", derive(defmt::Format))]
11pub struct Frame {
12 pub(crate) id: IdReg,
13 pub(crate) data: Data,
14}
15
16impl Frame {
17 /// Creates a new data frame.
18 pub fn new_data(id: impl Into<Id>, data: impl Into<Data>) -> Self {
19 let id = match id.into() {
20 Id::Standard(id) => IdReg::new_standard(id),
21 Id::Extended(id) => IdReg::new_extended(id),
22 };
23
24 Self { id, data: data.into() }
25 }
26
27 /// Creates a new remote frame with configurable data length code (DLC).
28 ///
29 /// # Panics
30 ///
31 /// This function will panic if `dlc` is not inside the valid range `0..=8`.
32 pub fn new_remote(id: impl Into<Id>, dlc: u8) -> Self {
33 assert!(dlc <= 8);
34
35 let mut frame = Self::new_data(id, []);
36 // Just extend the data length, even with no data present. The API does not hand out this
37 // `Data` object.
38 frame.data.len = dlc;
39 frame.id = frame.id.with_rtr(true);
40 frame
41 }
42
43 /// Returns true if this frame is an extended frame.
44 #[inline]
45 pub fn is_extended(&self) -> bool {
46 self.id.is_extended()
47 }
48
49 /// Returns true if this frame is a standard frame.
50 #[inline]
51 pub fn is_standard(&self) -> bool {
52 self.id.is_standard()
53 }
54
55 /// Returns true if this frame is a remote frame.
56 #[inline]
57 pub fn is_remote_frame(&self) -> bool {
58 self.id.rtr()
59 }
60
61 /// Returns true if this frame is a data frame.
62 #[inline]
63 pub fn is_data_frame(&self) -> bool {
64 !self.is_remote_frame()
65 }
66
67 /// Returns the frame identifier.
68 #[inline]
69 pub fn id(&self) -> Id {
70 self.id.to_id()
71 }
72
73 /// Returns the priority of this frame.
74 #[inline]
75 pub fn priority(&self) -> FramePriority {
76 FramePriority(self.id)
77 }
78
79 /// Returns the data length code (DLC) which is in the range 0..8.
80 ///
81 /// For data frames the DLC value always matches the length of the data.
82 /// Remote frames do not carry any data, yet the DLC can be greater than 0.
83 #[inline]
84 pub fn dlc(&self) -> u8 {
85 self.data.len() as u8
86 }
87
88 /// Returns the frame data (0..8 bytes in length) if this is a data frame.
89 ///
90 /// If this is a remote frame, returns `None`.
91 pub fn data(&self) -> Option<&Data> {
92 if self.is_data_frame() {
93 Some(&self.data)
94 } else {
95 None
96 }
97 }
98}
99
100impl PartialEq for Frame {
101 fn eq(&self, other: &Self) -> bool {
102 match (self.data(), other.data()) {
103 (None, None) => self.id.eq(&other.id),
104 (Some(a), Some(b)) => self.id.eq(&other.id) && a.eq(b),
105 (None, Some(_)) | (Some(_), None) => false,
106 }
107 }
108}
109
110/// Priority of a CAN frame.
111///
112/// Returned by [`Frame::priority`].
113///
114/// The priority of a frame is determined by the bits that are part of the *arbitration field*.
115/// These consist of the frame identifier bits (including the *IDE* bit, which is 0 for extended
116/// frames and 1 for standard frames), as well as the *RTR* bit, which determines whether a frame
117/// is a data or remote frame. Lower values of the *arbitration field* have higher priority.
118///
119/// This struct wraps the *arbitration field* and implements `PartialOrd` and `Ord` accordingly,
120/// ordering higher priorities greater than lower ones.
121#[derive(Debug, Copy, Clone)]
122pub struct FramePriority(IdReg);
123
124/// Ordering is based on the Identifier and frame type (data vs. remote) and can be used to sort
125/// frames by priority.
126impl Ord for FramePriority {
127 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
128 self.0.cmp(&other.0)
129 }
130}
131
132impl PartialOrd for FramePriority {
133 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
134 Some(self.cmp(other))
135 }
136}
137
138impl PartialEq for FramePriority {
139 fn eq(&self, other: &Self) -> bool {
140 self.cmp(other) == core::cmp::Ordering::Equal
141 }
142}
143
144impl Eq for FramePriority {}
145
146/// Payload of a CAN data frame.
147///
148/// Contains 0 to 8 Bytes of data.
149///
150/// `Data` implements `From<[u8; N]>` for all `N` up to 8, which provides a convenient lossless
151/// conversion from fixed-length arrays.
152#[derive(Debug, Copy, Clone)]
153pub struct Data {
154 pub(crate) len: u8,
155 pub(crate) bytes: [u8; 8],
156}
157
158impl Data {
159 /// Creates a data payload from a raw byte slice.
160 ///
161 /// Returns `None` if `data` contains more than 8 Bytes (which is the maximum).
162 ///
163 /// `Data` can also be constructed from fixed-length arrays up to length 8 via `From`/`Into`.
164 pub fn new(data: &[u8]) -> Option<Self> {
165 if data.len() > 8 {
166 return None;
167 }
168
169 let mut bytes = [0; 8];
170 bytes[..data.len()].copy_from_slice(data);
171
172 Some(Self {
173 len: data.len() as u8,
174 bytes,
175 })
176 }
177
178 /// Creates an empty data payload containing 0 bytes.
179 #[inline]
180 pub const fn empty() -> Self {
181 Self { len: 0, bytes: [0; 8] }
182 }
183}
184
185impl Deref for Data {
186 type Target = [u8];
187
188 #[inline]
189 fn deref(&self) -> &[u8] {
190 &self.bytes[..usize::from(self.len)]
191 }
192}
193
194impl DerefMut for Data {
195 #[inline]
196 fn deref_mut(&mut self) -> &mut [u8] {
197 &mut self.bytes[..usize::from(self.len)]
198 }
199}
200
201impl AsRef<[u8]> for Data {
202 #[inline]
203 fn as_ref(&self) -> &[u8] {
204 self.deref()
205 }
206}
207
208impl AsMut<[u8]> for Data {
209 #[inline]
210 fn as_mut(&mut self) -> &mut [u8] {
211 self.deref_mut()
212 }
213}
214
215impl PartialEq for Data {
216 fn eq(&self, other: &Self) -> bool {
217 self.as_ref() == other.as_ref()
218 }
219}
220
221impl Eq for Data {}
222
223#[cfg(feature = "defmt")]
224impl defmt::Format for Data {
225 fn format(&self, fmt: defmt::Formatter<'_>) {
226 self.as_ref().format(fmt)
227 }
228}
229
230macro_rules! data_from_array {
231 ( $($len:literal),+ ) => {
232 $(
233 impl From<[u8; $len]> for Data {
234 #[inline]
235 fn from(arr: [u8; $len]) -> Self {
236 let mut bytes = [0; 8];
237 bytes[..$len].copy_from_slice(&arr);
238 Self {
239 len: $len,
240 bytes,
241 }
242 }
243 }
244 )+
245 };
246}
247
248data_from_array!(0, 1, 2, 3, 4, 5, 6, 7, 8);
diff --git a/embassy-stm32/src/can/bx/id.rs b/embassy-stm32/src/can/bx/id.rs
deleted file mode 100644
index 9fdcd8319..000000000
--- a/embassy-stm32/src/can/bx/id.rs
+++ /dev/null
@@ -1,113 +0,0 @@
1//! CAN Identifiers.
2
3/// Standard 11-bit CAN Identifier (`0..=0x7FF`).
4#[derive(Debug, Copy, Clone, Eq, PartialEq)]
5pub struct StandardId(u16);
6
7impl StandardId {
8 /// CAN ID `0`, the highest priority.
9 pub const ZERO: Self = Self(0);
10
11 /// CAN ID `0x7FF`, the lowest priority.
12 pub const MAX: Self = Self(0x7FF);
13
14 /// Tries to create a `StandardId` from a raw 16-bit integer.
15 ///
16 /// This will return `None` if `raw` is out of range of an 11-bit integer (`> 0x7FF`).
17 #[inline]
18 pub const fn new(raw: u16) -> Option<Self> {
19 if raw <= 0x7FF {
20 Some(Self(raw))
21 } else {
22 None
23 }
24 }
25
26 /// Creates a new `StandardId` without checking if it is inside the valid range.
27 ///
28 /// # Safety
29 ///
30 /// The caller must ensure that `raw` is in the valid range, otherwise the behavior is
31 /// undefined.
32 #[inline]
33 pub const unsafe fn new_unchecked(raw: u16) -> Self {
34 Self(raw)
35 }
36
37 /// Returns this CAN Identifier as a raw 16-bit integer.
38 #[inline]
39 pub fn as_raw(&self) -> u16 {
40 self.0
41 }
42}
43
44/// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`).
45#[derive(Debug, Copy, Clone, Eq, PartialEq)]
46pub struct ExtendedId(u32);
47
48impl ExtendedId {
49 /// CAN ID `0`, the highest priority.
50 pub const ZERO: Self = Self(0);
51
52 /// CAN ID `0x1FFFFFFF`, the lowest priority.
53 pub const MAX: Self = Self(0x1FFF_FFFF);
54
55 /// Tries to create a `ExtendedId` from a raw 32-bit integer.
56 ///
57 /// This will return `None` if `raw` is out of range of an 29-bit integer (`> 0x1FFF_FFFF`).
58 #[inline]
59 pub const fn new(raw: u32) -> Option<Self> {
60 if raw <= 0x1FFF_FFFF {
61 Some(Self(raw))
62 } else {
63 None
64 }
65 }
66
67 /// Creates a new `ExtendedId` without checking if it is inside the valid range.
68 ///
69 /// # Safety
70 ///
71 /// The caller must ensure that `raw` is in the valid range, otherwise the behavior is
72 /// undefined.
73 #[inline]
74 pub const unsafe fn new_unchecked(raw: u32) -> Self {
75 Self(raw)
76 }
77
78 /// Returns this CAN Identifier as a raw 32-bit integer.
79 #[inline]
80 pub fn as_raw(&self) -> u32 {
81 self.0
82 }
83
84 /// Returns the Base ID part of this extended identifier.
85 pub fn standard_id(&self) -> StandardId {
86 // ID-28 to ID-18
87 StandardId((self.0 >> 18) as u16)
88 }
89}
90
91/// A CAN Identifier (standard or extended).
92#[derive(Debug, Copy, Clone, Eq, PartialEq)]
93pub enum Id {
94 /// Standard 11-bit Identifier (`0..=0x7FF`).
95 Standard(StandardId),
96
97 /// Extended 29-bit Identifier (`0..=0x1FFF_FFFF`).
98 Extended(ExtendedId),
99}
100
101impl From<StandardId> for Id {
102 #[inline]
103 fn from(id: StandardId) -> Self {
104 Id::Standard(id)
105 }
106}
107
108impl From<ExtendedId> for Id {
109 #[inline]
110 fn from(id: ExtendedId) -> Self {
111 Id::Extended(id)
112 }
113}
diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs
index f639260a1..33e702c6e 100644
--- a/embassy-stm32/src/can/bx/mod.rs
+++ b/embassy-stm32/src/can/bx/mod.rs
@@ -25,19 +25,25 @@
25 25
26//mod embedded_hal; 26//mod embedded_hal;
27pub mod filter; 27pub mod filter;
28mod frame;
29mod id;
30 28
31#[allow(clippy::all)] // generated code 29#[allow(clippy::all)] // generated code
32use core::cmp::{Ord, Ordering}; 30use core::cmp::{Ord, Ordering};
33use core::convert::{Infallible, TryInto}; 31use core::convert::{Infallible, Into, TryInto};
34use core::marker::PhantomData; 32use core::marker::PhantomData;
35use core::mem; 33use core::mem;
36 34
37pub use id::{ExtendedId, Id, StandardId}; 35pub use embedded_can::{ExtendedId, Id, StandardId};
36
37/// CAN Header: includes ID and length
38pub type Header = crate::can::frame::Header;
39
40/// Data for a CAN Frame
41pub type Data = crate::can::frame::ClassicData;
42
43/// CAN Frame
44pub type Frame = crate::can::frame::ClassicFrame;
38 45
39use crate::can::bx::filter::MasterFilters; 46use crate::can::bx::filter::MasterFilters;
40pub use crate::can::bx::frame::{Data, Frame, FramePriority};
41 47
42/// A bxCAN peripheral instance. 48/// A bxCAN peripheral instance.
43/// 49///
@@ -145,23 +151,25 @@ impl IdReg {
145 Self(reg & 0xFFFF_FFFE) 151 Self(reg & 0xFFFF_FFFE)
146 } 152 }
147 153
148 /// Sets the remote transmission (RTR) flag. This marks the identifier as 154 /// Returns the identifier.
149 /// being part of a remote frame. 155 fn to_id(self) -> Id {
150 #[must_use = "returns a new IdReg without modifying `self`"] 156 if self.is_extended() {
151 fn with_rtr(self, rtr: bool) -> IdReg { 157 Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) })
152 if rtr {
153 Self(self.0 | Self::RTR_MASK)
154 } else { 158 } else {
155 Self(self.0 & !Self::RTR_MASK) 159 Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) })
156 } 160 }
157 } 161 }
158 162
159 /// Returns the identifier. 163 /// Returns the identifier.
160 fn to_id(self) -> Id { 164 fn id(self) -> embedded_can::Id {
161 if self.is_extended() { 165 if self.is_extended() {
162 Id::Extended(unsafe { ExtendedId::new_unchecked(self.0 >> Self::EXTENDED_SHIFT) }) 166 embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT)
167 .unwrap()
168 .into()
163 } else { 169 } else {
164 Id::Standard(unsafe { StandardId::new_unchecked((self.0 >> Self::STANDARD_SHIFT) as u16) }) 170 embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16)
171 .unwrap()
172 .into()
165 } 173 }
166 } 174 }
167 175
@@ -170,17 +178,27 @@ impl IdReg {
170 self.0 & Self::IDE_MASK != 0 178 self.0 & Self::IDE_MASK != 0
171 } 179 }
172 180
173 /// Returns `true` if the identifier is a standard identifier.
174 fn is_standard(self) -> bool {
175 !self.is_extended()
176 }
177
178 /// Returns `true` if the identifer is part of a remote frame (RTR bit set). 181 /// Returns `true` if the identifer is part of a remote frame (RTR bit set).
179 fn rtr(self) -> bool { 182 fn rtr(self) -> bool {
180 self.0 & Self::RTR_MASK != 0 183 self.0 & Self::RTR_MASK != 0
181 } 184 }
182} 185}
183 186
187impl From<&embedded_can::Id> for IdReg {
188 fn from(eid: &embedded_can::Id) -> Self {
189 match eid {
190 embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()),
191 embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()),
192 }
193 }
194}
195
196impl From<IdReg> for embedded_can::Id {
197 fn from(idr: IdReg) -> Self {
198 idr.id()
199 }
200}
201
184/// `IdReg` is ordered by priority. 202/// `IdReg` is ordered by priority.
185impl Ord for IdReg { 203impl Ord for IdReg {
186 fn cmp(&self, other: &Self) -> Ordering { 204 fn cmp(&self, other: &Self) -> Ordering {
@@ -682,9 +700,9 @@ where
682 // The controller schedules pending frames of same priority based on the 700 // The controller schedules pending frames of same priority based on the
683 // mailbox index instead. As a workaround check all pending mailboxes 701 // mailbox index instead. As a workaround check all pending mailboxes
684 // and only accept higher priority frames. 702 // and only accept higher priority frames.
685 self.check_priority(0, frame.id)?; 703 self.check_priority(0, frame.id().into())?;
686 self.check_priority(1, frame.id)?; 704 self.check_priority(1, frame.id().into())?;
687 self.check_priority(2, frame.id)?; 705 self.check_priority(2, frame.id().into())?;
688 706
689 let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); 707 let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2);
690 if all_frames_are_pending { 708 if all_frames_are_pending {
@@ -739,14 +757,15 @@ where
739 debug_assert!(idx < 3); 757 debug_assert!(idx < 3);
740 758
741 let mb = self.canregs.tx(idx); 759 let mb = self.canregs.tx(idx);
742 mb.tdtr().write(|w| w.set_dlc(frame.dlc() as u8)); 760 mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8));
743 761
744 mb.tdlr() 762 mb.tdlr()
745 .write(|w| w.0 = u32::from_ne_bytes(frame.data.bytes[0..4].try_into().unwrap())); 763 .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap()));
746 mb.tdhr() 764 mb.tdhr()
747 .write(|w| w.0 = u32::from_ne_bytes(frame.data.bytes[4..8].try_into().unwrap())); 765 .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap()));
766 let id: IdReg = frame.id().into();
748 mb.tir().write(|w| { 767 mb.tir().write(|w| {
749 w.0 = frame.id.0; 768 w.0 = id.0;
750 w.set_txrq(true); 769 w.set_txrq(true);
751 }); 770 });
752 } 771 }
@@ -756,16 +775,14 @@ where
756 debug_assert!(idx < 3); 775 debug_assert!(idx < 3);
757 776
758 let mb = self.canregs.tx(idx); 777 let mb = self.canregs.tx(idx);
759 // Read back the pending frame. 778
760 let mut pending_frame = Frame { 779 let id = IdReg(mb.tir().read().0).id();
761 id: IdReg(mb.tir().read().0), 780 let mut data = [0xff; 8];
762 data: Data::empty(), 781 data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes());
763 }; 782 data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes());
764 pending_frame.data.bytes[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); 783 let len = mb.tdtr().read().dlc();
765 pending_frame.data.bytes[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); 784
766 pending_frame.data.len = mb.tdtr().read().dlc(); 785 Some(Frame::new(Header::new(id, len, false), &data).unwrap())
767
768 Some(pending_frame)
769 } else { 786 } else {
770 // Abort request failed because the frame was already sent (or being sent) on 787 // Abort request failed because the frame was already sent (or being sent) on
771 // the bus. All mailboxes are now free. This can happen for small prescaler 788 // the bus. All mailboxes are now free. This can happen for small prescaler
@@ -898,18 +915,16 @@ fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result<Fra
898 } 915 }
899 916
900 // Read the frame. 917 // Read the frame.
901 let mut frame = Frame { 918 let id = IdReg(rx.rir().read().0).id();
902 id: IdReg(rx.rir().read().0), 919 let mut data = [0xff; 8];
903 data: [0; 8].into(), 920 data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes());
904 }; 921 data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes());
905 frame.data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes()); 922 let len = rx.rdtr().read().dlc();
906 frame.data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes());
907 frame.data.len = rx.rdtr().read().dlc();
908 923
909 // Release the mailbox. 924 // Release the mailbox.
910 rfr.write(|w| w.set_rfom(true)); 925 rfr.write(|w| w.set_rfom(true));
911 926
912 Ok(frame) 927 Ok(Frame::new(Header::new(id, len, false), &data).unwrap())
913} 928}
914 929
915/// Identifies one of the two receive FIFOs. 930/// Identifies one of the two receive FIFOs.
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index acd831937..bb7cc3d7f 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -6,7 +6,7 @@ use core::task::Poll;
6 6
7pub mod bx; 7pub mod bx;
8 8
9pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Id, StandardId}; 9pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Header, Id, StandardId};
10use embassy_hal_internal::{into_ref, PeripheralRef}; 10use embassy_hal_internal::{into_ref, PeripheralRef};
11use futures::FutureExt; 11use futures::FutureExt;
12 12
@@ -18,19 +18,20 @@ use crate::{interrupt, peripherals, Peripheral};
18 18
19pub mod enums; 19pub mod enums;
20use enums::*; 20use enums::*;
21pub mod frame;
21pub mod util; 22pub mod util;
22 23
23/// Contains CAN frame and additional metadata. 24/// Contains CAN frame and additional metadata.
24/// 25///
25/// Timestamp is available if `time` feature is enabled. 26/// Timestamp is available if `time` feature is enabled.
26#[derive(Debug, Clone, PartialEq, Eq)] 27#[derive(Debug, Clone)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))] 28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28pub struct Envelope { 29pub struct Envelope {
29 /// Reception time. 30 /// Reception time.
30 #[cfg(feature = "time")] 31 #[cfg(feature = "time")]
31 pub ts: embassy_time::Instant, 32 pub ts: embassy_time::Instant,
32 /// The actual CAN frame. 33 /// The actual CAN frame.
33 pub frame: crate::can::bx::Frame, 34 pub frame: Frame,
34} 35}
35 36
36/// Interrupt handler. 37/// Interrupt handler.
@@ -260,20 +261,20 @@ impl<'d, T: Instance> Can<'d, T> {
260 } 261 }
261 262
262 let rir = fifo.rir().read(); 263 let rir = fifo.rir().read();
263 let id = if rir.ide() == Ide::STANDARD { 264 let id: embedded_can::Id = if rir.ide() == Ide::STANDARD {
264 Id::from(StandardId::new_unchecked(rir.stid())) 265 embedded_can::StandardId::new(rir.stid()).unwrap().into()
265 } else { 266 } else {
266 let stid = (rir.stid() & 0x7FF) as u32; 267 let stid = (rir.stid() & 0x7FF) as u32;
267 let exid = rir.exid() & 0x3FFFF; 268 let exid = rir.exid() & 0x3FFFF;
268 let id = (stid << 18) | (exid); 269 let id = (stid << 18) | (exid);
269 Id::from(ExtendedId::new_unchecked(id)) 270 embedded_can::ExtendedId::new(id).unwrap().into()
270 }; 271 };
271 let data_len = fifo.rdtr().read().dlc() as usize; 272 let data_len = fifo.rdtr().read().dlc();
272 let mut data: [u8; 8] = [0; 8]; 273 let mut data: [u8; 8] = [0; 8];
273 data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); 274 data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes());
274 data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); 275 data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes());
275 276
276 let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap()); 277 let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap();
277 let envelope = Envelope { 278 let envelope = Envelope {
278 #[cfg(feature = "time")] 279 #[cfg(feature = "time")]
279 ts, 280 ts,
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs
index 36139a45c..651de9194 100644
--- a/embassy-stm32/src/can/enums.rs
+++ b/embassy-stm32/src/can/enums.rs
@@ -28,3 +28,15 @@ pub enum BusError {
28 /// At least one of error counter has reached the Error_Warning limit of 96. 28 /// At least one of error counter has reached the Error_Warning limit of 96.
29 BusWarning, 29 BusWarning,
30} 30}
31
32/// Frame Create Errors
33#[derive(Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub enum FrameCreateError {
36 /// Data in header does not match supplied.
37 NotEnoughData,
38 /// Invalid data length not 0-8 for Classic packet or valid for FD.
39 InvalidDataLength,
40 /// Invalid ID.
41 InvalidCanId,
42}
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index 8ec09ac12..e14977d91 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -56,7 +56,10 @@ impl Registers {
56 match maybe_header { 56 match maybe_header {
57 Some((header, ts)) => { 57 Some((header, ts)) => {
58 let data = &buffer[0..header.len() as usize]; 58 let data = &buffer[0..header.len() as usize];
59 Some((F::from_header(header, data)?, ts)) 59 match F::from_header(header, data) {
60 Ok(frame) => Some((frame, ts)),
61 Err(_) => None,
62 }
60 } 63 }
61 None => None, 64 None => None,
62 } 65 }
@@ -182,7 +185,7 @@ impl Registers {
182 DataLength::Fdcan(len) => len, 185 DataLength::Fdcan(len) => len,
183 DataLength::Classic(len) => len, 186 DataLength::Classic(len) => len,
184 }; 187 };
185 if len as usize > ClassicFrame::MAX_DATA_LEN { 188 if len as usize > ClassicData::MAX_DATA_LEN {
186 return None; 189 return None;
187 } 190 }
188 191
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs
index 9c293035d..14fc32c51 100644
--- a/embassy-stm32/src/can/frame.rs
+++ b/embassy-stm32/src/can/frame.rs
@@ -1,6 +1,8 @@
1//! Definition for CAN Frames 1//! Definition for CAN Frames
2use bit_field::BitField; 2use bit_field::BitField;
3 3
4use crate::can::enums::FrameCreateError;
5
4/// CAN Header, without meta data 6/// CAN Header, without meta data
5#[derive(Debug, Copy, Clone)] 7#[derive(Debug, Copy, Clone)]
6pub struct Header { 8pub struct Header {
@@ -9,6 +11,20 @@ pub struct Header {
9 flags: u8, 11 flags: u8,
10} 12}
11 13
14#[cfg(feature = "defmt")]
15impl defmt::Format for Header {
16 fn format(&self, fmt: defmt::Formatter<'_>) {
17 match self.id() {
18 embedded_can::Id::Standard(id) => {
19 defmt::write!(fmt, "Can Standard ID={:x} len={}", id.as_raw(), self.len,)
20 }
21 embedded_can::Id::Extended(id) => {
22 defmt::write!(fmt, "Can Extended ID={:x} len={}", id.as_raw(), self.len,)
23 }
24 }
25 }
26}
27
12impl Header { 28impl Header {
13 const FLAG_RTR: usize = 0; // Remote 29 const FLAG_RTR: usize = 0; // Remote
14 const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN 30 const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN
@@ -54,13 +70,21 @@ impl Header {
54 pub fn bit_rate_switching(&self) -> bool { 70 pub fn bit_rate_switching(&self) -> bool {
55 self.flags.get_bit(Self::FLAG_BRS) 71 self.flags.get_bit(Self::FLAG_BRS)
56 } 72 }
73
74 /// Get priority of frame
75 pub(crate) fn priority(&self) -> u32 {
76 match self.id() {
77 embedded_can::Id::Standard(id) => (id.as_raw() as u32) << 18,
78 embedded_can::Id::Extended(id) => id.as_raw(),
79 }
80 }
57} 81}
58 82
59/// Trait for FDCAN frame types, providing ability to construct from a Header 83/// Trait for FDCAN frame types, providing ability to construct from a Header
60/// and to retrieve the Header from a frame 84/// and to retrieve the Header from a frame
61pub trait CanHeader: Sized { 85pub trait CanHeader: Sized {
62 /// Construct frame from header and payload 86 /// Construct frame from header and payload
63 fn from_header(header: Header, data: &[u8]) -> Option<Self>; 87 fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError>;
64 88
65 /// Get this frame's header struct 89 /// Get this frame's header struct
66 fn header(&self) -> &Header; 90 fn header(&self) -> &Header;
@@ -70,24 +94,26 @@ pub trait CanHeader: Sized {
70/// 94///
71/// Contains 0 to 8 Bytes of data. 95/// Contains 0 to 8 Bytes of data.
72#[derive(Debug, Copy, Clone)] 96#[derive(Debug, Copy, Clone)]
97#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73pub struct ClassicData { 98pub struct ClassicData {
74 pub(crate) bytes: [u8; 8], 99 pub(crate) bytes: [u8; Self::MAX_DATA_LEN],
75} 100}
76 101
77impl ClassicData { 102impl ClassicData {
103 pub(crate) const MAX_DATA_LEN: usize = 8;
78 /// Creates a data payload from a raw byte slice. 104 /// Creates a data payload from a raw byte slice.
79 /// 105 ///
80 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or 106 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
81 /// cannot be represented with an FDCAN DLC. 107 /// cannot be represented with an FDCAN DLC.
82 pub fn new(data: &[u8]) -> Option<Self> { 108 pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
83 if !FdData::is_valid_len(data.len()) { 109 if data.len() > 8 {
84 return None; 110 return Err(FrameCreateError::InvalidDataLength);
85 } 111 }
86 112
87 let mut bytes = [0; 8]; 113 let mut bytes = [0; 8];
88 bytes[..data.len()].copy_from_slice(data); 114 bytes[..data.len()].copy_from_slice(data);
89 115
90 Some(Self { bytes }) 116 Ok(Self { bytes })
91 } 117 }
92 118
93 /// Raw read access to data. 119 /// Raw read access to data.
@@ -112,58 +138,50 @@ impl ClassicData {
112 138
113/// Frame with up to 8 bytes of data payload as per Classic CAN 139/// Frame with up to 8 bytes of data payload as per Classic CAN
114#[derive(Debug, Copy, Clone)] 140#[derive(Debug, Copy, Clone)]
141#[cfg_attr(feature = "defmt", derive(defmt::Format))]
115pub struct ClassicFrame { 142pub struct ClassicFrame {
116 can_header: Header, 143 can_header: Header,
117 data: ClassicData, 144 data: ClassicData,
118} 145}
119 146
120impl ClassicFrame { 147impl ClassicFrame {
121 pub(crate) const MAX_DATA_LEN: usize = 8;
122
123 /// Create a new CAN classic Frame 148 /// Create a new CAN classic Frame
124 pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame { 149 pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
125 ClassicFrame { can_header, data } 150 let data = ClassicData::new(raw_data)?;
151 Ok(ClassicFrame { can_header, data: data })
152 }
153
154 /// Creates a new data frame.
155 pub fn new_data(id: impl Into<embedded_can::Id>, data: &[u8]) -> Result<Self, FrameCreateError> {
156 let eid: embedded_can::Id = id.into();
157 let header = Header::new(eid, data.len() as u8, false);
158 Self::new(header, data)
126 } 159 }
127 160
128 /// Create new extended frame 161 /// Create new extended frame
129 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { 162 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
130 if let Some(id) = embedded_can::ExtendedId::new(raw_id) { 163 if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
131 match ClassicData::new(raw_data) { 164 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
132 Some(data) => Some(ClassicFrame::new(
133 Header::new(id.into(), raw_data.len() as u8, false),
134 data,
135 )),
136 None => None,
137 }
138 } else { 165 } else {
139 None 166 Err(FrameCreateError::InvalidCanId)
140 } 167 }
141 } 168 }
142 169
143 /// Create new standard frame 170 /// Create new standard frame
144 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { 171 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
145 if let Some(id) = embedded_can::StandardId::new(raw_id) { 172 if let Some(id) = embedded_can::StandardId::new(raw_id) {
146 match ClassicData::new(raw_data) { 173 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
147 Some(data) => Some(ClassicFrame::new(
148 Header::new(id.into(), raw_data.len() as u8, false),
149 data,
150 )),
151 None => None,
152 }
153 } else { 174 } else {
154 None 175 Err(FrameCreateError::InvalidCanId)
155 } 176 }
156 } 177 }
157 178
158 /// Create new remote frame 179 /// Create new remote frame
159 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { 180 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> {
160 if len <= 8usize { 181 if len <= 8usize {
161 Some(ClassicFrame::new( 182 Self::new(Header::new(id.into(), len as u8, true), &[0; 8])
162 Header::new(id.into(), len as u8, true),
163 ClassicData::empty(),
164 ))
165 } else { 183 } else {
166 None 184 Err(FrameCreateError::InvalidDataLength)
167 } 185 }
168 } 186 }
169 187
@@ -181,24 +199,28 @@ impl ClassicFrame {
181 pub fn data(&self) -> &[u8] { 199 pub fn data(&self) -> &[u8] {
182 &self.data.raw() 200 &self.data.raw()
183 } 201 }
202
203 /// Get priority of frame
204 pub fn priority(&self) -> u32 {
205 self.header().priority()
206 }
184} 207}
185 208
186impl embedded_can::Frame for ClassicFrame { 209impl embedded_can::Frame for ClassicFrame {
187 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { 210 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
188 match ClassicData::new(raw_data) { 211 let frameopt = ClassicFrame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
189 Some(data) => Some(ClassicFrame::new( 212 match frameopt {
190 Header::new(id.into(), raw_data.len() as u8, false), 213 Ok(frame) => Some(frame),
191 data, 214 Err(_) => None,
192 )),
193 None => None,
194 } 215 }
195 } 216 }
196 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { 217 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
197 if len <= 8 { 218 if len <= 8 {
198 Some(ClassicFrame::new( 219 let frameopt = ClassicFrame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
199 Header::new(id.into(), len as u8, true), 220 match frameopt {
200 ClassicData::empty(), 221 Ok(frame) => Some(frame),
201 )) 222 Err(_) => None,
223 }
202 } else { 224 } else {
203 None 225 None
204 } 226 }
@@ -224,8 +246,8 @@ impl embedded_can::Frame for ClassicFrame {
224} 246}
225 247
226impl CanHeader for ClassicFrame { 248impl CanHeader for ClassicFrame {
227 fn from_header(header: Header, data: &[u8]) -> Option<Self> { 249 fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
228 Some(Self::new(header, ClassicData::new(data)?)) 250 Self::new(header, data)
229 } 251 }
230 252
231 fn header(&self) -> &Header { 253 fn header(&self) -> &Header {
@@ -246,15 +268,15 @@ impl FdData {
246 /// 268 ///
247 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or 269 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
248 /// cannot be represented with an FDCAN DLC. 270 /// cannot be represented with an FDCAN DLC.
249 pub fn new(data: &[u8]) -> Option<Self> { 271 pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> {
250 if !FdData::is_valid_len(data.len()) { 272 if !FdData::is_valid_len(data.len()) {
251 return None; 273 return Err(FrameCreateError::InvalidDataLength);
252 } 274 }
253 275
254 let mut bytes = [0; 64]; 276 let mut bytes = [0; 64];
255 bytes[..data.len()].copy_from_slice(data); 277 bytes[..data.len()].copy_from_slice(data);
256 278
257 Some(Self { bytes }) 279 Ok(Self { bytes })
258 } 280 }
259 281
260 /// Raw read access to data. 282 /// Raw read access to data.
@@ -293,40 +315,35 @@ pub struct FdFrame {
293 315
294impl FdFrame { 316impl FdFrame {
295 /// Create a new CAN classic Frame 317 /// Create a new CAN classic Frame
296 pub fn new(can_header: Header, data: FdData) -> FdFrame { 318 pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
297 FdFrame { can_header, data } 319 let data = FdData::new(raw_data)?;
320 Ok(FdFrame { can_header, data })
298 } 321 }
299 322
300 /// Create new extended frame 323 /// Create new extended frame
301 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Option<Self> { 324 pub fn new_extended(raw_id: u32, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
302 if let Some(id) = embedded_can::ExtendedId::new(raw_id) { 325 if let Some(id) = embedded_can::ExtendedId::new(raw_id) {
303 match FdData::new(raw_data) { 326 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
304 Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
305 None => None,
306 }
307 } else { 327 } else {
308 None 328 Err(FrameCreateError::InvalidCanId)
309 } 329 }
310 } 330 }
311 331
312 /// Create new standard frame 332 /// Create new standard frame
313 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Option<Self> { 333 pub fn new_standard(raw_id: u16, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
314 if let Some(id) = embedded_can::StandardId::new(raw_id) { 334 if let Some(id) = embedded_can::StandardId::new(raw_id) {
315 match FdData::new(raw_data) { 335 Self::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data)
316 Some(data) => Some(FdFrame::new(Header::new(id.into(), raw_data.len() as u8, false), data)),
317 None => None,
318 }
319 } else { 336 } else {
320 None 337 Err(FrameCreateError::InvalidCanId)
321 } 338 }
322 } 339 }
323 340
324 /// Create new remote frame 341 /// Create new remote frame
325 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { 342 pub fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Result<Self, FrameCreateError> {
326 if len <= 8 { 343 if len <= 8 {
327 Some(FdFrame::new(Header::new(id.into(), len as u8, true), FdData::empty())) 344 Self::new(Header::new(id.into(), len as u8, true), &[0; 8])
328 } else { 345 } else {
329 None 346 Err(FrameCreateError::InvalidDataLength)
330 } 347 }
331 } 348 }
332 349
@@ -348,20 +365,17 @@ impl FdFrame {
348 365
349impl embedded_can::Frame for FdFrame { 366impl embedded_can::Frame for FdFrame {
350 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> { 367 fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
351 match FdData::new(raw_data) { 368 match FdFrame::new(Header::new_fd(id.into(), raw_data.len() as u8, false, true), raw_data) {
352 Some(data) => Some(FdFrame::new( 369 Ok(frame) => Some(frame),
353 Header::new_fd(id.into(), raw_data.len() as u8, false, true), 370 Err(_) => None,
354 data,
355 )),
356 None => None,
357 } 371 }
358 } 372 }
359 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> { 373 fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
360 if len <= 8 { 374 if len <= 8 {
361 Some(FdFrame::new( 375 match FdFrame::new(Header::new_fd(id.into(), len as u8, true, true), &[0; 64]) {
362 Header::new_fd(id.into(), len as u8, true, true), 376 Ok(frame) => Some(frame),
363 FdData::empty(), 377 Err(_) => None,
364 )) 378 }
365 } else { 379 } else {
366 None 380 None
367 } 381 }
@@ -388,8 +402,8 @@ impl embedded_can::Frame for FdFrame {
388} 402}
389 403
390impl CanHeader for FdFrame { 404impl CanHeader for FdFrame {
391 fn from_header(header: Header, data: &[u8]) -> Option<Self> { 405 fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
392 Some(Self::new(header, FdData::new(data)?)) 406 Self::new(header, data)
393 } 407 }
394 408
395 fn header(&self) -> &Header { 409 fn header(&self) -> &Header {
diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs
index 00d61096f..ac337e8a0 100644
--- a/examples/stm32f1/src/bin/can.rs
+++ b/examples/stm32f1/src/bin/can.rs
@@ -46,16 +46,16 @@ async fn main(_spawner: Spawner) {
46 46
47 let mut i: u8 = 0; 47 let mut i: u8 = 0;
48 loop { 48 loop {
49 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i, 0, 1, 2, 3, 4, 5, 6]); 49 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
50 can.write(&tx_frame).await; 50 can.write(&tx_frame).await;
51 51
52 match can.read().await { 52 match can.read().await {
53 Ok(env) => match env.frame.id() { 53 Ok(env) => match env.frame.id() {
54 Id::Extended(id) => { 54 Id::Extended(id) => {
55 defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data().unwrap()); 55 defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
56 } 56 }
57 Id::Standard(id) => { 57 Id::Standard(id) => {
58 defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data().unwrap()); 58 defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
59 } 59 }
60 }, 60 },
61 Err(err) => { 61 Err(err) => {
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs
index b20af8cf1..71b9453eb 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -51,7 +51,7 @@ async fn main(_spawner: Spawner) {
51 51
52 let mut i: u8 = 0; 52 let mut i: u8 = 0;
53 loop { 53 loop {
54 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 54 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap();
55 let tx_ts = Instant::now(); 55 let tx_ts = Instant::now();
56 can.write(&tx_frame).await; 56 can.write(&tx_frame).await;
57 57
@@ -65,7 +65,7 @@ async fn main(_spawner: Spawner) {
65 65
66 info!( 66 info!(
67 "loopback frame {=u8}, latency: {} us", 67 "loopback frame {=u8}, latency: {} us",
68 unwrap!(envelope.frame.data())[0], 68 envelope.frame.data()[0],
69 latency.as_micros() 69 latency.as_micros()
70 ); 70 );
71 i += 1; 71 i += 1;
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs
index c3e14bbf4..221ac2a05 100644
--- a/examples/stm32f7/src/bin/can.rs
+++ b/examples/stm32f7/src/bin/can.rs
@@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs {
26#[embassy_executor::task] 26#[embassy_executor::task]
27pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) { 27pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) {
28 loop { 28 loop {
29 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]); 29 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap();
30 tx.write(&frame).await; 30 tx.write(&frame).await;
31 embassy_time::Timer::after_secs(1).await; 31 embassy_time::Timer::after_secs(1).await;
32 } 32 }
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
index e869e8fb9..c08c69a3b 100644
--- a/tests/stm32/src/bin/can.rs
+++ b/tests/stm32/src/bin/can.rs
@@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) {
60 60
61 let mut i: u8 = 0; 61 let mut i: u8 = 0;
62 loop { 62 loop {
63 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 63 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap();
64 64
65 info!("Transmitting frame..."); 65 info!("Transmitting frame...");
66 let tx_ts = Instant::now(); 66 let tx_ts = Instant::now();
@@ -70,7 +70,7 @@ async fn main(_spawner: Spawner) {
70 info!("Frame received!"); 70 info!("Frame received!");
71 71
72 info!("loopback time {}", envelope.ts); 72 info!("loopback time {}", envelope.ts);
73 info!("loopback frame {=u8}", envelope.frame.data().unwrap()[0]); 73 info!("loopback frame {=u8}", envelope.frame.data()[0]);
74 74
75 let latency = envelope.ts.saturating_duration_since(tx_ts); 75 let latency = envelope.ts.saturating_duration_since(tx_ts);
76 info!("loopback latency {} us", latency.as_micros()); 76 info!("loopback latency {} us", latency.as_micros());