Closed blaa closed 9 months ago
I gathered changes from (2) and (4) on new branch to create something that might be mergeable - no debug prints, cleanly split commits, no commented code. Moved the example from FDCAN2/3 to FDCAN1. It compiles example for stm32g4, I haven't yet tried it on hardware at least in loopback mode it seems to work on stm32g431.
Lacking:
https://github.com/blaa/embassy/commits/feature/fdcan/
Two not included parts (were commented) are:
+ /*
+ pub async fn flush(&self, mb: bxcan::Mailbox) {
+ poll_fn(|cx| {
+ T::state().tx_waker.register(cx.waker());
+ if T::regs().tsr().read().tme(mb.index()) {
+ return Poll::Ready(());
+ }
+
+ Poll::Pending
+ })
+ .await;
+ }*/
+// TODO: impl Drop prevents us from changing modes without dropping the old one.
+// there is a solution here but I need to think about it more
+/*
+impl<'d, T: Instance, M: FdcanOperatingMode> Drop for Fdcan<'d, T, M> {
+ fn drop(&mut self) {
+ // Cannot call `free()` because it moves the instance.
+ // Manually reset the peripheral.
+ T::regs().cccr().write(|w| w.set_init(true));
+ T::disable();
+ }
+}
+ */
+
@blaa let myself and @aaamorgan know if you need a hand reviewing or implementing anything for this. We are quite interested in getting what we built in (4) above merged in and if you have combined those forks that seems like a good place to start working from. Happy to help with docs, test code, and any hardware testing that's needed. We have hardware that has a G4 with two transceivers that can be setup to talk to each other if that helps any for testing.
I'm on the Embassy matrix as kevlan
if you want to ping me there to chat through anything as well.
Hi have been kicking this can a little further down the road at: https://github.com/embassy-rs/embassy/compare/main...cschuhen:embassy:feature/fdcan I added a HIL (internal loopback) test and added basic documentation for all of the public's that needed it. Tonight (Brisbane time) I intend to clean the changesets up a bit, squishing and reverting some of my own testing changes. Hopefully then it will be in shape to PR and get opinions from the core embassy developers.
Heh, just an hour minutes ago I started documenting this code. I'll stop and leave it to you then - maybe add some comments somewhere (maybe here). If you wish I can create PR later or leave it to you - as you wish.
I've checked two TODOs in comments and added additional docs to Bit0Error and Bit1Error (but I see you did too! Great work)
My partial local diff follows
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index cc87b256..96f12584 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -16,6 +16,8 @@ use crate::rcc::RccPeripheral;
use crate::time::Hertz;
use crate::{interrupt, peripherals, Peripheral};
+use super::calc_bit_timings;
+
/// Contains CAN frame and additional metadata.
///
/// Timestamp is available if `time` feature is enabled.
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 08f3398a..9c54ca15 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -18,17 +18,25 @@ use crate::interrupt::typelevel::Interrupt;
use crate::rcc::RccPeripheral;
use crate::{interrupt, peripherals, Peripheral};
+// as far as I can tell, embedded-hal/can doesn't have any fdcan frame support
+/// CAN frame (header + data) upon reception.
pub struct RxFrame {
+ /// CAN Header
pub header: RxFrameInfo,
+ /// CAN or FDCAN (8-64 bytes) of data
pub data: Data,
}
+/// CAN frame that will be transmitted.
pub struct TxFrame {
+ /// CAN Header
pub header: TxFrameHeader,
+ /// CAN or FDCAN (8-64 bytes) of data
pub data: Data,
}
impl TxFrame {
+ /// Validate input data and return new TxFrame.
pub fn new(header: TxFrameHeader, data: &[u8]) -> Option<Self> {
if data.len() < header.len as usize {
return None;
@@ -51,10 +59,12 @@ impl TxFrame {
Some(TxFrame { header, data })
}
+ /// Access frame data (without a CAN header)
pub fn data(&self) -> &[u8] {
&self.data.bytes[..(self.header.len as usize)]
}
}
+
impl RxFrame {
pub(crate) fn new(header: RxFrameInfo, data: &[u8]) -> Self {
let data = Data::new(&data).unwrap_or_else(|| Data::empty());
@@ -62,6 +72,7 @@ impl RxFrame {
RxFrame { header, data }
}
+ /// Access frame payload
pub fn data(&self) -> &[u8] {
&self.data.bytes[..(self.header.len as usize)]
}
@@ -91,6 +102,7 @@ impl Data {
Some(Self { bytes })
}
+ /// Access internal raw bytes.
pub fn raw(&self) -> &[u8] {
&self.bytes
}
(...)
#[derive(Debug)]
+/// Possible CAN Bus errors.
pub enum BusError {
+ /// Error: More than 5 equal bits in sequence are not allowed on the bus.
Stuff,
+ /// Error: Fixed part of received frame was invalid.
Form,
+ /// Error: Transmitted messages was not acked.
Acknowledge,
+ /// Error: Error during transmit: sent dominant but read recessive.
BitRecessive,
+ /// Error: Arbitration error during transmit: sent recessive but read dominant.
BitDominant,
+ /// Error: Invalid CRC of received message.
Crc,
+ /// Error: Other software error
Software,
+ /// Error: Bus is in off state.
BusOff,
+ /// Error: Bus is in passive state.
BusPassive,
+ /// Error: Bus is in warning state.
BusWarning,
}
@@ -185,8 +216,10 @@ impl BusError {
fn try_from(lec: LastErrorCode) -> Option<BusError> {
match lec {
LastErrorCode::AckError => Some(BusError::Acknowledge),
- LastErrorCode::Bit0Error => Some(BusError::BitRecessive), // TODO: verify
- LastErrorCode::Bit1Error => Some(BusError::BitDominant), // TODO: verify
+ // `0` data bit encodes a dominant state. `1` data bit is recessive.
+ // Bit0Error: During transmit, the node wanted to send a 0 but monitored a 1
+ LastErrorCode::Bit0Error => Some(BusError::BitRecessive),
+ LastErrorCode::Bit1Error => Some(BusError::BitDominant),
LastErrorCode::CRCError => Some(BusError::Crc),
LastErrorCode::FormError => Some(BusError::Form),
LastErrorCode::StuffError => Some(BusError::Stuff),
I have pushed more changesets and opened a PR but CI is failing.
I have cleaned up the PR.
I have pushed some more fixes after review comments.
Also, for those interested, I have a few more experimental changesets here on my fdcan_experimental branch: https://github.com/cschuhen/embassy/tree/feature/fdcan_experimental I was planning to leave these until after the main merge.
I have pushed some more fixes after review comments.
Also, for those interested, I have a few more experimental changesets here on my fdcan_experimental branch: https://github.com/cschuhen/embassy/tree/feature/fdcan_experimental I was planning to leave these until after the main merge.
This branch is redundant now. The important bits were merged into fdcan_r2
@blaa Can this be closed now?
For those interested, follow up PR: https://github.com/embassy-rs/embassy/pull/2571
Many STM32 devices with "generic" CAN2.0 peripheral are currently supported via the bxcan library. The ones listed in the title have a different peripheral. Additionaly the H7 is a bit different flavor because why not. Those FDCAN peripherals are currently not supported.
There's plenty of semi-coordinated progress on making the FDCAN embassy driver and many partial not-merged solutions. I've created this issue to summarize all information I could gather.
Which was a basis for some other forks.
So my current understanding is to go with the (1) if using H7 or probably (4) if using the rest of devices. But I can't be sure. In near future I'll try (4) with stm32g431 and see how it goes.