can_speedtest.rs 6.15 KiB
//! # 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); } };