complicated
This commit is contained in:
parent
5e9526a2d1
commit
be6cd2d609
@ -21,6 +21,7 @@ embedded-hal-async = "1"
|
||||
embedded-hal = "1"
|
||||
embedded-io = "0.6"
|
||||
embedded-io-async = "0.6"
|
||||
embedded-can = "0.4"
|
||||
num_enum = { version = "0.7", default-features = false }
|
||||
typenum = "1"
|
||||
bitflags = "2"
|
||||
|
117
va416xx-hal/src/can/frame.rs
Normal file
117
va416xx-hal/src/can/frame.rs
Normal file
@ -0,0 +1,117 @@
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("invalid data size error {0}")]
|
||||
pub struct InvalidDataSizeError(usize);
|
||||
|
||||
pub struct CanFrameNormal {
|
||||
id: embedded_can::Id,
|
||||
size: usize,
|
||||
data: [u8; 8],
|
||||
}
|
||||
|
||||
impl CanFrameNormal {
|
||||
pub fn new(id: embedded_can::Id, data: &[u8]) -> Self {
|
||||
let size = data.len();
|
||||
let mut data_array = [0; 8];
|
||||
data_array[..size].copy_from_slice(data);
|
||||
Self {
|
||||
id,
|
||||
size,
|
||||
data: data_array,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> embedded_can::Id {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data[..self.size]
|
||||
}
|
||||
|
||||
pub fn dlc(&self) -> usize {
|
||||
self.size
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CanFrameRtr {
|
||||
id: embedded_can::Id,
|
||||
dlc: usize,
|
||||
}
|
||||
|
||||
impl CanFrameRtr {
|
||||
pub fn new(id: embedded_can::Id, dlc: usize) -> Self {
|
||||
Self { id, dlc }
|
||||
}
|
||||
|
||||
pub fn id(&self) -> embedded_can::Id {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn dlc(&self) -> usize {
|
||||
self.dlc
|
||||
}
|
||||
}
|
||||
|
||||
pub enum CanFrame {
|
||||
Normal(CanFrameNormal),
|
||||
Rtr(CanFrameRtr),
|
||||
}
|
||||
|
||||
impl From<CanFrameNormal> for CanFrame {
|
||||
fn from(value: CanFrameNormal) -> Self {
|
||||
Self::Normal(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CanFrameRtr> for CanFrame {
|
||||
fn from(value: CanFrameRtr) -> Self {
|
||||
Self::Rtr(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_can::Frame for CanFrame {
|
||||
fn new(id: impl Into<embedded_can::Id>, data: &[u8]) -> Option<Self> {
|
||||
let id: embedded_can::Id = id.into();
|
||||
Some(Self::Normal(CanFrameNormal::new(id, data)))
|
||||
}
|
||||
|
||||
fn new_remote(id: impl Into<embedded_can::Id>, dlc: usize) -> Option<Self> {
|
||||
let id: embedded_can::Id = id.into();
|
||||
Some(Self::Rtr(CanFrameRtr::new(id, dlc)))
|
||||
}
|
||||
|
||||
fn is_extended(&self) -> bool {
|
||||
match self.id() {
|
||||
embedded_can::Id::Extended(_) => true,
|
||||
embedded_can::Id::Standard(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_remote_frame(&self) -> bool {
|
||||
match self {
|
||||
CanFrame::Normal(_) => false,
|
||||
CanFrame::Rtr(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn id(&self) -> embedded_can::Id {
|
||||
match self {
|
||||
CanFrame::Normal(can_frame_normal) => can_frame_normal.id(),
|
||||
CanFrame::Rtr(can_frame_rtr) => can_frame_rtr.id(),
|
||||
}
|
||||
}
|
||||
|
||||
fn dlc(&self) -> usize {
|
||||
match self {
|
||||
CanFrame::Normal(can_frame_normal) => can_frame_normal.dlc(),
|
||||
CanFrame::Rtr(can_frame_rtr) => can_frame_rtr.dlc(),
|
||||
}
|
||||
}
|
||||
|
||||
fn data(&self) -> &[u8] {
|
||||
match self {
|
||||
CanFrame::Normal(can_frame_normal) => can_frame_normal.data(),
|
||||
CanFrame::Rtr(_) => &[],
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,18 @@
|
||||
use arbitrary_int::{u2, u3, u4, u7, Number};
|
||||
//! CAN driver.
|
||||
//!
|
||||
//! The VA416xx CAN module is based on the CP3UB26 module.
|
||||
use arbitrary_int::{u11, u15, u2, u3, u4, u7, Number};
|
||||
use embedded_can::Frame;
|
||||
use regs::{
|
||||
BaseId, BufStatusAndControl, Control, DataDirection, ExtendedId, MmioCan, TimingConfig,
|
||||
};
|
||||
|
||||
use crate::{clock::Clocks, enable_peripheral_clock, time::Hertz, PeripheralSelect};
|
||||
use libm::roundf;
|
||||
|
||||
pub mod frame;
|
||||
pub mod regs;
|
||||
pub use frame::*;
|
||||
|
||||
pub const PRESCALER_MIN: u8 = 2;
|
||||
pub const PRESCALER_MAX: u8 = 128;
|
||||
@ -23,10 +32,18 @@ pub enum CanId {
|
||||
Can1 = 1,
|
||||
}
|
||||
|
||||
impl CanId {}
|
||||
|
||||
pub struct Can {
|
||||
id: CanId,
|
||||
impl CanId {
|
||||
/// Steal the register block for the CAN ID.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See safety of the [regs::Can::new_mmio_fixed_0].
|
||||
pub unsafe fn steal_regs(&self) -> regs::MmioCan<'static> {
|
||||
match self {
|
||||
CanId::Can0 => unsafe { regs::Can::new_mmio_fixed_0() },
|
||||
CanId::Can1 => unsafe { regs::Can::new_mmio_fixed_1() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sample point between 0 and 1.0 for the given time segments.
|
||||
@ -128,6 +145,10 @@ pub struct ClockConfig {
|
||||
sjw: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("invalid buffer index {0}")]
|
||||
pub struct InvalidBufferIndexError(usize);
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("sjw must be less than or equal to the smaller tseg value")]
|
||||
pub struct InvalidSjwError(u8);
|
||||
@ -253,6 +274,11 @@ impl ClockConfig {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Can {
|
||||
regs: regs::MmioCan<'static>,
|
||||
id: CanId,
|
||||
}
|
||||
|
||||
impl Can {
|
||||
pub fn new<CanI: Instance>(_can: CanI, clk_config: ClockConfig) -> Self {
|
||||
enable_peripheral_clock(CanI::PERIPH_SEL);
|
||||
@ -262,15 +288,290 @@ impl Can {
|
||||
} else {
|
||||
unsafe { regs::Can::new_mmio_fixed_1() }
|
||||
};
|
||||
// Disable the CAN bus before configuring it.
|
||||
regs.write_control(Control::new_with_raw_value(0));
|
||||
for i in 0..15 {
|
||||
regs.msg_buf_block_mut(i).reset();
|
||||
}
|
||||
Self { id }
|
||||
regs.write_timing(
|
||||
TimingConfig::builder()
|
||||
.with_tseg2(clk_config.tseg2_reg_value())
|
||||
.with_tseg1(clk_config.tseg1_reg_value())
|
||||
.with_sync_jump_width(clk_config.sjw_reg_value())
|
||||
.with_prescaler(clk_config.prescaler_reg_value())
|
||||
.build(),
|
||||
);
|
||||
Self { regs, id }
|
||||
}
|
||||
|
||||
/// This configures the global mask so that acceptance is only determined by an exact match
|
||||
/// with the ID in the receive message buffers. This is the default reset configuration for
|
||||
/// the global mask as well.
|
||||
pub fn set_global_mask_for_exact_id_match(&mut self) {
|
||||
self.regs.write_gmskx(ExtendedId::new_with_raw_value(0));
|
||||
self.regs.write_gmskb(BaseId::new_with_raw_value(0));
|
||||
}
|
||||
|
||||
/// Similar to [Self::set_global_mask_for_exact_id_match] but masks the XRTR and RTR/SRR bits.
|
||||
///
|
||||
/// This is useful for when transmitting remote frames with the RTR bit set. The hardware
|
||||
/// will automatically go into the [regs::BufferState::RxReady] state after the transmission,
|
||||
/// but the XRTR and RTR/SRR bits need to be masked for the response frame to be accepted
|
||||
/// on that buffer.
|
||||
pub fn set_global_mask_for_exact_id_match_with_rtr_masked(&mut self) {
|
||||
self.regs.write_gmskx(
|
||||
ExtendedId::builder()
|
||||
.with_mask_14_0(u15::new(0))
|
||||
.with_xrtr(true)
|
||||
.build(),
|
||||
);
|
||||
self.regs.write_gmskb(
|
||||
BaseId::builder()
|
||||
.with_mask_28_18(u11::new(0))
|
||||
.with_rtr_or_srr(true)
|
||||
.with_ide(false)
|
||||
.with_mask_17_15(u3::new(0))
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
/// This configures the base mask for buffer 14 so that acceptance is only determined by an
|
||||
/// exact match with the ID in the receive message buffers. This is the default reset
|
||||
/// configuration for the global mask as well.
|
||||
pub fn set_base_mask_for_exact_id_match(&mut self) {
|
||||
self.regs.write_bmskx(ExtendedId::new_with_raw_value(0));
|
||||
self.regs.write_bmskb(BaseId::new_with_raw_value(0));
|
||||
}
|
||||
|
||||
/// This configures the base mask so that all CAN frames which are not handled by any other
|
||||
/// buffers are accepted by the base buffer 14.
|
||||
pub fn set_base_mask_for_all_match(&mut self) {
|
||||
self.regs
|
||||
.write_bmskx(ExtendedId::new_with_raw_value(0xffff));
|
||||
self.regs.write_bmskb(BaseId::new_with_raw_value(0xffff));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn regs(&mut self) -> &mut MmioCan<'static> {
|
||||
&mut self.regs
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn id(&self) -> CanId {
|
||||
self.id
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_ctrl_reg(&mut self, ctrl: Control) {
|
||||
self.regs.write_control(ctrl);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn enable_bufflock(&mut self) {
|
||||
self.regs.modify_control(|mut ctrl| {
|
||||
ctrl.set_bufflock(true);
|
||||
ctrl
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn enable(&mut self) {
|
||||
self.regs.modify_control(|mut ctrl| {
|
||||
ctrl.set_enable(true);
|
||||
ctrl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ChannelState {
|
||||
Idle,
|
||||
Receiving,
|
||||
Transmitting,
|
||||
AwaitingRtrReply,
|
||||
}
|
||||
|
||||
pub struct CanChannel {
|
||||
can_id: CanId,
|
||||
idx: usize,
|
||||
regs: regs::MmioCanMsgBuf<'static>,
|
||||
mode: ChannelState,
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for CanChannel {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("CanChannel")
|
||||
.field("can_id", &self.can_id)
|
||||
.field("idx", &self.idx)
|
||||
.field("mode", &self.mode)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl CanChannel {
|
||||
pub fn configure_for_reception_with_standard_id(
|
||||
&mut self,
|
||||
standard_id: embedded_can::StandardId,
|
||||
set_rtr: bool,
|
||||
) -> Result<(), InvalidBufferIndexError> {
|
||||
let mut id1_reg = standard_id.as_raw() << 5;
|
||||
if set_rtr {
|
||||
id1_reg |= 1 << 4;
|
||||
}
|
||||
self.regs
|
||||
.write_id1(BaseId::new_with_raw_value(id1_reg as u32));
|
||||
|
||||
self.regs.write_stat_ctrl(
|
||||
BufStatusAndControl::builder()
|
||||
.with_dlc(u4::new(0))
|
||||
.with_priority(u4::new(0))
|
||||
.with_status(regs::BufferState::RxReady)
|
||||
.build(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn configure_for_reception_with_extended_id(
|
||||
&mut self,
|
||||
extended_id: embedded_can::ExtendedId,
|
||||
set_rtr: bool,
|
||||
) -> Result<(), InvalidBufferIndexError> {
|
||||
let mut regs = unsafe { self.can_id.steal_regs() };
|
||||
let mut cmb_block = regs.msg_buf_block_mut(self.idx);
|
||||
let id_raw = extended_id.as_raw();
|
||||
let id1_reg = (((id_raw >> 18) & 0x7FF) << 4) as u16 | ((id_raw >> 15) & 0b111) as u16;
|
||||
cmb_block.write_id1(BaseId::new_with_raw_value(id1_reg as u32));
|
||||
let id0_reg = ((id_raw & 0x7FFF) << 1) as u16 | set_rtr as u16;
|
||||
cmb_block.write_id0(ExtendedId::new_with_raw_value(id0_reg as u32));
|
||||
cmb_block.write_stat_ctrl(
|
||||
BufStatusAndControl::builder()
|
||||
.with_dlc(u4::new(0))
|
||||
.with_priority(u4::new(0))
|
||||
.with_status(regs::BufferState::RxReady)
|
||||
.build(),
|
||||
);
|
||||
self.mode = ChannelState::Receiving;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn configure_for_transmission(
|
||||
&mut self,
|
||||
tx_priority: u4,
|
||||
) -> Result<(), InvalidBufferIndexError> {
|
||||
let mut regs = unsafe { self.can_id.steal_regs() };
|
||||
let mut cmb_block = regs.msg_buf_block_mut(self.idx);
|
||||
cmb_block.write_stat_ctrl(
|
||||
BufStatusAndControl::builder()
|
||||
.with_dlc(u4::new(0))
|
||||
.with_priority(tx_priority)
|
||||
.with_status(regs::BufferState::TxNotActive)
|
||||
.build(),
|
||||
);
|
||||
self.mode = ChannelState::Receiving;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reads a received CAN frame from the message buffer.
|
||||
///
|
||||
/// This function does not check whether the pre-requisites for reading a CAN frame were
|
||||
/// met and assumes this was already checked by the user.
|
||||
pub fn read_frame_unchecked(&self) -> CanFrame {
|
||||
let id0 = self.regs.read_id0();
|
||||
let id1 = self.regs.read_id1();
|
||||
let data0 = self.regs.read_data0();
|
||||
let data1 = self.regs.read_data1();
|
||||
let data2 = self.regs.read_data2();
|
||||
let data3 = self.regs.read_data3();
|
||||
let mut data: [u8; 8] = [0; 8];
|
||||
let mut read_data = |dlc: u4| {
|
||||
(0..dlc.as_usize()).for_each(|i| match i {
|
||||
0 => data[i] = data3.data_upper_byte().as_u8(),
|
||||
1 => data[i] = data3.data_lower_byte().as_u8(),
|
||||
2 => data[i] = data2.data_upper_byte().as_u8(),
|
||||
3 => data[i] = data2.data_lower_byte().as_u8(),
|
||||
4 => data[i] = data1.data_upper_byte().as_u8(),
|
||||
5 => data[i] = data1.data_lower_byte().as_u8(),
|
||||
6 => data[i] = data0.data_upper_byte().as_u8(),
|
||||
7 => data[i] = data0.data_lower_byte().as_u8(),
|
||||
_ => unreachable!(),
|
||||
});
|
||||
};
|
||||
let (id, rtr) = if !id1.ide() {
|
||||
let id = embedded_can::Id::Standard(
|
||||
embedded_can::StandardId::new(id1.mask_28_18().as_u16()).unwrap(),
|
||||
);
|
||||
if id1.rtr_or_srr() {
|
||||
(id, true)
|
||||
} else {
|
||||
(id, false)
|
||||
}
|
||||
} else {
|
||||
let id_raw = (id1.mask_28_18().as_u32() << 18)
|
||||
| (id1.mask_17_15().as_u32() << 15)
|
||||
| id0.mask_14_0().as_u32();
|
||||
let id = embedded_can::Id::Extended(embedded_can::ExtendedId::new(id_raw).unwrap());
|
||||
if id0.xrtr() {
|
||||
(id, true)
|
||||
} else {
|
||||
(id, false)
|
||||
}
|
||||
};
|
||||
if rtr {
|
||||
CanFrameRtr::new(id, self.regs.read_stat_ctrl().dlc().as_usize()).into()
|
||||
} else {
|
||||
let dlc = self.regs.read_stat_ctrl().dlc();
|
||||
read_data(dlc);
|
||||
CanFrameNormal::new(id, &data[0..dlc.as_usize()]).into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transmit_frame_unchecked(&mut self, frame: CanFrame) {
|
||||
let is_remote = frame.is_remote_frame();
|
||||
self.write_id(frame.id(), is_remote);
|
||||
let dlc = frame.dlc();
|
||||
self.regs.modify_stat_ctrl(|mut ctrl| {
|
||||
ctrl.set_status(regs::BufferState::TxOnce);
|
||||
ctrl
|
||||
});
|
||||
}
|
||||
|
||||
fn write_id(&mut self, id: embedded_can::Id, is_remote: bool) {
|
||||
match id {
|
||||
embedded_can::Id::Standard(standard_id) => {
|
||||
self.regs.write_id1(
|
||||
BaseId::builder()
|
||||
.with_mask_28_18(u11::new(standard_id.as_raw()))
|
||||
.with_rtr_or_srr(is_remote)
|
||||
.with_ide(false)
|
||||
.with_mask_17_15(u3::new(0))
|
||||
.build(),
|
||||
);
|
||||
self.regs.write_id0(ExtendedId::new_with_raw_value(0));
|
||||
}
|
||||
embedded_can::Id::Extended(extended_id) => {
|
||||
let id_raw = extended_id.as_raw();
|
||||
self.regs.write_id1(
|
||||
BaseId::builder()
|
||||
.with_mask_28_18(u11::new(((id_raw >> 18) & 0x7FF) as u16))
|
||||
.with_rtr_or_srr(true)
|
||||
.with_ide(true)
|
||||
.with_mask_17_15(u3::new(((id_raw >> 15) & 0b111) as u8))
|
||||
.build(),
|
||||
);
|
||||
self.regs.write_id0(
|
||||
ExtendedId::builder()
|
||||
.with_mask_14_0(u15::new((id_raw & 0x7FFF) as u16))
|
||||
.with_xrtr(is_remote)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CanWorker {
|
||||
can: Can,
|
||||
channels: [CanChannel; 15],
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,31 +1,43 @@
|
||||
//! Custom register definitions for the CAN register block to circumvent PAC API / SVD
|
||||
//! shortcomings.
|
||||
|
||||
use arbitrary_int::{u2, u3, u4, u7};
|
||||
use arbitrary_int::{u11, u15, u2, u3, u4, u7};
|
||||
|
||||
pub const CAN_0_BASE: usize = 0x4001_4000;
|
||||
pub const CAN_1_BASE: usize = 0x4001_4400;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[bitbybit::bitenum(u4)]
|
||||
pub enum BufferStatus {
|
||||
pub enum BufferState {
|
||||
/// Passive channel.
|
||||
RxNotActive = 0b0000,
|
||||
RxReady = 0b0001,
|
||||
RxBusy0 = 0b0010,
|
||||
/// This condition indicated that SW wrote RxNotActive to a buffer when a data copy
|
||||
/// process is still active.
|
||||
RxBusy = 0b0001,
|
||||
RxReady = 0b0010,
|
||||
/// Indicated that data is being copied for the first time (RxRead -> RxBusy0).
|
||||
RxBusy0 = 0b0011,
|
||||
RxFull = 0b0100,
|
||||
/// Indicated that data is being copied for the second time (RxFull -> RxBusy2).
|
||||
RxBusy1 = 0b0101,
|
||||
RxOverrun = 0b0110,
|
||||
RxBusy2 = 0b0111,
|
||||
TxNotActive = 0b1000,
|
||||
/// Automatical response to a remote frame.
|
||||
TxRtr = 0b1010,
|
||||
/// Transmit one frame.
|
||||
TxOnce = 0b1100,
|
||||
TxBusy0 = 0b1101,
|
||||
/// Transmit one frame, and changes to TxRtr after that. This can either be written by
|
||||
/// software, or it will be written by the hardware after an auto response of the
|
||||
/// [BufferState::TxRtr] state.
|
||||
TxOnceRtr = 0b1110,
|
||||
TxBusy2 = 0b1111,
|
||||
}
|
||||
|
||||
/// Status control register for individual message buffers.
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct BufStatusAndControl {
|
||||
/// Data length code.
|
||||
#[bits(12..=15, rw)]
|
||||
@ -33,13 +45,13 @@ pub struct BufStatusAndControl {
|
||||
#[bits(4..=7, rw)]
|
||||
priority: u4,
|
||||
#[bits(0..=3, rw)]
|
||||
status: Option<BufferStatus>,
|
||||
status: Option<BufferState>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Data16Bit(arbitrary_int::UInt<u32, 16>);
|
||||
pub struct Timestamp(arbitrary_int::UInt<u32, 16>);
|
||||
|
||||
impl Data16Bit {
|
||||
impl Timestamp {
|
||||
pub fn new(value: u16) -> Self {
|
||||
Self(value.into())
|
||||
}
|
||||
@ -52,29 +64,38 @@ impl Data16Bit {
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct TwoBytesData {
|
||||
#[bits(8..=15, rw)]
|
||||
data_upper_byte: u8,
|
||||
#[bits(8..=15, rw)]
|
||||
data_lower_byte: u8,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct CanMsgBuf {
|
||||
stat_ctrl: BufStatusAndControl,
|
||||
timestamp: Data16Bit,
|
||||
data3: Data16Bit,
|
||||
data2: Data16Bit,
|
||||
data1: Data16Bit,
|
||||
data0: Data16Bit,
|
||||
id0: Data16Bit,
|
||||
id1: Data16Bit,
|
||||
timestamp: Timestamp,
|
||||
data3: TwoBytesData,
|
||||
data2: TwoBytesData,
|
||||
data1: TwoBytesData,
|
||||
data0: TwoBytesData,
|
||||
id0: ExtendedId,
|
||||
id1: BaseId,
|
||||
}
|
||||
|
||||
impl MmioCanMsgBuf<'_> {
|
||||
pub fn reset(&mut self) {
|
||||
self.write_stat_ctrl(BufStatusAndControl::new_with_raw_value(0));
|
||||
self.write_timestamp(Data16Bit::new(0));
|
||||
self.write_data3(Data16Bit::new(0));
|
||||
self.write_data2(Data16Bit::new(0));
|
||||
self.write_data1(Data16Bit::new(0));
|
||||
self.write_data0(Data16Bit::new(0));
|
||||
self.write_id1(Data16Bit::new(0));
|
||||
self.write_id0(Data16Bit::new(0));
|
||||
self.write_timestamp(Timestamp::new(0));
|
||||
self.write_data3(TwoBytesData::new_with_raw_value(0));
|
||||
self.write_data2(TwoBytesData::new_with_raw_value(0));
|
||||
self.write_data1(TwoBytesData::new_with_raw_value(0));
|
||||
self.write_data0(TwoBytesData::new_with_raw_value(0));
|
||||
self.write_id1(BaseId::new_with_raw_value(0));
|
||||
self.write_id0(ExtendedId::new_with_raw_value(0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +157,7 @@ pub struct Control {
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct TimingConfig {
|
||||
#[bits(0..=2, rw)]
|
||||
@ -185,6 +206,35 @@ pub struct ErrorCounter {
|
||||
receive: u8,
|
||||
}
|
||||
|
||||
/// This register is unused for standard frames.
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct ExtendedId {
|
||||
/// Mask for ID bits \[14:0\] of extended frames.
|
||||
#[bits(1..=15, rw)]
|
||||
mask_14_0: u15,
|
||||
/// CAN XRTR bit.
|
||||
#[bit(0, rw)]
|
||||
xrtr: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||
#[derive(Debug)]
|
||||
pub struct BaseId {
|
||||
/// This will contain ID\[10:0\] for standard frames and bits [28:18] for extended frames.
|
||||
#[bits(5..=15, rw)]
|
||||
mask_28_18: u11,
|
||||
/// This is the RTR bit for standard frames, and the SRR bit for extended frames.
|
||||
#[bit(4, rw)]
|
||||
rtr_or_srr: bool,
|
||||
/// Identifier extension bit.
|
||||
#[bit(3, rw)]
|
||||
ide: bool,
|
||||
/// Mask for ID bits \[17:15\] of extended frames.
|
||||
#[bits(0..=2, rw)]
|
||||
mask_17_15: u3,
|
||||
}
|
||||
|
||||
#[derive(derive_mmio::Mmio)]
|
||||
#[repr(C)]
|
||||
pub struct Can {
|
||||
@ -216,20 +266,22 @@ pub struct Can {
|
||||
cmb12: CanMsgBuf,
|
||||
#[mmio(inner)]
|
||||
cmb13: CanMsgBuf,
|
||||
// This CAN message buffer has different mask registers.
|
||||
#[mmio(inner)]
|
||||
cmb14: CanMsgBuf,
|
||||
/// Hidden CAN message buffer. Only allowed to be used internally by the peripheral.
|
||||
#[mmio(inner)]
|
||||
hcmb: CanMsgBuf,
|
||||
_hcmb: CanMsgBuf,
|
||||
control: Control,
|
||||
timing: TimingConfig,
|
||||
/// Global mask extension.
|
||||
gmskx: u32,
|
||||
/// Global mask base.
|
||||
gmskb: u32,
|
||||
/// Basic mask extension.
|
||||
bmskx: u32,
|
||||
/// Basic mask base.
|
||||
bmskb: u32,
|
||||
/// Global mask extension used for buffers 0 to 13.
|
||||
gmskx: ExtendedId,
|
||||
/// Global mask base used for buffers 0 to 13.
|
||||
gmskb: BaseId,
|
||||
/// Basic mask extension used for buffer 14.
|
||||
bmskx: ExtendedId,
|
||||
/// Basic mask base used for buffer 14.
|
||||
bmskb: BaseId,
|
||||
ien: InterruptEnable,
|
||||
#[mmio(PureRead)]
|
||||
ipnd: InterruptPending,
|
||||
@ -274,7 +326,7 @@ impl Can {
|
||||
impl MmioCan<'_> {
|
||||
// TODO: It would be nice if derive-mmio could generate this for us..
|
||||
pub fn msg_buf_block_mut(&mut self, idx: usize) -> MmioCanMsgBuf<'static> {
|
||||
assert!(idx < 16, "invalid index for CAN message buffer");
|
||||
assert!(idx < 15, "invalid index for CAN message buffer");
|
||||
match idx {
|
||||
0 => unsafe { self.steal_cmb0() },
|
||||
1 => unsafe { self.steal_cmb1() },
|
||||
@ -291,7 +343,6 @@ impl MmioCan<'_> {
|
||||
12 => unsafe { self.steal_cmb12() },
|
||||
13 => unsafe { self.steal_cmb13() },
|
||||
14 => unsafe { self.steal_cmb14() },
|
||||
15 => unsafe { self.steal_hcmb() },
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user