add CAN example app
This commit is contained in:
parent
997e0502ab
commit
629ba4f8f2
@ -18,6 +18,7 @@ static_cell = "2"
|
||||
critical-section = "1"
|
||||
ringbuf = { version = "0.4", default-features = false }
|
||||
|
||||
nb = "1"
|
||||
embassy-sync = "0.6"
|
||||
embassy-time = "0.4"
|
||||
embassy-executor = { version = "0.7", features = [
|
||||
|
57
examples/embassy/src/bin/can.rs
Normal file
57
examples/embassy/src/bin/can.rs
Normal file
@ -0,0 +1,57 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
// Import panic provider.
|
||||
use panic_probe as _;
|
||||
// Import logger.
|
||||
use defmt_rtt as _;
|
||||
|
||||
use embassy_example::EXTCLK_FREQ;
|
||||
use embassy_executor::Spawner;
|
||||
use va416xx_hal::can::asynch::on_interrupt_can;
|
||||
use va416xx_hal::can::{Can, CanFrame, CanFrameNormal, CanId, CanRx, CanTx, ClockConfig};
|
||||
use va416xx_hal::clock::ClockConfigurator;
|
||||
use va416xx_hal::pac::{self, interrupt};
|
||||
use va416xx_hal::time::Hertz;
|
||||
use va416xx_hal::{can, prelude::*};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
defmt::println!("-- VA416xx CAN Demo --");
|
||||
|
||||
let dp = pac::Peripherals::take().unwrap();
|
||||
|
||||
// Initialize the systick interrupt & obtain the token to prove that we did
|
||||
// Use the external clock connected to XTAL_N.
|
||||
let clocks = ClockConfigurator::new(dp.clkgen)
|
||||
.xtal_n_clk_with_src_freq(Hertz::from_raw(EXTCLK_FREQ))
|
||||
.freeze()
|
||||
.unwrap();
|
||||
// Safety: Only called once here.
|
||||
va416xx_embassy::init(dp.tim15, dp.tim14, &clocks);
|
||||
let clk_config = ClockConfig::from_bitrate_and_segments(&clocks, 250.kHz(), 16, 4, 4).unwrap();
|
||||
let mut can = Can::new(dp.can0, clk_config);
|
||||
can.set_loopback(true);
|
||||
can.set_bufflock(true);
|
||||
can.set_base_mask_for_all_match();
|
||||
can.enable();
|
||||
let mut channels = can.take_channels().unwrap();
|
||||
// Transmit channel.
|
||||
let mut tx = CanTx::new(channels.take(0).unwrap(), None);
|
||||
// Base channel which has dedicated mask.
|
||||
let mut rx = CanRx::new(channels.take(14).unwrap());
|
||||
let send_frame = CanFrame::Normal(CanFrameNormal::new(
|
||||
can::Id::Standard(can::StandardId::new(0x1).unwrap()),
|
||||
&[1, 2, 3, 4],
|
||||
));
|
||||
defmt::info!("sending CAN frame");
|
||||
tx.transmit_frame(send_frame).unwrap();
|
||||
let _frame = nb::block!(rx.receive(true)).expect("invalid CAN rx state");
|
||||
defmt::info!("received CAN frame with data");
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
#[allow(non_snake_case)]
|
||||
fn CAN0() {
|
||||
on_interrupt_can(CanId::Can0, false).unwrap();
|
||||
}
|
@ -53,6 +53,8 @@ pub enum InterruptResult {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum InterruptError {
|
||||
UnexpectedError,
|
||||
InvalidInterruptId(StatusPending),
|
||||
@ -95,35 +97,30 @@ pub fn on_interrupt_can(
|
||||
return Err(InterruptError::InvalidInterruptId(pending_id));
|
||||
}
|
||||
match pending_id.interrupt_id().unwrap() {
|
||||
super::regs::CanInterruptId::None => {
|
||||
return Ok(InterruptResult::NoInterrupt);
|
||||
}
|
||||
super::regs::CanInterruptId::Error => {
|
||||
return Err(InterruptError::CanError(regs.read_diag()));
|
||||
}
|
||||
super::regs::CanInterruptId::None => Ok(InterruptResult::NoInterrupt),
|
||||
super::regs::CanInterruptId::Error => Err(InterruptError::CanError(regs.read_diag())),
|
||||
super::regs::CanInterruptId::Buffer(idx) => {
|
||||
let mut channel = unsafe { CanChannelLowLevel::steal_unchecked(id, idx) };
|
||||
let status = channel.read_status();
|
||||
let status = channel.read_state();
|
||||
if status.is_err() {
|
||||
let mut clr = InterruptClear::new_with_raw_value(0);
|
||||
clr.set_buffer(idx as usize, true);
|
||||
clr.set_buffer(idx, true);
|
||||
regs.write_iclr(clr);
|
||||
regs.modify_ien(|mut val| {
|
||||
val.set_buffer(idx as usize, false);
|
||||
val.set_buffer(idx, false);
|
||||
val
|
||||
});
|
||||
return Err(InterruptError::InvalidStatus(status.unwrap_err()));
|
||||
}
|
||||
let buf_state = status.unwrap();
|
||||
if buf_state == BufferState::TxNotActive {
|
||||
let tx_state = TX_STATES[idx as usize].load(Ordering::Relaxed);
|
||||
let tx_state = TX_STATES[idx].load(Ordering::Relaxed);
|
||||
clear_and_disable_interrupt(&mut regs, idx);
|
||||
// Handle reading frames, updating states etc.
|
||||
if tx_state == TxChannelState::TxDataFrame as u8 {
|
||||
// Transmission complete.
|
||||
TX_STATES[idx as usize]
|
||||
.store(TxChannelState::Finished as u8, Ordering::Relaxed);
|
||||
TX_WAKERS[idx as usize].wake();
|
||||
TX_STATES[idx].store(TxChannelState::Finished as u8, Ordering::Relaxed);
|
||||
TX_WAKERS[idx].wake();
|
||||
return Ok(InterruptResult::TransmissionEvent {
|
||||
channel_index: idx,
|
||||
id: TxEventId::TxDataFrame,
|
||||
@ -131,22 +128,21 @@ pub fn on_interrupt_can(
|
||||
}
|
||||
}
|
||||
if buf_state == BufferState::RxReady {
|
||||
let tx_state = TX_STATES[idx as usize].load(Ordering::Relaxed);
|
||||
let tx_state = TX_STATES[idx].load(Ordering::Relaxed);
|
||||
if tx_state == TxChannelState::TxRtrTransmission as u8 {
|
||||
if reconfigure_tx_rtr_to_tx {
|
||||
channel.write_status(BufferState::TxNotActive);
|
||||
channel.write_state(BufferState::TxNotActive);
|
||||
clear_and_disable_interrupt(&mut regs, idx);
|
||||
// Transmission complete.
|
||||
TX_STATES[idx as usize]
|
||||
.store(TxChannelState::Idle as u8, Ordering::Relaxed);
|
||||
TX_STATES[idx].store(TxChannelState::Idle as u8, Ordering::Relaxed);
|
||||
} else {
|
||||
// Do not disable interrupt, channel is now used to receive the frame.
|
||||
clear_interrupt(&mut regs, idx);
|
||||
// Transmission complete.
|
||||
TX_STATES[idx as usize]
|
||||
TX_STATES[idx]
|
||||
.store(TxChannelState::TxRtrReception as u8, Ordering::Relaxed);
|
||||
}
|
||||
TX_WAKERS[idx as usize].wake();
|
||||
TX_WAKERS[idx].wake();
|
||||
return Ok(InterruptResult::TransmissionEvent {
|
||||
channel_index: idx,
|
||||
id: TxEventId::TxRemoteFrame,
|
||||
@ -154,18 +150,18 @@ pub fn on_interrupt_can(
|
||||
}
|
||||
}
|
||||
if buf_state == BufferState::RxOverrun || buf_state == BufferState::RxFull {
|
||||
let tx_state = TX_STATES[idx as usize].load(Ordering::Relaxed);
|
||||
let tx_state = TX_STATES[idx].load(Ordering::Relaxed);
|
||||
// Do not disable interrupt and assume continuous reception.
|
||||
clear_interrupt(&mut regs, idx);
|
||||
let frame = channel.read_frame_unchecked();
|
||||
if tx_state == TxChannelState::TxRtrReception as u8 {
|
||||
// Reception of response complete. We can release the channel for TX (or RX)
|
||||
// usage again.
|
||||
TX_STATES[idx as usize].store(TxChannelState::Idle as u8, Ordering::Relaxed);
|
||||
channel.write_status(BufferState::TxNotActive);
|
||||
TX_STATES[idx].store(TxChannelState::Idle as u8, Ordering::Relaxed);
|
||||
channel.write_state(BufferState::TxNotActive);
|
||||
} else {
|
||||
// Assume continous reception of frames.
|
||||
channel.write_status(BufferState::RxReady);
|
||||
channel.write_state(BufferState::RxReady);
|
||||
}
|
||||
return Ok(InterruptResult::ReceivedFrame {
|
||||
channel_index: idx,
|
||||
@ -205,7 +201,7 @@ fn clear_interrupt(regs: &mut MmioCan<'static>, idx: usize) {
|
||||
fn clear_and_disable_interrupt(regs: &mut MmioCan<'static>, idx: usize) {
|
||||
clear_interrupt(regs, idx);
|
||||
regs.modify_ien(|mut val| {
|
||||
val.set_buffer(idx as usize, false);
|
||||
val.set_buffer(idx, false);
|
||||
val
|
||||
});
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
pub use embedded_can::{ExtendedId, Id, StandardId};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("invalid data size error {0}")]
|
||||
pub struct InvalidDataSizeError(usize);
|
||||
|
@ -63,12 +63,12 @@ impl CanChannelLowLevel {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn read_status(&self) -> Result<BufferState, u8> {
|
||||
pub fn read_state(&self) -> Result<BufferState, u8> {
|
||||
self.msg_buf.read_stat_ctrl().status()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_status(&mut self, buffer_state: BufferState) {
|
||||
pub fn write_state(&mut self, buffer_state: BufferState) {
|
||||
self.msg_buf.modify_stat_ctrl(|mut val| {
|
||||
val.set_status(buffer_state);
|
||||
val
|
||||
@ -90,7 +90,7 @@ impl CanChannelLowLevel {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn configure_for_reception_with_standard_id(
|
||||
pub fn set_standard_id(
|
||||
&mut self,
|
||||
standard_id: embedded_can::StandardId,
|
||||
set_rtr: bool,
|
||||
@ -101,18 +101,10 @@ impl CanChannelLowLevel {
|
||||
}
|
||||
self.msg_buf
|
||||
.write_id1(BaseId::new_with_raw_value(id1_reg as u32));
|
||||
|
||||
self.msg_buf.write_stat_ctrl(
|
||||
BufStatusAndControl::builder()
|
||||
.with_dlc(u4::new(0))
|
||||
.with_priority(u4::new(0))
|
||||
.with_status(BufferState::RxReady)
|
||||
.build(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn configure_for_reception_with_extended_id(
|
||||
pub fn set_extended_id(
|
||||
&mut self,
|
||||
extended_id: embedded_can::ExtendedId,
|
||||
set_rtr: bool,
|
||||
@ -124,6 +116,10 @@ impl CanChannelLowLevel {
|
||||
let id0_reg = ((id_raw & 0x7FFF) << 1) as u16 | set_rtr as u16;
|
||||
self.msg_buf
|
||||
.write_id0(ExtendedId::new_with_raw_value(id0_reg as u32));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn configure_for_reception(&mut self) {
|
||||
self.msg_buf.write_stat_ctrl(
|
||||
BufStatusAndControl::builder()
|
||||
.with_dlc(u4::new(0))
|
||||
@ -131,7 +127,6 @@ impl CanChannelLowLevel {
|
||||
.with_status(BufferState::RxReady)
|
||||
.build(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn transmit_frame_unchecked(&mut self, frame: CanFrame) {
|
||||
|
@ -6,7 +6,7 @@ use core::sync::atomic::AtomicBool;
|
||||
use arbitrary_int::{u11, u15, u2, u3, u4, u7, Number};
|
||||
use embedded_can::Frame;
|
||||
use ll::CanChannelLowLevel;
|
||||
use regs::{BaseId, BufferState, Control, ExtendedId, MmioCan, TimingConfig};
|
||||
use regs::{BaseId, BufferState, Control, MmioCan, TimingConfig};
|
||||
|
||||
use crate::{clock::Clocks, enable_peripheral_clock, time::Hertz, PeripheralSelect};
|
||||
use libm::roundf;
|
||||
@ -230,7 +230,7 @@ impl ClockConfig {
|
||||
}
|
||||
|
||||
/// Calculate the clock configuration for the given input clock, the target bitrate and for a
|
||||
/// set of timing parameters.
|
||||
/// set of timing parameters. The CAN controller uses the APB1 clock.
|
||||
///
|
||||
/// This function basically calculates the necessary prescaler to achieve the given timing
|
||||
/// parameters. It also performs sanity and validity checks for the calculated prescaler:
|
||||
@ -314,7 +314,7 @@ impl Can {
|
||||
/// 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_gmskx(regs::ExtendedId::new_with_raw_value(0));
|
||||
self.regs.write_gmskb(BaseId::new_with_raw_value(0));
|
||||
}
|
||||
|
||||
@ -333,7 +333,7 @@ impl Can {
|
||||
/// on that buffer.
|
||||
pub fn set_global_mask_for_exact_id_match_with_rtr_masked(&mut self) {
|
||||
self.regs.write_gmskx(
|
||||
ExtendedId::builder()
|
||||
regs::ExtendedId::builder()
|
||||
.with_mask_14_0(u15::new(0))
|
||||
.with_xrtr(true)
|
||||
.build(),
|
||||
@ -352,7 +352,7 @@ impl Can {
|
||||
/// 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_bmskx(regs::ExtendedId::new_with_raw_value(0));
|
||||
self.regs.write_bmskb(BaseId::new_with_raw_value(0));
|
||||
}
|
||||
|
||||
@ -360,7 +360,7 @@ impl Can {
|
||||
/// 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));
|
||||
.write_bmskx(regs::ExtendedId::new_with_raw_value(0xffff));
|
||||
self.regs.write_bmskb(BaseId::new_with_raw_value(0xffff));
|
||||
}
|
||||
|
||||
@ -380,9 +380,17 @@ impl Can {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn enable_bufflock(&mut self) {
|
||||
pub fn set_loopback(&mut self, enable: bool) {
|
||||
self.regs.modify_control(|mut val| {
|
||||
val.set_loopback(enable);
|
||||
val
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_bufflock(&mut self, enable: bool) {
|
||||
self.regs.modify_control(|mut ctrl| {
|
||||
ctrl.set_bufflock(true);
|
||||
ctrl.set_bufflock(enable);
|
||||
ctrl
|
||||
});
|
||||
}
|
||||
@ -400,7 +408,6 @@ impl Can {
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum TxState {
|
||||
Idle,
|
||||
TransmissionIdle,
|
||||
TransmittingDataFrame,
|
||||
TransmittingRemoteFrame,
|
||||
AwaitingRemoteFrameReply,
|
||||
@ -430,28 +437,20 @@ pub struct CanTx {
|
||||
}
|
||||
|
||||
impl CanTx {
|
||||
pub fn new(ll: CanChannelLowLevel) -> Self {
|
||||
pub fn new(mut ll: CanChannelLowLevel, tx_priority: Option<u4>) -> Self {
|
||||
ll.configure_for_transmission(tx_priority).unwrap();
|
||||
Self {
|
||||
ll,
|
||||
mode: TxState::Idle,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn configure_for_transmission(
|
||||
&mut self,
|
||||
tx_priority: Option<u4>,
|
||||
) -> Result<(), InvalidBufferIndexError> {
|
||||
self.ll.configure_for_transmission(tx_priority).unwrap();
|
||||
self.mode = TxState::TransmissionIdle;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn transmit_frame(&mut self, frame: CanFrame) -> Result<(), InvalidTxStateError> {
|
||||
if self.mode == TxState::AwaitingRemoteFrameReply {
|
||||
self.configure_for_transmission(None).unwrap();
|
||||
self.mode = TxState::TransmissionIdle;
|
||||
self.ll.configure_for_transmission(None).unwrap();
|
||||
self.mode = TxState::Idle;
|
||||
}
|
||||
if self.mode != TxState::TransmissionIdle {
|
||||
if self.mode != TxState::Idle {
|
||||
return Err(InvalidTxStateError(self.mode));
|
||||
}
|
||||
if !frame.is_remote_frame() {
|
||||
@ -467,13 +466,13 @@ impl CanTx {
|
||||
if self.mode != TxState::TransmittingDataFrame {
|
||||
return Err(nb::Error::Other(InvalidTxStateError(self.mode)));
|
||||
}
|
||||
let status = self.ll.read_status();
|
||||
let status = self.ll.read_state();
|
||||
if status.is_err() {
|
||||
return Err(nb::Error::WouldBlock);
|
||||
}
|
||||
let status = status.unwrap();
|
||||
if status == BufferState::TxNotActive {
|
||||
self.mode = TxState::TransmissionIdle;
|
||||
self.mode = TxState::Idle;
|
||||
return Ok(());
|
||||
}
|
||||
Err(nb::Error::WouldBlock)
|
||||
@ -483,7 +482,7 @@ impl CanTx {
|
||||
if self.mode != TxState::TransmittingRemoteFrame {
|
||||
return Err(nb::Error::Other(InvalidTxStateError(self.mode)));
|
||||
}
|
||||
let status = self.ll.read_status();
|
||||
let status = self.ll.read_state();
|
||||
if status.is_err() {
|
||||
return Err(nb::Error::WouldBlock);
|
||||
}
|
||||
@ -505,14 +504,19 @@ pub struct CanRx {
|
||||
}
|
||||
|
||||
impl CanRx {
|
||||
pub fn new(ll: CanChannelLowLevel) -> Self {
|
||||
Self {
|
||||
ll,
|
||||
mode: RxState::Idle,
|
||||
}
|
||||
}
|
||||
pub fn configure_for_reception_with_standard_id(
|
||||
&mut self,
|
||||
standard_id: embedded_can::StandardId,
|
||||
set_rtr: bool,
|
||||
) -> Result<(), InvalidBufferIndexError> {
|
||||
self.ll
|
||||
.configure_for_reception_with_standard_id(standard_id, set_rtr)?;
|
||||
self.mode = RxState::Receiving;
|
||||
self.ll.set_standard_id(standard_id, set_rtr)?;
|
||||
self.configure_for_reception();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -521,12 +525,16 @@ impl CanRx {
|
||||
extended_id: embedded_can::ExtendedId,
|
||||
set_rtr: bool,
|
||||
) -> Result<(), InvalidBufferIndexError> {
|
||||
self.ll
|
||||
.configure_for_reception_with_extended_id(extended_id, set_rtr)?;
|
||||
self.mode = RxState::Receiving;
|
||||
self.ll.set_extended_id(extended_id, set_rtr)?;
|
||||
self.configure_for_reception();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn configure_for_reception(&mut self) {
|
||||
self.ll.configure_for_reception();
|
||||
self.mode = RxState::Receiving;
|
||||
}
|
||||
|
||||
pub fn receive(
|
||||
&mut self,
|
||||
reconfigure_for_reception: bool,
|
||||
@ -534,7 +542,7 @@ impl CanRx {
|
||||
if self.mode != RxState::Receiving {
|
||||
return Err(nb::Error::Other(InvalidRxStateError(self.mode)));
|
||||
}
|
||||
let status = self.ll.read_status();
|
||||
let status = self.ll.read_state();
|
||||
if status.is_err() {
|
||||
return Err(nb::Error::WouldBlock);
|
||||
}
|
||||
@ -542,7 +550,7 @@ impl CanRx {
|
||||
if status == BufferState::RxReady || status == BufferState::RxOverrun {
|
||||
self.mode = RxState::Idle;
|
||||
if reconfigure_for_reception {
|
||||
self.ll.write_status(BufferState::RxReady);
|
||||
self.ll.write_state(BufferState::RxReady);
|
||||
}
|
||||
return Ok(self.ll.read_frame_unchecked());
|
||||
}
|
||||
@ -557,25 +565,28 @@ pub struct CanChannels {
|
||||
|
||||
impl CanChannels {
|
||||
const fn new(id: CanId) -> Self {
|
||||
Self {
|
||||
id,
|
||||
channels: [
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 0)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 1)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 2)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 3)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 4)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 5)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 6)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 7)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 8)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 9)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 10)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 11)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 12)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 13)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 14)),
|
||||
],
|
||||
// Safety: Private function, ownership rules enforced by public API.
|
||||
unsafe {
|
||||
Self {
|
||||
id,
|
||||
channels: [
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 0)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 1)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 2)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 3)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 4)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 5)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 6)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 7)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 8)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 9)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 10)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 11)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 12)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 13)),
|
||||
Some(CanChannelLowLevel::steal_unchecked(id, 14)),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ pub const CAN_1_BASE: usize = 0x4001_4400;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[bitbybit::bitenum(u4)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BufferState {
|
||||
/// Passive channel.
|
||||
RxNotActive = 0b0000,
|
||||
@ -207,6 +208,7 @@ pub enum CanInterruptId {
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct StatusPending {
|
||||
#[bits(5..=7, r)]
|
||||
ns: u3,
|
||||
|
@ -33,7 +33,7 @@ use gpio::Port;
|
||||
pub use va416xx as device;
|
||||
pub use va416xx as pac;
|
||||
|
||||
pub mod prelude;
|
||||
pub mod can;
|
||||
pub mod clock;
|
||||
pub mod dma;
|
||||
pub mod edac;
|
||||
@ -41,12 +41,12 @@ pub mod gpio;
|
||||
pub mod i2c;
|
||||
pub mod irq_router;
|
||||
pub mod pins;
|
||||
pub mod prelude;
|
||||
pub mod pwm;
|
||||
pub mod spi;
|
||||
pub mod time;
|
||||
pub mod timer;
|
||||
pub mod uart;
|
||||
pub mod can;
|
||||
pub mod wdt;
|
||||
|
||||
#[cfg(feature = "va41630")]
|
||||
|
Loading…
x
Reference in New Issue
Block a user