Forked from Embedded Rust / lpc43xx-hal
Source project has a limited visibility.
can.rs 8.40 KiB
#![feature(panic_info_message)]
#![no_main]
#![no_std]
extern crate panic_halt;
use lpc43xx_hal::{
    can::{CanBus, MsgIface, MsgObj},
    io::pin::{split_ports, PinSplit},
    pac,
    serial::Serial,
    timer::{Timer, EMC0_A, InterruptType, MR0I_A, MR0R_A, MR0S_A, NoMatchPin, NoCapturePin},
use pac::{
    c_can1::cntl::{DAR_A, EIE_A, IE_A, SIE_A},
    usart0::lcr::{BC_A, DLAB_A, PE_A, PS_A, SBS_A, WLS_A},
    SCU,
use heapless::consts::U32;
static TIMER_PERIOD: u32 = 8192;
// Panic handler for USART3
// use lpc43xx_hal::{debug::PanicInfo, uart_panic_handler};
// uart_panic_handler!(pac::USART3);
use core::fmt::Write;
use rtfm::app;
type Timer0 = Timer<pac::TIMER0, NoMatchPin, NoMatchPin, NoMatchPin, NoMatchPin, NoCapturePin, NoCapturePin, NoCapturePin, NoCapturePin>;
#[app(device = lpc43xx_pac)]
const APP: () = {
    static mut TIMER: Timer0 = ();
    static mut UART: Serial<pac::USART3> = ();
    static mut CAN_0: CanBus<pac::C_CAN0, U32> = ();
    static mut CAN_1: CanBus<pac::C_CAN1, U32> = ();
    static mut TX_OBJ: MsgObj = ();
    static mut TX_STATE: u8 = ();
    #[init]
    fn init() -> init::LateResources {
        let tx_state: u8 = 0;
        // Pins
        let port_9 = split_ports(device.SCU, device.GPIO_PORT)
            .port_9
            .split_pins();
        let uart_tx = port_9.p9_3;
        let uart_rx = port_9.p9_4;
        // ========= TIMER INITIALIZATION ==========
        let mut timer = Timer0::new_no_pins(device.TIMER0);
        timer.start_timer(false);
        timer.set_match(0, TIMER_PERIOD);
        timer.set_prescaler(1024, Some(0));
        unsafe {
            timer.mr0(MR0I_A::INTERRUPT, MR0R_A::RESET, MR0S_A::NO_STOP, EMC0_A::NOP);
        timer.start_timer(true);
        // ========= SERIAL OUTPUT INITIALIZATION ==========
        let mut serial =
            Serial::<pac::USART3>::new(device.USART3, uart_tx, uart_rx, 0x41, 0x0, 0x0);
        serial.lcr(
            WLS_A::_8_BIT_CHARACTER_LENGTH,
            SBS_A::_1_STOP_BIT,
            PE_A::DISABLE_PARITY_GENERERATION,
            PS_A::ODD_PARITY,
            BC_A::DISABLED,
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
DLAB_A::DISABLED, ); serial.ier(true, false, false, false, false); // Configure PLL1 for use with UART3 unsafe { // Select the IRC as BASE_M4_CLK source device.CGU.base_m4_clk.write(|w| w.clk_sel().bits(0x1)); // Enable the crystal oscillator device.CGU.xtal_osc_ctrl.modify(|_, w| w.hf().bit(false)); device .CGU .xtal_osc_ctrl .modify(|_, w| w.enable().bit(false)); // Wait 250us for i in 0..9_000 { core::ptr::read_volatile(&i); } device.CGU.pll1_ctrl.write(|w| { w.pd() .bit(false) .clk_sel() .bits(0x6) // Select the crystal oscillator as clock source .msel() .bits(20) .nsel() .bits(1) // Select the M and N divider values .psel() .bits(0) .fbsel() .bit(true) .bypass() .bit(false) .direct() .bit(false) }); // Wait for the PLL to lock while !device.CGU.pll1_stat.read().lock().bit() {} // Set PLL1 p-divider to divide by 2 (DIRECT=0; PSEL=0) device .CGU .pll1_ctrl .modify(|_, w| w.direct().bit(false).psel().bits(0x0)); // Select PLL1 as base_m4_clk source device.CGU.base_m4_clk.modify(|_, w| w.clk_sel().bits(0x09)); // Wait for 50us for i in 0..1800 { core::ptr::read_volatile(&i); } // Enable direct output mode device.CGU.pll1_ctrl.modify(|_, w| w.direct().bit(true)); // Enable clock on UART3 device.CGU.base_uart3_clk.write(|w| w.clk_sel().bits(0x09)); } // ========= CAN 0 INITIALIZATION ========== // NOTE We materialize a new SCU since we gave the safely accessed one away to the // HAL. This is undesirable, but further work to put pin ownership in peripherals is halted // for now. // // Safety: as long as we keep away from the pins we assigned through the HAL, we are as
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
// safe as before. In this case it is the UART pins (9_3 and 9_4) that we should stay away // from. let scu = unsafe { core::mem::transmute::<(), SCU>(()) }; let mut can_0 = CanBus::<pac::C_CAN0, U32>::new(device.C_CAN0); scu.sfspe_3 .write(|w| w.mode().function_1().epun().bit(true)); // CAN0_TD scu.sfspe_2 .write(|w| w.mode().function_1().epun().bit(true).ezi().bit(true)); // CAN0_RD can_0.initialize( 12_000_000, 500000, IE_A::ENABLE_CAN_INTERRUPTS, SIE_A::ENABLE_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); scu.sfspe_0 .write(|w| w.mode().function_5().epun().bit(true)); // CAN1_TD 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::ENABLE_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 { TX_OBJ: tx_obj, TIMER: timer, UART: serial, CAN_0: can_0, CAN_1: can_1, TX_STATE: tx_state, } } #[idle] fn idle() -> ! { loop {} } #[interrupt(resources = [UART, 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