An error occurred while loading the file. Please try again.
-
A Sundbom authored86ec72da
//! # Point-to-point speedtest
//! This program sllows you to strobe the CAN network with a single packet whose
//! starting time is known. Simply run the program, setup your oscilloscope to
//! probe the GPIO output and measure the time taken between rise and fall.
//!
//! At some point, the timer will trigger to send your CAN output, which makes
//! the breakpoint trigger, allowing you to setup single-edge triggering.
//!
//! *REMEMBER: Using debug mode builds will yield _very_ pessimistic results.*
#![feature(panic_info_message)]
#![no_main]
#![no_std]
extern crate panic_halt;
// CAN driver
use lpc43xx_hal::{
can::{CanBus, MsgIface, MsgObj},
pac,
timer::{InterruptType, Timer},
};
use pac::c_can1::cntl::{DAR_A, EIE_A, IE_A, SIE_A};
static TIMER_PERIOD: u32 = 8192;
use rtfm::app;
use heapless::consts::U32;
#[app(device = lpc43xx_pac)]
const APP: () = {
static mut GPIO: pac::GPIO_PORT = ();
static mut TIMER: Timer<pac::TIMER0> = ();
static mut CAN_0: CanBus<pac::C_CAN0, U32> = ();
static mut CAN_1: CanBus<pac::C_CAN1, U32> = ();
static mut RX_OBJ: MsgObj = ();
static mut TX_OBJ: MsgObj = ();
static mut TX_STATE: u8 = ();
#[init]
fn init() -> init::LateResources {
let tx_state: u8 = 0;
// ========= TIMER INITIALIZATION ==========
let timer = Timer::<pac::TIMER0>::new(device.TIMER0);
timer.start_timer(false);
timer.set_match(0, TIMER_PERIOD);
timer.set_prescaler(1024, Some(0));
timer.mr0(true, true, false);
timer.start_timer(true);
// ========= GPIO SETUP =========
device.SCU.sfsp7_7.write(|w| w.mode().function_0_default());
device.GPIO_PORT.dir[3].write(|w| w.dirp15().set_bit());
device.GPIO_PORT.clr[3].write(|w| w.clrp015().set_bit());
// ========= CAN 0 INITIALIZATION ==========
let mut can_0 = CanBus::<pac::C_CAN0, U32>::new(device.C_CAN0);
device
.SCU
.sfspe_3
.write(|w| w.mode().function_1().epun().bit(true)); // CAN0_TD
device
.SCU
.sfspe_2
.write(|w| w.mode().function_1().epun().bit(true).ezi().bit(true)); // CAN0_RD
can_0.initialize(
12_000_000,
500000,
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
IE_A::ENABLE_CAN_INTERRUPTS,
SIE_A::DISABLE_STATUS_CHANGE_INTERRUPTS,
EIE_A::DISABLE_ERROR_INTERRUPTS,
DAR_A::ENABLED,
false,
);
// Object setup
let tx_obj = MsgObj::new_tx_obj(true, 0x200, 0x8, 0xDEADBEEF, 0x8008135);
// ========= CAN 1 INITIALIZATION ==========
let mut can_1 = CanBus::<pac::C_CAN1, U32>::new(device.C_CAN1);
device
.SCU
.sfspe_0
.write(|w| w.mode().function_5().epun().bit(true)); // CAN1_TD
device
.SCU
.sfspe_1
.write(|w| w.mode().function_5().epun().bit(true).ezi().bit(true)); // CAN1_RD
can_1.initialize(
12_000_000,
500000,
IE_A::ENABLE_CAN_INTERRUPTS,
SIE_A::DISABLE_STATUS_CHANGE_INTERRUPTS,
EIE_A::DISABLE_ERROR_INTERRUPTS,
DAR_A::ENABLED,
false,
);
let rx_obj = MsgObj::new_rx_obj(true, 0x200, 0x8, 0xfffffff);
can_1.transfer_obj(MsgIface::Iface1, 1, &rx_obj);
init::LateResources {
GPIO: device.GPIO_PORT,
RX_OBJ: rx_obj,
TX_OBJ: tx_obj,
TIMER: timer,
CAN_0: can_0,
CAN_1: can_1,
TX_STATE: tx_state,
}
}
#[idle]
fn idle() -> ! {
loop {}
}
#[interrupt(resources = [GPIO, TIMER, CAN_0, TX_OBJ, TX_STATE])]
fn TIMER0() {
match resources.TX_STATE {
0 => resources
.TX_OBJ
.msgval(false)
.mctrl_txrqst(false)
.cmdmsk_txrqst(false)
.data_a(true)
.data_b(true),
1 => resources
.TX_OBJ
.msgval(false)
.newdat(true)
.mctrl_txrqst(true)
.cmdmsk_txrqst(true),
2 => resources
.TX_OBJ
.msgval(true)
.mctrl_txrqst(true)
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
.cmdmsk_txrqst(true),
_ => resources
.TX_OBJ
.msgval(false)
.mctrl_txrqst(false)
.cmdmsk_txrqst(false),
};
*resources.TX_STATE += if *resources.TX_STATE < 4 { 1 } else { 0 };
if *resources.TX_STATE == 2 {
cortex_m::asm::bkpt();
resources.GPIO.set[3].write(|w| w.setp15().set_bit());
}
resources
.CAN_0
.transfer_obj(MsgIface::Iface1, 1, &resources.TX_OBJ);
resources
.TIMER
.clear_interrupt(InterruptType::MatchChannel, 0);
if *resources.TX_STATE == 3 {
resources.TIMER.start_timer(false);
}
}
#[interrupt(resources = [TX_OBJ, CAN_0, GPIO])]
fn C_CAN0() {
resources
.CAN_0
.can
.stat
.modify(|_, w| w.txok().bit(false).rxok().bit(false));
// Clear newdat
let mut tx_obj = resources.TX_OBJ;
tx_obj.cmdmsk = (1 << 2) | (1 << 3) | (1 << 7); // NEWDAT, WR_RD
tx_obj.newdat(false);
tx_obj.mctrl_txrqst(false);
tx_obj.cmdmsk_txrqst(false);
// Write object
let mut can = resources.CAN_0;
can.transfer_obj(MsgIface::Iface1, 1, &tx_obj);
}
#[interrupt(resources = [CAN_1, GPIO, RX_OBJ])]
fn C_CAN1() {
resources.GPIO.clr[3].write(|w| w.clrp015().set_bit());
resources
.CAN_1
.can
.stat
.modify(|_, w| w.txok().bit(false).rxok().bit(false));
// Clear newdat
let mut rx_obj = resources.RX_OBJ;
rx_obj.cmdmsk = (1 << 2) | (1 << 3) | (1 << 7); // NEWDAT, WR_RD
rx_obj.newdat(false);
rx_obj.mctrl_txrqst(false);
rx_obj.cmdmsk_txrqst(false);
// Write object
let can = resources.CAN_1;
can.transfer_obj(MsgIface::Iface1, 1, &rx_obj);
}
};