Skip to content

Commit

Permalink
First compiling commit of CAN driver with all traits marked with `uni…
Browse files Browse the repository at this point in the history
…mplemented!()`

Signed-off-by: delphi <[email protected]>
  • Loading branch information
asmfreak committed Feb 4, 2021
1 parent 37d0dec commit 10d5d70
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 3 additions & 1 deletion src/afio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
271 changes: 271 additions & 0 deletions src/can.rs
Original file line number Diff line number Diff line change
@@ -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<Id>, data: &[u8]) -> Result<Self, ()>{
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<Id>, dlc: usize) -> Result<Self, ()>{
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<Target = can0::RegisterBlock> {}
impl CanX for CAN0 {}
impl CanX for CAN1 {}

pub trait Pins<CAN> {
type Variant;
const REMAP: Self::Variant;
}

impl Pins<CAN0>
for (
PA11<Input<Floating>>,
PA12<Alternate<PushPull>>,
)
{
type Variant = u8;
const REMAP: u8 = 0b00;
}
impl Pins<CAN0>
for (
PB8<Input<Floating>>,
PB9<Alternate<PushPull>>,
)
{
type Variant = u8;
const REMAP: u8 = 0b10;
}
impl Pins<CAN0>
for (
PD0<Input<Floating>>,
PD1<Alternate<PushPull>>,
)
{
type Variant = u8;
const REMAP: u8 = 0b11;
}

impl Pins<CAN1>
for (
PB12<Input<Floating>>,
PB13<Alternate<PushPull>>,
)
{
type Variant = bool;
const REMAP: bool = false;
}
impl Pins<CAN1>
for (
PB5<Input<Floating>>,
PB6<Alternate<PushPull>>,
)
{
type Variant = bool;
const REMAP: bool = true;
}

pub struct Can<CAN, PINS> {
can: CAN,
pins: PINS,
}

impl<PINS: Pins<CAN0, Variant=u8>> Can<CAN0, PINS> {
pub fn can0(
can: CAN0,
pins: PINS,
afio: &mut Afio,
tqc : TimeQuantaConfiguration,
mode: CanMode,
freq: impl Into<Hertz>,
rcu: &mut Rcu
) -> Self
{
CAN0::remap(afio, PINS::REMAP);
Can::new(can, pins, tqc, mode,freq, rcu)
}
}

impl<PINS: Pins<CAN1, Variant=bool>> Can<CAN1, PINS> {
pub fn can1(
can: CAN1,
pins: PINS,
afio: &mut Afio,
tqc : TimeQuantaConfiguration,
mode: CanMode,
freq: impl Into<Hertz>,
rcu: &mut Rcu
) -> Self
{
CAN1::remap(afio, PINS::REMAP);
Can::new(can, pins, tqc, mode, freq, rcu)
}
}


impl<CAN, PINS> Can<CAN, PINS> where CAN: CanX
{
const MAX_PSC : u16 = 0b111111111;
fn new(
can: CAN,
pins: PINS,
tqc : TimeQuantaConfiguration,
mode: CanMode,
freq: impl Into<Hertz>,
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<CAN, PINS> CanTrait for Can<CAN, PINS> {
/// 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<Option<Self::Frame>, Self::Error>{
unimplemented!()
}

/// Returns a received frame if available.
fn try_receive(&mut self) -> nb::Result<Self::Frame, Self::Error>{
unimplemented!()
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/rcu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ base_freq! {
SPI0 => pclk2,
SPI1 => pclk1,
SPI2 => pclk1,
CAN0 => pclk1,
CAN1 => pclk1,
TIMER0 => timer0,
TIMER1 => timerx,
TIMER2 => timerx,
Expand Down

0 comments on commit 10d5d70

Please sign in to comment.