va416xx_hal/can/
regs.rs

1//! Custom register definitions for the CAN register block to circumvent PAC API / SVD
2//! shortcomings.
3
4use arbitrary_int::{prelude::*, u11, u15, u2, u3, u4, u6, u7};
5
6pub const CAN_0_BASE: usize = 0x4001_4000;
7pub const CAN_1_BASE: usize = 0x4001_4400;
8
9#[derive(Debug, PartialEq, Eq)]
10#[bitbybit::bitenum(u4)]
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12pub enum BufferState {
13    /// Passive channel.
14    RxNotActive = 0b0000,
15    /// This condition indicated that SW wrote RxNotActive to a buffer when a data copy
16    /// process is still active.
17    RxBusy = 0b0001,
18    RxReady = 0b0010,
19    /// Indicated that data is being copied for the first time (RxRead -> RxBusy0).
20    RxBusy0 = 0b0011,
21    RxFull = 0b0100,
22    /// Indicated that data is being copied for the second time (RxFull -> RxBusy2).
23    RxBusy1 = 0b0101,
24    RxOverrun = 0b0110,
25    RxBusy2 = 0b0111,
26    TxNotActive = 0b1000,
27    /// Automatical response to a remote frame.
28    TxRtr = 0b1010,
29    /// Transmit one frame.
30    TxOnce = 0b1100,
31    TxBusy0 = 0b1101,
32    /// Transmit one frame, and changes to TxRtr after that. This can either be written by
33    /// software, or it will be written by the hardware after an auto response of the
34    /// [BufferState::TxRtr] state.
35    TxOnceRtr = 0b1110,
36    TxBusy2 = 0b1111,
37}
38
39/// Status control register for individual message buffers.
40#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_fields(feature = "defmt"))]
41pub struct BufStatusAndControl {
42    /// Data length code.
43    #[bits(12..=15, rw)]
44    dlc: u4,
45    #[bits(4..=7, rw)]
46    priority: u4,
47    #[bits(0..=3, rw)]
48    state: Option<BufferState>,
49}
50
51#[derive(Debug)]
52pub struct Timestamp(arbitrary_int::UInt<u32, 16>);
53
54impl Timestamp {
55    pub fn new(value: u16) -> Self {
56        Self(value.into())
57    }
58    pub fn value(&self) -> u16 {
59        self.0.value() as u16
60    }
61
62    pub fn write(&mut self, value: u16) {
63        self.0 = value.into();
64    }
65}
66
67#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
68pub struct TwoBytesData {
69    #[bits(0..=7, rw)]
70    data_lower_byte: u8,
71    #[bits(8..=15, rw)]
72    data_upper_byte: u8,
73}
74
75#[derive(derive_mmio::Mmio)]
76#[repr(C)]
77pub struct CanMessageBuffer {
78    stat_ctrl: BufStatusAndControl,
79    timestamp: Timestamp,
80    data3: TwoBytesData,
81    data2: TwoBytesData,
82    data1: TwoBytesData,
83    data0: TwoBytesData,
84    id0: ExtendedId,
85    id1: BaseId,
86}
87
88static_assertions::const_assert_eq!(core::mem::size_of::<CanMessageBuffer>(), 0x20);
89
90impl MmioCanMessageBuffer<'_> {
91    pub fn reset(&mut self) {
92        self.write_stat_ctrl(BufStatusAndControl::new_with_raw_value(0));
93        self.write_timestamp(Timestamp::new(0));
94        self.write_data0(TwoBytesData::new_with_raw_value(0));
95        self.write_data1(TwoBytesData::new_with_raw_value(0));
96        self.write_data2(TwoBytesData::new_with_raw_value(0));
97        self.write_data3(TwoBytesData::new_with_raw_value(0));
98        self.write_id1(BaseId::new_with_raw_value(0));
99        self.write_id0(ExtendedId::new_with_raw_value(0));
100    }
101}
102
103#[bitbybit::bitenum(u1, exhaustive = true)]
104#[derive(Debug)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub enum PinLogicLevel {
107    DominantIsZero = 0b0,
108    DominantIsOne = 0b1,
109}
110
111#[bitbybit::bitenum(u1, exhaustive = true)]
112#[derive(Debug)]
113#[cfg_attr(feature = "defmt", derive(defmt::Format))]
114pub enum ErrorInterruptType {
115    /// EIPND bit is set on every error.
116    EveryError = 0b0,
117    /// EIPND bit is only set if error state changes as a result of a receive or transmit
118    /// error counter increment.
119    ErrorOnRxTxCounterChange = 0b1,
120}
121
122#[bitbybit::bitenum(u1, exhaustive = true)]
123#[derive(Debug)]
124#[cfg_attr(feature = "defmt", derive(defmt::Format))]
125pub enum DataDirection {
126    FirstByteAtHighestAddr = 0b0,
127    LastByteAtHighestAddr = 0b1,
128}
129
130#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"))]
131pub struct Control {
132    #[bit(11, rw)]
133    error_interrupt_type: ErrorInterruptType,
134    /// Enables special diagnostics features of the CAN like LO, IGNACK, LOOPBACK, INTERNAL.
135    #[bit(10, rw)]
136    diag_enable: bool,
137    /// CANTX and CANRX pins are internally connected to each other.
138    #[bit(9, rw)]
139    internal: bool,
140    /// All messages sent by the CAN controller can also be received by a CAN buffer with a
141    /// matching buffer ID.
142    #[bit(8, rw)]
143    loopback: bool,
144    /// IGNACK feature. The CAN does not expect to receive an ACK bit.
145    #[bit(7, rw)]
146    ignore_ack: bool,
147    /// LO feature. The CAN is only configured as a receiver.
148    #[bit(6, rw)]
149    listen_only: bool,
150    #[bit(5, rw)]
151    data_dir: DataDirection,
152    #[bit(4, rw)]
153    timestamp_enable: bool,
154    #[bit(3, rw)]
155    bufflock: bool,
156    #[bit(2, rw)]
157    tx_logic_level: PinLogicLevel,
158    #[bit(1, rw)]
159    rx_logic_level: PinLogicLevel,
160    #[bit(0, rw)]
161    enable: bool,
162}
163
164#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
165pub struct TimingConfig {
166    #[bits(0..=2, rw)]
167    tseg2: u3,
168    #[bits(3..=6, rw)]
169    tseg1: u4,
170    #[bits(7..=8, rw)]
171    sync_jump_width: u2,
172    #[bits(9..=15, rw)]
173    prescaler: u7,
174}
175
176#[bitbybit::bitfield(u32)]
177#[derive(Debug)]
178pub struct InterruptEnable {
179    #[bit(15, rw)]
180    error: bool,
181    #[bit(0, rw)]
182    buffer: [bool; 15],
183}
184
185#[bitbybit::bitfield(u32)]
186#[derive(Debug)]
187pub struct InterruptClear {
188    #[bit(15, w)]
189    error: bool,
190    #[bit(0, w)]
191    buffer: [bool; 15],
192}
193
194#[bitbybit::bitfield(u32)]
195#[derive(Debug)]
196pub struct InterruptPending {
197    #[bit(15, r)]
198    error: bool,
199    #[bit(0, r)]
200    buffer: [bool; 15],
201}
202
203#[derive(Debug)]
204#[repr(usize)]
205#[cfg_attr(feature = "defmt", derive(defmt::Format))]
206pub enum CanInterruptId {
207    None = 0b00000,
208    Error = 0b10000,
209    Buffer(usize),
210}
211
212#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
213pub struct StatusPending {
214    #[bits(5..=7, r)]
215    ns: u3,
216    #[bit(4, r)]
217    irq: bool,
218    #[bits(0..=3, r)]
219    ist: u4,
220}
221
222impl StatusPending {
223    pub fn interrupt_id(&self) -> Option<CanInterruptId> {
224        if !self.irq() && self.ist().value() == 0 {
225            return Some(CanInterruptId::None);
226        }
227
228        if self.irq() && self.ist().value() == 0 {
229            return Some(CanInterruptId::Error);
230        }
231        if !self.irq() {
232            return None;
233        }
234        Some(CanInterruptId::Buffer(self.ist().as_usize() - 1))
235    }
236}
237
238#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
239pub struct ErrorCounter {
240    #[bits(0..=7, r)]
241    transmit: u8,
242    #[bits(8..=15, r)]
243    receive: u8,
244}
245
246/// This register is unused for standard frames.
247#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
248pub struct ExtendedId {
249    /// Mask for ID bits \[14:0\] of extended frames.
250    #[bits(1..=15, rw)]
251    mask_14_0: u15,
252    /// CAN XRTR bit.
253    #[bit(0, rw)]
254    xrtr: bool,
255}
256
257#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
258pub struct BaseId {
259    /// This will contain ID\[10:0\] for standard frames and bits \[28:18\] for extended frames.
260    #[bits(5..=15, rw)]
261    mask_28_18: u11,
262    /// This is the RTR bit for standard frames, and the SRR bit for extended frames.
263    #[bit(4, rw)]
264    rtr_or_srr: bool,
265    /// Identifier extension bit.
266    #[bit(3, rw)]
267    ide: bool,
268    /// Mask for ID bits \[17:15\] of extended frames.
269    #[bits(0..=2, rw)]
270    mask_17_15: u3,
271}
272
273#[derive(Debug, PartialEq, Eq)]
274#[bitbybit::bitenum(u4, exhaustive = true)]
275#[cfg_attr(feature = "defmt", derive(defmt::Format))]
276pub enum ErrorFieldId {
277    Error = 0b0000,
278    ErrorDel = 0b0001,
279    ErrorEcho = 0b0010,
280    BusIdle = 0b0011,
281    Ack = 0b0100,
282    Eof = 0b0101,
283    Intermission = 0b0110,
284    SuspendTransmission = 0b0111,
285    Sof = 0b1000,
286    Arbitration = 0b1001,
287    Ide = 0b1010,
288    ExtendedArbitration = 0b1011,
289    R1R0 = 0b1100,
290    Dlc = 0b1101,
291    Data = 0b1110,
292    Crc = 0b1111,
293}
294
295#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
296pub struct DiagnosticRegister {
297    /// Shows the output value on the CAN TX pin at the time of the error.
298    #[bit(14, r)]
299    drive: bool,
300    /// Shows the bus value on the CAN RX pin as sampled by the CAN module at the time of the
301    /// error.
302    #[bit(13, r)]
303    mon: bool,
304    /// Indicated whether the CRC is invalid. This bit should only be checked if the EFID field
305    /// is [ErrorFieldId::Ack].
306    #[bit(12, r)]
307    crc: bool,
308    /// Indicated whether the bit stuffing rule was violated at the time the error occured.
309    #[bit(11, r)]
310    stuff: bool,
311    /// Indicated whether the CAN module was an active transmitter at the time the error occured.
312    #[bit(10, r)]
313    txe: bool,
314    #[bits(4..=9, r)]
315    ebid: u6,
316    #[bits(0..=3, r)]
317    efid: ErrorFieldId,
318}
319
320#[derive(derive_mmio::Mmio)]
321#[mmio(const_inner)]
322#[repr(C)]
323pub struct Can {
324    #[mmio(Inner)]
325    cmbs: [CanMessageBuffer; 15],
326    /// Hidden CAN message buffer. Only allowed to be used internally by the peripheral.
327    #[mmio(Inner)]
328    _hcmb: CanMessageBuffer,
329    control: Control,
330    timing: TimingConfig,
331    /// Global mask extension used for buffers 0 to 13.
332    gmskx: ExtendedId,
333    /// Global mask base used for buffers 0 to 13.
334    gmskb: BaseId,
335    /// Basic mask extension used for buffer 14.
336    bmskx: ExtendedId,
337    /// Basic mask base used for buffer 14.
338    bmskb: BaseId,
339    ien: InterruptEnable,
340    #[mmio(PureRead)]
341    ipnd: InterruptPending,
342    #[mmio(Write)]
343    iclr: InterruptClear,
344    /// Interrupt Code Enable Register.
345    icen: InterruptEnable,
346    #[mmio(PureRead)]
347    status_pending: StatusPending,
348    #[mmio(PureRead)]
349    error_counter: ErrorCounter,
350    #[mmio(PureRead)]
351    diag: DiagnosticRegister,
352    #[mmio(PureRead)]
353    timer: u32,
354}
355
356static_assertions::const_assert_eq!(core::mem::size_of::<Can>(), 0x238);
357
358impl Can {
359    /// Create a new CAN MMIO instance for peripheral 0.
360    ///
361    /// # Safety
362    ///
363    /// This API can be used to potentially create a driver to the same peripheral structure
364    /// from multiple threads. The user must ensure that concurrent accesses are safe and do not
365    /// interfere with each other.
366    pub const unsafe fn new_mmio_fixed_0() -> MmioCan<'static> {
367        Self::new_mmio_at(CAN_0_BASE)
368    }
369
370    /// Create a new CAN MMIO instance for peripheral 1.
371    ///
372    /// # Safety
373    ///
374    /// This API can be used to potentially create a driver to the same peripheral structure
375    /// from multiple threads. The user must ensure that concurrent accesses are safe and do not
376    /// interfere with each other.
377    pub const unsafe fn new_mmio_fixed_1() -> MmioCan<'static> {
378        Self::new_mmio_at(CAN_1_BASE)
379    }
380}