mirror of
				https://github.com/embassy-rs/embassy.git
				synced 2025-11-03 22:33:16 +00:00 
			
		
		
		
	Add FDCAN clock registers to G4 RCC.
Author: Adam Morgan <adam@luci.com> Break definitions out of bxcan that can be used innm fdcan. Typo
This commit is contained in:
		
							parent
							
								
									a91a7a8557
								
							
						
					
					
						commit
						03ba45065e
					
				@ -449,7 +449,7 @@ fn main() {
 | 
				
			|||||||
    // ========
 | 
					    // ========
 | 
				
			||||||
    // Generate RccPeripheral impls
 | 
					    // Generate RccPeripheral impls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let refcounted_peripherals = HashSet::from(["usart", "adc"]);
 | 
					    let refcounted_peripherals = HashSet::from(["usart", "adc", "can"]);
 | 
				
			||||||
    let mut refcount_statics = BTreeSet::new();
 | 
					    let mut refcount_statics = BTreeSet::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for p in METADATA.peripherals {
 | 
					    for p in METADATA.peripherals {
 | 
				
			||||||
 | 
				
			|||||||
@ -13,9 +13,12 @@ use crate::gpio::sealed::AFType;
 | 
				
			|||||||
use crate::interrupt::typelevel::Interrupt;
 | 
					use crate::interrupt::typelevel::Interrupt;
 | 
				
			||||||
use crate::pac::can::vals::{Ide, Lec};
 | 
					use crate::pac::can::vals::{Ide, Lec};
 | 
				
			||||||
use crate::rcc::RccPeripheral;
 | 
					use crate::rcc::RccPeripheral;
 | 
				
			||||||
use crate::time::Hertz;
 | 
					 | 
				
			||||||
use crate::{interrupt, peripherals, Peripheral};
 | 
					use crate::{interrupt, peripherals, Peripheral};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod enums;
 | 
				
			||||||
 | 
					use enums::*;
 | 
				
			||||||
 | 
					pub mod util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Contains CAN frame and additional metadata.
 | 
					/// Contains CAN frame and additional metadata.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Timestamp is available if `time` feature is enabled.
 | 
					/// Timestamp is available if `time` feature is enabled.
 | 
				
			||||||
@ -93,23 +96,6 @@ pub struct Can<'d, T: Instance> {
 | 
				
			|||||||
    can: bxcan::Can<BxcanInstance<'d, T>>,
 | 
					    can: bxcan::Can<BxcanInstance<'d, T>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// CAN bus error
 | 
					 | 
				
			||||||
#[allow(missing_docs)]
 | 
					 | 
				
			||||||
#[derive(Debug)]
 | 
					 | 
				
			||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
					 | 
				
			||||||
pub enum BusError {
 | 
					 | 
				
			||||||
    Stuff,
 | 
					 | 
				
			||||||
    Form,
 | 
					 | 
				
			||||||
    Acknowledge,
 | 
					 | 
				
			||||||
    BitRecessive,
 | 
					 | 
				
			||||||
    BitDominant,
 | 
					 | 
				
			||||||
    Crc,
 | 
					 | 
				
			||||||
    Software,
 | 
					 | 
				
			||||||
    BusOff,
 | 
					 | 
				
			||||||
    BusPassive,
 | 
					 | 
				
			||||||
    BusWarning,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Error returned by `try_read`
 | 
					/// Error returned by `try_read`
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
					#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
				
			||||||
@ -186,8 +172,15 @@ impl<'d, T: Instance> Can<'d, T> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// Set CAN bit rate.
 | 
					    /// Set CAN bit rate.
 | 
				
			||||||
    pub fn set_bitrate(&mut self, bitrate: u32) {
 | 
					    pub fn set_bitrate(&mut self, bitrate: u32) {
 | 
				
			||||||
        let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
 | 
					        let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
 | 
				
			||||||
        self.can.modify_config().set_bit_timing(bit_timing).leave_disabled();
 | 
					        let sjw = u8::from(bit_timing.sync_jump_width) as u32;
 | 
				
			||||||
 | 
					        let seg1 = u8::from(bit_timing.seg1) as u32;
 | 
				
			||||||
 | 
					        let seg2 = u8::from(bit_timing.seg2) as u32;
 | 
				
			||||||
 | 
					        let prescaler = u16::from(bit_timing.prescaler) as u32;
 | 
				
			||||||
 | 
					        self.can
 | 
				
			||||||
 | 
					            .modify_config()
 | 
				
			||||||
 | 
					            .set_bit_timing((sjw - 1) << 24 | (seg1 - 1) << 16 | (seg2 - 1) << 20 | (prescaler - 1))
 | 
				
			||||||
 | 
					            .leave_disabled();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Enables the peripheral and synchronizes with the bus.
 | 
					    /// Enables the peripheral and synchronizes with the bus.
 | 
				
			||||||
@ -302,97 +295,6 @@ impl<'d, T: Instance> Can<'d, T> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> {
 | 
					 | 
				
			||||||
        const BS1_MAX: u8 = 16;
 | 
					 | 
				
			||||||
        const BS2_MAX: u8 = 8;
 | 
					 | 
				
			||||||
        const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let periph_clock = periph_clock.0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if can_bitrate < 1000 {
 | 
					 | 
				
			||||||
            return None;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
 | 
					 | 
				
			||||||
        //      CAN in Automation, 2003
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // According to the source, optimal quanta per bit are:
 | 
					 | 
				
			||||||
        //   Bitrate        Optimal Maximum
 | 
					 | 
				
			||||||
        //   1000 kbps      8       10
 | 
					 | 
				
			||||||
        //   500  kbps      16      17
 | 
					 | 
				
			||||||
        //   250  kbps      16      17
 | 
					 | 
				
			||||||
        //   125  kbps      16      17
 | 
					 | 
				
			||||||
        let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Computing (prescaler * BS):
 | 
					 | 
				
			||||||
        //   BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2))       -- See the Reference Manual
 | 
					 | 
				
			||||||
        //   BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2))                 -- Simplified
 | 
					 | 
				
			||||||
        // let:
 | 
					 | 
				
			||||||
        //   BS = 1 + BS1 + BS2                                             -- Number of time quanta per bit
 | 
					 | 
				
			||||||
        //   PRESCALER_BS = PRESCALER * BS
 | 
					 | 
				
			||||||
        // ==>
 | 
					 | 
				
			||||||
        //   PRESCALER_BS = PCLK / BITRATE
 | 
					 | 
				
			||||||
        let prescaler_bs = periph_clock / can_bitrate;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Searching for such prescaler value so that the number of quanta per bit is highest.
 | 
					 | 
				
			||||||
        let mut bs1_bs2_sum = max_quanta_per_bit - 1;
 | 
					 | 
				
			||||||
        while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
 | 
					 | 
				
			||||||
            if bs1_bs2_sum <= 2 {
 | 
					 | 
				
			||||||
                return None; // No solution
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            bs1_bs2_sum -= 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
 | 
					 | 
				
			||||||
        if (prescaler < 1) || (prescaler > 1024) {
 | 
					 | 
				
			||||||
            return None; // No solution
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
 | 
					 | 
				
			||||||
        // We need to find such values so that the sample point is as close as possible to the optimal value,
 | 
					 | 
				
			||||||
        // which is 87.5%, which is 7/8.
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        //   Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2]  (* Where 7/8 is 0.875, the recommended sample point location *)
 | 
					 | 
				
			||||||
        //   {{bs2 -> (1 + bs1)/7}}
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // Hence:
 | 
					 | 
				
			||||||
        //   bs2 = (1 + bs1) / 7
 | 
					 | 
				
			||||||
        //   bs1 = (7 * bs1_bs2_sum - 1) / 8
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // Sample point location can be computed as follows:
 | 
					 | 
				
			||||||
        //   Sample point location = (1 + bs1) / (1 + bs1 + bs2)
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
        // Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
 | 
					 | 
				
			||||||
        //   - With rounding to nearest
 | 
					 | 
				
			||||||
        //   - With rounding to zero
 | 
					 | 
				
			||||||
        let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first
 | 
					 | 
				
			||||||
        let mut bs2 = bs1_bs2_sum - bs1;
 | 
					 | 
				
			||||||
        core::assert!(bs1_bs2_sum > bs1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16;
 | 
					 | 
				
			||||||
        if sample_point_permill > MAX_SAMPLE_POINT_PERMILL {
 | 
					 | 
				
			||||||
            // Nope, too far; now rounding to zero
 | 
					 | 
				
			||||||
            bs1 = (7 * bs1_bs2_sum - 1) / 8;
 | 
					 | 
				
			||||||
            bs2 = bs1_bs2_sum - bs1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Check is BS1 and BS2 are in range
 | 
					 | 
				
			||||||
        if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
 | 
					 | 
				
			||||||
            return None;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Check if final bitrate matches the requested
 | 
					 | 
				
			||||||
        if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) {
 | 
					 | 
				
			||||||
            return None;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // One is recommended by DS-015, CANOpen, and DeviceNet
 | 
					 | 
				
			||||||
        let sjw = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Pack into BTR register values
 | 
					 | 
				
			||||||
        Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Split the CAN driver into transmit and receive halves.
 | 
					    /// Split the CAN driver into transmit and receive halves.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Useful for doing separate transmit/receive tasks.
 | 
					    /// Useful for doing separate transmit/receive tasks.
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										30
									
								
								embassy-stm32/src/can/enums.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								embassy-stm32/src/can/enums.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					//! Enums shared between CAN controller types.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Bus error
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
				
			||||||
 | 
					pub enum BusError {
 | 
				
			||||||
 | 
					    /// Bit stuffing error - more than 5 equal bits
 | 
				
			||||||
 | 
					    Stuff,
 | 
				
			||||||
 | 
					    /// Form error - A fixed format part of a received message has wrong format
 | 
				
			||||||
 | 
					    Form,
 | 
				
			||||||
 | 
					    /// The message transmitted by the FDCAN was not acknowledged by another node.
 | 
				
			||||||
 | 
					    Acknowledge,
 | 
				
			||||||
 | 
					    /// Bit0Error: During the transmission of a message the device wanted to send a dominant level
 | 
				
			||||||
 | 
					    /// but the monitored bus value was recessive.
 | 
				
			||||||
 | 
					    BitRecessive,
 | 
				
			||||||
 | 
					    /// Bit1Error: During the transmission of a message the device wanted to send a recessive level
 | 
				
			||||||
 | 
					    /// but the monitored bus value was dominant.
 | 
				
			||||||
 | 
					    BitDominant,
 | 
				
			||||||
 | 
					    /// The CRC check sum of a received message was incorrect. The CRC of an
 | 
				
			||||||
 | 
					    /// incoming message does not match with the CRC calculated from the received data.
 | 
				
			||||||
 | 
					    Crc,
 | 
				
			||||||
 | 
					    /// A software error occured
 | 
				
			||||||
 | 
					    Software,
 | 
				
			||||||
 | 
					    ///  The FDCAN is in Bus_Off state.
 | 
				
			||||||
 | 
					    BusOff,
 | 
				
			||||||
 | 
					    ///  The FDCAN is in the Error_Passive state.
 | 
				
			||||||
 | 
					    BusPassive,
 | 
				
			||||||
 | 
					    ///  At least one of error counter has reached the Error_Warning limit of 96.
 | 
				
			||||||
 | 
					    BusWarning,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										117
									
								
								embassy-stm32/src/can/util.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								embassy-stm32/src/can/util.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,117 @@
 | 
				
			|||||||
 | 
					//! Utility functions shared between CAN controller types.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use core::num::{NonZeroU16, NonZeroU8};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Shared struct to represent bit timings used by calc_can_timings.
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
 | 
					pub struct NominalBitTiming {
 | 
				
			||||||
 | 
					    /// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit
 | 
				
			||||||
 | 
					    /// time is built up from a multiple of this quanta. Valid values are 1 to 512.
 | 
				
			||||||
 | 
					    pub prescaler: NonZeroU16,
 | 
				
			||||||
 | 
					    /// Valid values are 1 to 128.
 | 
				
			||||||
 | 
					    pub seg1: NonZeroU8,
 | 
				
			||||||
 | 
					    /// Valid values are 1 to 255.
 | 
				
			||||||
 | 
					    pub seg2: NonZeroU8,
 | 
				
			||||||
 | 
					    /// Valid values are 1 to 128.
 | 
				
			||||||
 | 
					    pub sync_jump_width: NonZeroU8,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency
 | 
				
			||||||
 | 
					pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option<NominalBitTiming> {
 | 
				
			||||||
 | 
					    const BS1_MAX: u8 = 16;
 | 
				
			||||||
 | 
					    const BS2_MAX: u8 = 8;
 | 
				
			||||||
 | 
					    const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let periph_clock = periph_clock.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if can_bitrate < 1000 {
 | 
				
			||||||
 | 
					        return None;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
 | 
				
			||||||
 | 
					    //      CAN in Automation, 2003
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // According to the source, optimal quanta per bit are:
 | 
				
			||||||
 | 
					    //   Bitrate        Optimal Maximum
 | 
				
			||||||
 | 
					    //   1000 kbps      8       10
 | 
				
			||||||
 | 
					    //   500  kbps      16      17
 | 
				
			||||||
 | 
					    //   250  kbps      16      17
 | 
				
			||||||
 | 
					    //   125  kbps      16      17
 | 
				
			||||||
 | 
					    let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Computing (prescaler * BS):
 | 
				
			||||||
 | 
					    //   BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2))       -- See the Reference Manual
 | 
				
			||||||
 | 
					    //   BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2))                 -- Simplified
 | 
				
			||||||
 | 
					    // let:
 | 
				
			||||||
 | 
					    //   BS = 1 + BS1 + BS2                                             -- Number of time quanta per bit
 | 
				
			||||||
 | 
					    //   PRESCALER_BS = PRESCALER * BS
 | 
				
			||||||
 | 
					    // ==>
 | 
				
			||||||
 | 
					    //   PRESCALER_BS = PCLK / BITRATE
 | 
				
			||||||
 | 
					    let prescaler_bs = periph_clock / can_bitrate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Searching for such prescaler value so that the number of quanta per bit is highest.
 | 
				
			||||||
 | 
					    let mut bs1_bs2_sum = max_quanta_per_bit - 1;
 | 
				
			||||||
 | 
					    while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
 | 
				
			||||||
 | 
					        if bs1_bs2_sum <= 2 {
 | 
				
			||||||
 | 
					            return None; // No solution
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        bs1_bs2_sum -= 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
 | 
				
			||||||
 | 
					    if (prescaler < 1) || (prescaler > 1024) {
 | 
				
			||||||
 | 
					        return None; // No solution
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
 | 
				
			||||||
 | 
					    // We need to find such values so that the sample point is as close as possible to the optimal value,
 | 
				
			||||||
 | 
					    // which is 87.5%, which is 7/8.
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    //   Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2]  (* Where 7/8 is 0.875, the recommended sample point location *)
 | 
				
			||||||
 | 
					    //   {{bs2 -> (1 + bs1)/7}}
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // Hence:
 | 
				
			||||||
 | 
					    //   bs2 = (1 + bs1) / 7
 | 
				
			||||||
 | 
					    //   bs1 = (7 * bs1_bs2_sum - 1) / 8
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // Sample point location can be computed as follows:
 | 
				
			||||||
 | 
					    //   Sample point location = (1 + bs1) / (1 + bs1 + bs2)
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
 | 
				
			||||||
 | 
					    //   - With rounding to nearest
 | 
				
			||||||
 | 
					    //   - With rounding to zero
 | 
				
			||||||
 | 
					    let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first
 | 
				
			||||||
 | 
					    let mut bs2 = bs1_bs2_sum - bs1;
 | 
				
			||||||
 | 
					    core::assert!(bs1_bs2_sum > bs1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16;
 | 
				
			||||||
 | 
					    if sample_point_permill > MAX_SAMPLE_POINT_PERMILL {
 | 
				
			||||||
 | 
					        // Nope, too far; now rounding to zero
 | 
				
			||||||
 | 
					        bs1 = (7 * bs1_bs2_sum - 1) / 8;
 | 
				
			||||||
 | 
					        bs2 = bs1_bs2_sum - bs1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check is BS1 and BS2 are in range
 | 
				
			||||||
 | 
					    if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
 | 
				
			||||||
 | 
					        return None;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check if final bitrate matches the requested
 | 
				
			||||||
 | 
					    if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) {
 | 
				
			||||||
 | 
					        return None;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // One is recommended by DS-015, CANOpen, and DeviceNet
 | 
				
			||||||
 | 
					    let sync_jump_width = core::num::NonZeroU8::new(1)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let seg1 = core::num::NonZeroU8::new(bs1)?;
 | 
				
			||||||
 | 
					    let seg2 = core::num::NonZeroU8::new(bs2)?;
 | 
				
			||||||
 | 
					    let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Some(NominalBitTiming {
 | 
				
			||||||
 | 
					        sync_jump_width,
 | 
				
			||||||
 | 
					        prescaler: nz_prescaler,
 | 
				
			||||||
 | 
					        seg1,
 | 
				
			||||||
 | 
					        seg2,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -3,8 +3,8 @@ use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw};
 | 
				
			|||||||
use stm32_metapac::FLASH;
 | 
					use stm32_metapac::FLASH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use crate::pac::rcc::vals::{
 | 
					pub use crate::pac::rcc::vals::{
 | 
				
			||||||
    Adcsel as AdcClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, Pllp as PllP, Pllq as PllQ,
 | 
					    Adcsel as AdcClockSource, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN,
 | 
				
			||||||
    Pllr as PllR, Ppre as APBPrescaler,
 | 
					    Pllp as PllP, Pllq as PllQ, Pllr as PllR, Ppre as APBPrescaler,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use crate::pac::{PWR, RCC};
 | 
					use crate::pac::{PWR, RCC};
 | 
				
			||||||
use crate::rcc::{set_freqs, Clocks};
 | 
					use crate::rcc::{set_freqs, Clocks};
 | 
				
			||||||
@ -87,6 +87,7 @@ pub struct Config {
 | 
				
			|||||||
    pub clock_48mhz_src: Option<Clock48MhzSrc>,
 | 
					    pub clock_48mhz_src: Option<Clock48MhzSrc>,
 | 
				
			||||||
    pub adc12_clock_source: AdcClockSource,
 | 
					    pub adc12_clock_source: AdcClockSource,
 | 
				
			||||||
    pub adc345_clock_source: AdcClockSource,
 | 
					    pub adc345_clock_source: AdcClockSource,
 | 
				
			||||||
 | 
					    pub fdcan_clock_source: FdCanClockSource,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub ls: super::LsConfig,
 | 
					    pub ls: super::LsConfig,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -104,6 +105,7 @@ impl Default for Config {
 | 
				
			|||||||
            clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())),
 | 
					            clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())),
 | 
				
			||||||
            adc12_clock_source: Adcsel::DISABLE,
 | 
					            adc12_clock_source: Adcsel::DISABLE,
 | 
				
			||||||
            adc345_clock_source: Adcsel::DISABLE,
 | 
					            adc345_clock_source: Adcsel::DISABLE,
 | 
				
			||||||
 | 
					            fdcan_clock_source: FdCanClockSource::PCLK1,
 | 
				
			||||||
            ls: Default::default(),
 | 
					            ls: Default::default(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -282,6 +284,7 @@ pub(crate) unsafe fn init(config: Config) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
 | 
					    RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
 | 
				
			||||||
    RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
 | 
					    RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
 | 
				
			||||||
 | 
					    RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let adc12_ck = match config.adc12_clock_source {
 | 
					    let adc12_ck = match config.adc12_clock_source {
 | 
				
			||||||
        AdcClockSource::DISABLE => None,
 | 
					        AdcClockSource::DISABLE => None,
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ use crate::pac::pwr::vals::Vos;
 | 
				
			|||||||
pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
 | 
					pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
 | 
				
			||||||
#[cfg(stm32h7)]
 | 
					#[cfg(stm32h7)]
 | 
				
			||||||
pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
 | 
					pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
 | 
				
			||||||
 | 
					pub use crate::pac::rcc::vals::Fdcansel as FdCanClockSource;
 | 
				
			||||||
pub use crate::pac::rcc::vals::{
 | 
					pub use crate::pac::rcc::vals::{
 | 
				
			||||||
    Ckpersel as PerClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
 | 
					    Ckpersel as PerClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
 | 
				
			||||||
    Pllsrc as PllSource, Sw as Sysclk,
 | 
					    Pllsrc as PllSource, Sw as Sysclk,
 | 
				
			||||||
@ -212,6 +213,8 @@ pub struct Config {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    pub per_clock_source: PerClockSource,
 | 
					    pub per_clock_source: PerClockSource,
 | 
				
			||||||
    pub adc_clock_source: AdcClockSource,
 | 
					    pub adc_clock_source: AdcClockSource,
 | 
				
			||||||
 | 
					    pub fdcan_clock_source: FdCanClockSource,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub timer_prescaler: TimerPrescaler,
 | 
					    pub timer_prescaler: TimerPrescaler,
 | 
				
			||||||
    pub voltage_scale: VoltageScale,
 | 
					    pub voltage_scale: VoltageScale,
 | 
				
			||||||
    pub ls: super::LsConfig,
 | 
					    pub ls: super::LsConfig,
 | 
				
			||||||
@ -248,6 +251,8 @@ impl Default for Config {
 | 
				
			|||||||
            #[cfg(stm32h7)]
 | 
					            #[cfg(stm32h7)]
 | 
				
			||||||
            adc_clock_source: AdcClockSource::PER,
 | 
					            adc_clock_source: AdcClockSource::PER,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            timer_prescaler: TimerPrescaler::DefaultX2,
 | 
					            timer_prescaler: TimerPrescaler::DefaultX2,
 | 
				
			||||||
            voltage_scale: VoltageScale::Scale0,
 | 
					            voltage_scale: VoltageScale::Scale0,
 | 
				
			||||||
            ls: Default::default(),
 | 
					            ls: Default::default(),
 | 
				
			||||||
@ -585,7 +590,8 @@ pub(crate) unsafe fn init(config: Config) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        RCC.ccipr5().modify(|w| {
 | 
					        RCC.ccipr5().modify(|w| {
 | 
				
			||||||
            w.set_ckpersel(config.per_clock_source);
 | 
					            w.set_ckpersel(config.per_clock_source);
 | 
				
			||||||
            w.set_adcdacsel(config.adc_clock_source)
 | 
					            w.set_adcdacsel(config.adc_clock_source);
 | 
				
			||||||
 | 
					            w.set_fdcan1sel(config.fdcan_clock_source)
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user