From 125619e485a81092cee633a217860222862fd6e5 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 8 Apr 2025 16:22:02 +0200 Subject: [PATCH] continue CAN --- va416xx-hal/src/can/mod.rs | 56 ++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/va416xx-hal/src/can/mod.rs b/va416xx-hal/src/can/mod.rs index 618a4d4..3e2f630 100644 --- a/va416xx-hal/src/can/mod.rs +++ b/va416xx-hal/src/can/mod.rs @@ -1,6 +1,6 @@ -use arbitrary_int::{u2, u3, u4, u7}; +use arbitrary_int::{u2, u3, u4, u7, Number}; -use crate::{clock::Clocks, enable_peripheral_clock, PeripheralSelect}; +use crate::{clock::Clocks, enable_peripheral_clock, time::Hertz, PeripheralSelect}; pub mod regs; @@ -38,16 +38,62 @@ pub struct ClockConfig { sjw: u2, } +#[derive(Debug, thiserror::Error)] +#[error("sjw must be less than or equal to the smaller tseg value")] +pub struct InvalidSjwError(u2); + +/// Sample point between 0 and 1.0 for the given time segments. +pub const fn sample_point(tseg1: u4, tseg2: u3) -> f32 { + let tseg1_val = tseg1.value() as f32; + (tseg1_val + 1.0) / (1.0 + tseg1_val + tseg2.value() as f32) +} + +#[derive(Debug, thiserror::Error)] +#[error("invalid sample point {sample_point} for tseg1 {tseg1} and tseg2 {tseg2}.")] +pub struct InvalidSamplePointError { + tseg1: u4, + tseg2: u3, + /// Sample point, should be larger than 0.5 (50 %) but was not. + sample_point: f32, +} + +#[derive(Debug, thiserror::Error)] +pub enum ClockConfigError { + #[error("invalid sjw: {0}")] + InvalidSjw(#[from] InvalidSjwError), + #[error("invalid sample point: {0}")] + InvalidSamplePoint(#[from] InvalidSamplePointError), +} + impl ClockConfig { /// New clock configuration from the raw configuration values. - pub fn new(prescaler: u7, tseg1: u4, tseg2: u3, sjw: u2) -> Self { - Self { + /// + /// The synchronization jump width MUST be smaller than the smaller of the time segment + /// configuration values. The sample point must also be larger than 50 %. + pub fn new(prescaler: u7, tseg1: u4, tseg2: u3, sjw: u2) -> Result { + let smaller_tseg = core::cmp::min(tseg1.value(), tseg2.value()); + if sjw.value() > smaller_tseg { + return Err(InvalidSjwError(sjw).into()); + } + let sample_point = sample_point(tseg1, tseg2); + if sample_point < 0.5 { + return Err(InvalidSamplePointError { + tseg1, + tseg2, + sample_point, + }.into()); + } + Ok(Self { prescaler, tseg1, tseg2, sjw, - } + }) } + + pub fn from_bitrate(clocks: &Clocks, bitrate: Hertz, prescaler: u7, tseg1: u4, tseg2: u3, sjw: u2) {} + + pub fn from_sample_point(clocks: &Clocks, bitrate: Hertz, sample_point: f32) {} } impl Can {