From 10d5d704f80ee69480c2f961d74045407379e8ab Mon Sep 17 00:00:00 2001 From: delphi Date: Thu, 4 Feb 2021 12:22:15 +0300 Subject: [PATCH] First compiling commit of CAN driver with all traits marked with `unimplemented!()` Signed-off-by: delphi --- Cargo.toml | 1 + src/afio.rs | 4 +- src/can.rs | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 + src/rcu.rs | 2 + 5 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 src/can.rs diff --git a/Cargo.toml b/Cargo.toml index 1144e1d..96b1f93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ nb = "0.1.2" void = { version = "1.0.2", default-features = false } cast = { version = "0.2.3", default-features = false } vcell = "0.1.2" +embedded-can = "0.3.0" [dependencies.embedded-hal] version = "0.2.3" diff --git a/src/afio.rs b/src/afio.rs index f1085bb..9ea6d0d 100644 --- a/src/afio.rs +++ b/src/afio.rs @@ -119,9 +119,11 @@ macro_rules! remap { } remap! { + CAN0 => (can0_remap, u8), + CAN1 => (can1_remap, bool), I2C0 => (i2c0_remap, bool), SPI0 => (spi0_remap, bool), - SPI2 => (spi2_remap, bool), + SPI2 => (spi2_remap, bool), USART0 => (usart0_remap, bool), USART1 => (usart1_remap, bool), USART2 => (usart2_remap, u8), diff --git a/src/can.rs b/src/can.rs new file mode 100644 index 0000000..780bfb9 --- /dev/null +++ b/src/can.rs @@ -0,0 +1,271 @@ +//! # Controller area network controller + +use nb; + +pub use crate::hal_can::{Id, Frame as FrameTrait,Can as CanTrait}; +use crate::pac::{can0, CAN0, CAN1}; +use crate::gpio::gpioa::{PA11, PA12}; +use crate::gpio::gpiob::{PB5, PB6, PB8, PB9, PB12, PB13}; +use crate::gpio::gpiod::{PD0, PD1}; +use crate::gpio::{Alternate, Floating, Input, PushPull}; +use crate::rcu::{Rcu, Enable, Reset, BaseFrequency}; +use crate::time::Hertz; +use crate::afio::{Afio, Remap}; +use core::{convert::TryInto, ops::Deref}; + +pub struct Frame{ +} + +impl FrameTrait for Frame { + /// Creates a new frame. + /// Returns an error when the data slice is too long. + fn new(id: impl Into, data: &[u8]) -> Result{ + unimplemented!() + } + + /// Creates a new remote frame (RTR bit set). + /// Returns an error when the data length code (DLC) is not valid. + fn new_remote(id: impl Into, dlc: usize) -> Result{ + unimplemented!() + } + + /// Returns true if this frame is a extended frame. + fn is_extended(&self) -> bool{ + unimplemented!() + } + + + /// Returns true if this frame is a remote frame. + fn is_remote_frame(&self) -> bool{ + unimplemented!() + } + + /// Returns the frame identifier. + fn id(&self) -> Id{ + unimplemented!() + } + + /// Returns the data length code (DLC) which is in the range 0..8. + /// + /// For data frames the DLC value always matches the length of the data. + /// Remote frames do not carry any data, yet the DLC can be greater than 0. + fn dlc(&self) -> usize{ + unimplemented!() + } + + /// Returns the frame data (0..8 bytes in length). + fn data(&self) -> &[u8]{ + unimplemented!() + } +} + +/// Can error +#[derive(Debug)] +pub enum Error { + /// Overrun occurred + Overrun, + /// Mode fault occurred + ModeFault, + /// CRC error + Crc, + #[doc(hidden)] + _Extensible, +} + +pub enum CanMode{ + Normal = 0b00, + Silent = 0b10, + Loopback = 0b01, + SilentLoopback = 0b11 +} + +#[derive(Clone)] +pub struct TimeQuantaConfiguration{ + pub sync: u8, + pub propagandation: u8, + pub before_sample: u8, + pub after_sample: u8 +} + +impl TimeQuantaConfiguration{ + fn sum(&self) -> u32{ + (self.sync + self.propagandation + self.before_sample + self.after_sample) as u32 + } + fn bs1(&self) -> u8 { + self.propagandation + self.before_sample + } + fn bs2(&self) -> u8 { + self.after_sample + } +} + +#[doc(hidden)] +pub trait CanX: Deref {} +impl CanX for CAN0 {} +impl CanX for CAN1 {} + +pub trait Pins { + type Variant; + const REMAP: Self::Variant; +} + +impl Pins + for ( + PA11>, + PA12>, + ) +{ + type Variant = u8; + const REMAP: u8 = 0b00; +} +impl Pins + for ( + PB8>, + PB9>, + ) +{ + type Variant = u8; + const REMAP: u8 = 0b10; +} +impl Pins + for ( + PD0>, + PD1>, + ) +{ + type Variant = u8; + const REMAP: u8 = 0b11; +} + +impl Pins + for ( + PB12>, + PB13>, + ) +{ + type Variant = bool; + const REMAP: bool = false; +} +impl Pins + for ( + PB5>, + PB6>, + ) +{ + type Variant = bool; + const REMAP: bool = true; +} + +pub struct Can { + can: CAN, + pins: PINS, +} + +impl> Can { + pub fn can0( + can: CAN0, + pins: PINS, + afio: &mut Afio, + tqc : TimeQuantaConfiguration, + mode: CanMode, + freq: impl Into, + rcu: &mut Rcu + ) -> Self + { + CAN0::remap(afio, PINS::REMAP); + Can::new(can, pins, tqc, mode,freq, rcu) + } +} + +impl> Can { + pub fn can1( + can: CAN1, + pins: PINS, + afio: &mut Afio, + tqc : TimeQuantaConfiguration, + mode: CanMode, + freq: impl Into, + rcu: &mut Rcu + ) -> Self + { + CAN1::remap(afio, PINS::REMAP); + Can::new(can, pins, tqc, mode, freq, rcu) + } +} + + +impl Can where CAN: CanX +{ + const MAX_PSC : u16 = 0b111111111; + fn new( + can: CAN, + pins: PINS, + tqc : TimeQuantaConfiguration, + mode: CanMode, + freq: impl Into, + rcu: &mut Rcu + ) -> Self where CAN: Enable + Reset + BaseFrequency { + + let baudpsc:u16= ( + CAN::base_frequency(rcu).0 / (freq.into().0 * tqc.sum() ) + ).try_into().unwrap_or(Self::MAX_PSC); + let baudpsc:u16 = if baudpsc > Self::MAX_PSC { + Self::MAX_PSC + } else if baudpsc == 0 { + unreachable!(); + } else{ + baudpsc + }; + + CAN::enable(rcu); + CAN::reset(rcu); + can.bt.write(|w| unsafe{w + .baudpsc().bits(baudpsc) + .scmod().bit(match mode { + CanMode::Silent | CanMode::SilentLoopback => {true}, + _ => {false}, + }) + .lcmod().bit(match mode { + CanMode::Loopback | CanMode::SilentLoopback => {true}, + _ => {false}, + }) + .sjw().bits(tqc.sync) + .bs1().bits(tqc.bs1()) + .bs2().bits(tqc.bs2()) + }); + Can{can, pins} + } +} + + +/// A CAN interface that is able to transmit and receive frames. +impl CanTrait for Can { + /// Associated frame type. + type Frame = Frame; + + /// Associated error type. + type Error = Error; + + /// Puts a frame in the transmit buffer to be sent on the bus. + /// + /// If the transmit buffer is full, this function will try to replace a pending + /// lower priority frame and return the frame that was replaced. + /// Returns `Err(WouldBlock)` if the transmit buffer is full and no frame can be + /// replaced. + /// + /// # Notes for implementers + /// + /// * Frames of equal identifier shall be transmited in FIFO fashion when more + /// than one transmit buffer is available. + /// * When replacing pending frames make sure the frame is not in the process of + /// being send to the bus. + fn try_transmit(&mut self, frame: &Self::Frame) + -> nb::Result, Self::Error>{ + unimplemented!() + } + + /// Returns a received frame if available. + fn try_receive(&mut self) -> nb::Result{ + unimplemented!() + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index ea049b1..b0794ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,9 +8,11 @@ pub use gd32vf103_pac as pac; use embedded_hal as hal; +use embedded_can as hal_can; pub mod afio; pub mod backup_domain; +pub mod can; pub mod delay; pub mod eclic; pub mod exmc; diff --git a/src/rcu.rs b/src/rcu.rs index 8fd3e28..7a446c1 100644 --- a/src/rcu.rs +++ b/src/rcu.rs @@ -285,6 +285,8 @@ base_freq! { SPI0 => pclk2, SPI1 => pclk1, SPI2 => pclk1, + CAN0 => pclk1, + CAN1 => pclk1, TIMER0 => timer0, TIMER1 => timerx, TIMER2 => timerx,