#![cfg_attr(test, allow(unused_imports))] #![cfg_attr(not(test), no_std)] #![cfg_attr(not(test), no_main)] // #![feature(generic_const_exprs)] #![feature(half_open_range_patterns)] #![feature(exclusive_range_pattern)] #![allow(dead_code)] // custom panic handler #[cfg(not(test))] use core::panic::PanicInfo; use core::{cell::RefCell, ops::DerefMut}; // use cortex_m::asm; use cortex_m::{interrupt::free, interrupt::Mutex, peripheral::NVIC}; use cortex_m_rt::entry; // use cortex_m_semihosting::hprintln; use stm32l4xx_hal::{ delay::Delay, device::I2C1, gpio::{Alternate, Edge, Input, OpenDrain, Output, PullUp, PushPull, AF4, PA3, PC15}, gpio::{State, PA10, PA9}, i2c::I2c, interrupt, pac, prelude::*, rcc, stm32::Interrupt, }; mod ds3231; // mod pca9685; mod tusb322; static FAULT_INT: Mutex>>>> = Mutex::new(RefCell::new(None)); static FAULT_LED: Mutex>>>> = Mutex::new(RefCell::new(None)); static I2C: Mutex< RefCell< Option< I2c< I2C1, ( PA9>>, PA10>>, ), >, >, >, > = Mutex::new(RefCell::new(None)); const DS3231_ADDR: u8 = 0x68; const TUSB322_ADDR: u8 = 0x47; // NewType wrapper for the // unsafe fn any_as_u8_slice(p: &T) -> &[u8] { // core::slice::from_raw_parts( // (p as *const T) as *const u8, // core::mem::size_of::(), // ) // } // pub fn concat(a: &[T; A], b: &[T; B]) -> [T; A+B] { // let mut whole: [T; A+B] = [Default::default(); A+B]; // let (one, two) = whole.split_at_mut(A); // one.copy_from_slice(a); // two.copy_from_slice(b); // whole // } #[cfg(not(test))] #[entry] fn main() -> ! { // Semihosting only works if debugger is connected. // See https://github.com/rust-embedded/cortex-m/issues/289 // hprintln!("Hello, world!").unwrap(); // Acquire a singleton instance for the chip's peripherals let mut dp = pac::Peripherals::take().unwrap(); let cp = pac::CorePeripherals::take().unwrap(); // Consume the raw peripheral and return a new object that implements a higher level API let mut flash = dp.FLASH.constrain(); let mut rcc = dp.RCC.constrain(); let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1); // Configure clocks to run at maximum frequency off internal oscillator let clocks = rcc .cfgr .pll_source(rcc::PllSource::HSI16) .sysclk(80.mhz()) .hclk(80.mhz()) .pclk1(80.mhz()) .pclk2(80.mhz()) .freeze(&mut flash.acr, &mut pwr); // Split GPIO peripheral into independent pins and registers // let mut gpiob = dp.GPIOB.split(&mut rcc.ahb2); let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2); let mut gpioc = dp.GPIOC.split(&mut rcc.ahb2); // Configure fault LED output on PC15 let fault_led = gpioc.pc15.into_push_pull_output_with_state( &mut gpioc.moder, &mut gpioc.otyper, State::Low, ); // Store fault LED in global static variable as it is accessed in interrupts free(|cs| { FAULT_LED.borrow(cs).replace(Some(fault_led)); }); // Configure fault input interrupt on PA3 let mut fault_int = gpioa .pa3 .into_pull_up_input(&mut gpioa.moder, &mut gpioa.pupdr); fault_int.make_interrupt_source(&mut dp.SYSCFG, &mut rcc.apb2); fault_int.enable_interrupt(&mut dp.EXTI); fault_int.trigger_on_edge(&mut dp.EXTI, Edge::FALLING); // Sanity check that fault pin isn't already set (active low) before enabling interrupt if fault_int.is_high().unwrap() { // Configure NVIC mask to enable interrupt source unsafe { NVIC::unmask(Interrupt::EXTI3); } // Store fault input in global static variable as it is accessed in interrupt free(|cs| { FAULT_INT.borrow(cs).replace(Some(fault_int)); }); } else { panic!(); } // Start with HV PSU disabled (enable pin on PA2) let mut _hv_en = gpioa .pa2 .into_push_pull_output_with_state(&mut gpioa.moder, &mut gpioa.otyper, State::Low); // Configure I2C SCL let scl = gpioa .pa9 .into_open_drain_output(&mut gpioa.moder, &mut gpioa.otyper); let scl = scl.into_af4(&mut gpioa.moder, &mut gpioa.afrh); // Configure I2C SDA let sda = gpioa .pa10 .into_open_drain_output(&mut gpioa.moder, &mut gpioa.otyper); let sda = sda.into_af4(&mut gpioa.moder, &mut gpioa.afrh); // Initialize I2C let mut i2c = I2c::i2c1(dp.I2C1, (scl, sda), 100.khz(), clocks, &mut rcc.apb1r1); tusb322::init(TUSB322_ADDR, &mut i2c); ds3231::init(DS3231_ADDR, &mut i2c); free(|cs| { I2C.borrow(cs).replace(Some(i2c)); }); // Configure abstract timer that operates off systick timer let mut timer = Delay::new(cp.SYST, clocks); loop { timer.delay_ms(1000_u32); set_fault_led(State::High); timer.delay_ms(1000_u32); set_fault_led(State::Low); } } fn set_fault_led(state: State) { free(|cs| { let mut led_ref = FAULT_LED.borrow(cs).borrow_mut(); if let Some(ref mut led) = led_ref.deref_mut() { match state { State::High => led.set_high().unwrap(), State::Low => led.set_low().unwrap(), }; } }); } #[interrupt] fn EXTI3() { free(|cs| { let mut nfault_ref = FAULT_INT.borrow(cs).borrow_mut(); if let Some(ref mut nfault) = nfault_ref.deref_mut() { if nfault.check_interrupt() { // hprintln!("Fault pin interrupt triggered!").unwrap(); // nfault.clear_interrupt_pending_bit(); panic!(); } } }); } #[panic_handler] #[cfg(not(test))] /// Custom panic handler fn panic(_info: &PanicInfo) -> ! { // if let Some(location) = info.location() { // hprintln!( // "Panic in file '{}' at line {}", // location.file(), // location.line() // ) // .unwrap(); // } else { // hprintln!("Panic'd!").unwrap(); // } set_fault_led(State::High); loop { continue; } }