|
@@ -1,7 +1,6 @@
|
|
|
#![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)]
|
|
@@ -11,14 +10,15 @@
|
|
|
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::{asm, 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::{
|
|
|
+ Alternate, Edge, Floating, Input, OpenDrain, Output, PullUp, PushPull, AF4, PA3, PB5, PC15,
|
|
|
+ },
|
|
|
gpio::{State, PA10, PA9},
|
|
|
i2c::I2c,
|
|
|
interrupt, pac,
|
|
@@ -28,9 +28,13 @@ use stm32l4xx_hal::{
|
|
|
};
|
|
|
|
|
|
mod ds3231;
|
|
|
-mod tusb322;
|
|
|
+mod nixie;
|
|
|
mod pca9685;
|
|
|
+mod tusb322;
|
|
|
+
|
|
|
+use nixie::*;
|
|
|
|
|
|
+static RTC_INT: Mutex<RefCell<Option<PB5<Input<Floating>>>>> = Mutex::new(RefCell::new(None));
|
|
|
static FAULT_INT: Mutex<RefCell<Option<PA3<Input<PullUp>>>>> = Mutex::new(RefCell::new(None));
|
|
|
static FAULT_LED: Mutex<RefCell<Option<PC15<Output<PushPull>>>>> = Mutex::new(RefCell::new(None));
|
|
|
static I2C: Mutex<
|
|
@@ -47,68 +51,6 @@ static I2C: Mutex<
|
|
|
>,
|
|
|
> = Mutex::new(RefCell::new(None));
|
|
|
|
|
|
-const DS3231_ADDR: u8 = 0x68;
|
|
|
-const TUSB322_ADDR: u8 = 0x47;
|
|
|
-const PCA9685_ADDR_1: u8 = 0x41;
|
|
|
-const PCA9685_ADDR_2: u8 = 0x42;
|
|
|
-const PCA9685_ADDR_3: u8 = 0x43;
|
|
|
-
|
|
|
-
|
|
|
-const MAP_ADDR: usize = 0;
|
|
|
-const MAP_PIN: usize = 1;
|
|
|
-
|
|
|
-static PCA9685_MAPPING: [[[u8; 2]; 10]; 4] = [
|
|
|
- [
|
|
|
- [PCA9685_ADDR_1, 8], // Tube 0 Digit 0
|
|
|
- [PCA9685_ADDR_1, 9], // Tube 0 Digit 1
|
|
|
- [PCA9685_ADDR_1, 10], // Tube 0 Digit 2
|
|
|
- [PCA9685_ADDR_1, 12], // Tube 0 Digit 3
|
|
|
- [PCA9685_ADDR_1, 15], // Tube 0 Digit 4
|
|
|
- [PCA9685_ADDR_1, 14], // Tube 0 Digit 5
|
|
|
- [PCA9685_ADDR_1, 11], // Tube 0 Digit 6
|
|
|
- [PCA9685_ADDR_1, 0], // Tube 0 Digit 7
|
|
|
- [PCA9685_ADDR_1, 1], // Tube 0 Digit 8
|
|
|
- [PCA9685_ADDR_1, 13], // Tube 0 Digit 9
|
|
|
- ],
|
|
|
- [
|
|
|
- [PCA9685_ADDR_1, 5], // Tube 1 Digit 0
|
|
|
- [PCA9685_ADDR_1, 6], // Tube 1 Digit 1
|
|
|
- [PCA9685_ADDR_1, 7], // Tube 1 Digit 2
|
|
|
- [PCA9685_ADDR_1, 2], // Tube 1 Digit 3
|
|
|
- [PCA9685_ADDR_2, 4], // Tube 1 Digit 4
|
|
|
- [PCA9685_ADDR_2, 1], // Tube 1 Digit 5
|
|
|
- [PCA9685_ADDR_1, 4], // Tube 1 Digit 6
|
|
|
- [PCA9685_ADDR_2, 2], // Tube 1 Digit 7
|
|
|
- [PCA9685_ADDR_2, 3], // Tube 1 Digit 8
|
|
|
- [PCA9685_ADDR_1, 3], // Tube 1 Digit 9
|
|
|
- ],
|
|
|
- [
|
|
|
- [PCA9685_ADDR_3, 8], // Tube 2 Digit 0
|
|
|
- [PCA9685_ADDR_3, 9], // Tube 2 Digit 1
|
|
|
- [PCA9685_ADDR_3, 10], // Tube 2 Digit 2
|
|
|
- [PCA9685_ADDR_3, 12], // Tube 2 Digit 3
|
|
|
- [PCA9685_ADDR_2, 12], // Tube 2 Digit 4
|
|
|
- [PCA9685_ADDR_2, 13], // Tube 2 Digit 5
|
|
|
- [PCA9685_ADDR_3, 11], // Tube 2 Digit 6
|
|
|
- [PCA9685_ADDR_2, 14], // Tube 2 Digit 7
|
|
|
- [PCA9685_ADDR_2, 11], // Tube 2 Digit 8
|
|
|
- [PCA9685_ADDR_3, 13], // Tube 2 Digit 9
|
|
|
- ],
|
|
|
- [
|
|
|
- [PCA9685_ADDR_3, 5], // Tube 3 Digit 0
|
|
|
- [PCA9685_ADDR_3, 6], // Tube 3 Digit 1
|
|
|
- [PCA9685_ADDR_3, 7], // Tube 3 Digit 2
|
|
|
- [PCA9685_ADDR_3, 2], // Tube 3 Digit 3
|
|
|
- [PCA9685_ADDR_3, 14], // Tube 3 Digit 4
|
|
|
- [PCA9685_ADDR_3, 15], // Tube 3 Digit 5
|
|
|
- [PCA9685_ADDR_3, 4], // Tube 3 Digit 6
|
|
|
- [PCA9685_ADDR_3, 1], // Tube 3 Digit 7
|
|
|
- [PCA9685_ADDR_3, 0], // Tube 3 Digit 8
|
|
|
- [PCA9685_ADDR_3, 3], // Tube 3 Digit 9
|
|
|
- ],
|
|
|
-];
|
|
|
-
|
|
|
-// NewType wrapper for the
|
|
|
// unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
|
|
|
// core::slice::from_raw_parts(
|
|
|
// (p as *const T) as *const u8,
|
|
@@ -144,17 +86,26 @@ fn main() -> ! {
|
|
|
let clocks = rcc
|
|
|
.cfgr
|
|
|
.pll_source(rcc::PllSource::HSI16)
|
|
|
- .sysclk(80.mhz())
|
|
|
- .hclk(80.mhz())
|
|
|
- .pclk1(80.mhz())
|
|
|
- .pclk2(80.mhz())
|
|
|
+ .sysclk(64.mhz())
|
|
|
+ .hclk(64.mhz())
|
|
|
+ .pclk1(64.mhz())
|
|
|
+ .pclk2(64.mhz())
|
|
|
.freeze(&mut flash.acr, &mut pwr);
|
|
|
|
|
|
+ // Configure abstract timer that operates off systick timer
|
|
|
+ let mut timer = Delay::new(cp.SYST, clocks);
|
|
|
+
|
|
|
// 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 gpiob = dp.GPIOB.split(&mut rcc.ahb2);
|
|
|
let mut gpioc = dp.GPIOC.split(&mut rcc.ahb2);
|
|
|
|
|
|
+ // Configure high voltage PSU enable pin on PA2
|
|
|
+ let mut hv_enable =
|
|
|
+ gpioa
|
|
|
+ .pa2
|
|
|
+ .into_push_pull_output_with_state(&mut gpioa.moder, &mut gpioa.otyper, State::Low);
|
|
|
+
|
|
|
// Configure fault LED output on PC15
|
|
|
let fault_led = gpioc.pc15.into_push_pull_output_with_state(
|
|
|
&mut gpioc.moder,
|
|
@@ -162,7 +113,7 @@ fn main() -> ! {
|
|
|
State::Low,
|
|
|
);
|
|
|
|
|
|
- // Store fault LED in global static variable as it is accessed in interrupts
|
|
|
+ // Store fault LED in static singleton so that interrupt has access to it
|
|
|
free(|cs| {
|
|
|
FAULT_LED.borrow(cs).replace(Some(fault_led));
|
|
|
});
|
|
@@ -182,7 +133,7 @@ fn main() -> ! {
|
|
|
NVIC::unmask(Interrupt::EXTI3);
|
|
|
}
|
|
|
|
|
|
- // Store fault input in global static variable as it is accessed in interrupt
|
|
|
+ // Store fault interrupt in static singleton so that interrupt has access to it
|
|
|
free(|cs| {
|
|
|
FAULT_INT.borrow(cs).replace(Some(fault_int));
|
|
|
});
|
|
@@ -190,12 +141,6 @@ fn main() -> ! {
|
|
|
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
|
|
@@ -208,26 +153,79 @@ fn main() -> ! {
|
|
|
.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);
|
|
|
+ // Initialize I2C (configured for 1Mhz, but actually runs at 600kHz)
|
|
|
+ let mut i2c = I2c::i2c1(dp.I2C1, (scl, sda), 1.mhz(), clocks, &mut rcc.apb1r1);
|
|
|
|
|
|
+ // Initialize TUSB322 (USB Type-C configuration chip)
|
|
|
tusb322::init(TUSB322_ADDR, &mut i2c);
|
|
|
|
|
|
+ // Initialize DS3231 (RTC)
|
|
|
ds3231::init(DS3231_ADDR, &mut i2c);
|
|
|
|
|
|
+ // Configure input interrupt pin from DS3231 on PB5
|
|
|
+ // Interrupt is pulled high, with open drain on DS3231 to pull low
|
|
|
+ let mut rtc_int = gpiob
|
|
|
+ .pb5
|
|
|
+ .into_floating_input(&mut gpiob.moder, &mut gpiob.pupdr);
|
|
|
+ rtc_int.make_interrupt_source(&mut dp.SYSCFG, &mut rcc.apb2);
|
|
|
+ rtc_int.enable_interrupt(&mut dp.EXTI);
|
|
|
+ rtc_int.trigger_on_edge(&mut dp.EXTI, Edge::FALLING);
|
|
|
+
|
|
|
+ // Configure NVIC mask to enable interrupt source
|
|
|
+ unsafe {
|
|
|
+ NVIC::unmask(Interrupt::EXTI9_5);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Store RTC interrupt in static singleton so that interrupt has access to it
|
|
|
+ free(|cs| {
|
|
|
+ RTC_INT.borrow(cs).replace(Some(rtc_int));
|
|
|
+ });
|
|
|
+
|
|
|
+ // Configure DAC AMP enable pin for AD8591 on PB1
|
|
|
+ let mut _dac_enable = gpiob.pb1.into_push_pull_output_with_state(
|
|
|
+ &mut gpiob.moder,
|
|
|
+ &mut gpiob.otyper,
|
|
|
+ State::High,
|
|
|
+ );
|
|
|
+
|
|
|
+ // Configure DAC VIN for AD8591 on PA5
|
|
|
+ // Note that this pin should actually be configured as analog output (for DAC)
|
|
|
+ // but stm32l4xx_hal doesn't have support for the DAC as of now. We also currently
|
|
|
+ // set the output to only the highest possible voltage, so the same functionality
|
|
|
+ // can be achieved by configuring the pin as a digital output set to high.
|
|
|
+ let mut _dac_output = gpioa.pa5.into_push_pull_output_with_state(
|
|
|
+ &mut gpioa.moder,
|
|
|
+ &mut gpioa.otyper,
|
|
|
+ State::High,
|
|
|
+ );
|
|
|
+
|
|
|
+ // Configure PWM enable pin (active low) for PCA9685 on PA7
|
|
|
+ let mut pwm_enable = gpioa.pa7.into_push_pull_output_with_state(
|
|
|
+ &mut gpioa.moder,
|
|
|
+ &mut gpioa.otyper,
|
|
|
+ State::High,
|
|
|
+ );
|
|
|
+
|
|
|
+ // Small delay to ensure that PCA9685 is fully powered on before writing to it
|
|
|
+ timer.delay_us(10_u32);
|
|
|
+
|
|
|
+ // Initialize PCA9685 (PWM driver)
|
|
|
+ pca9685::init(PCA9685_ALL_CALL, &mut i2c);
|
|
|
+
|
|
|
+ // Enable PWM output after PCA9685 has been initialized
|
|
|
+ pwm_enable.set_low().unwrap();
|
|
|
+
|
|
|
+ pca9685::set_digit(PCA9685_ADDR_1, &mut i2c, 0, 0, 4096);
|
|
|
+
|
|
|
+ // Store I2C peripheral in global static variable as it is used in interrupt
|
|
|
free(|cs| {
|
|
|
I2C.borrow(cs).replace(Some(i2c));
|
|
|
});
|
|
|
|
|
|
- // Configure abstract timer that operates off systick timer
|
|
|
- let mut timer = Delay::new(cp.SYST, clocks);
|
|
|
+ // Enable the high voltage power supply last
|
|
|
+ hv_enable.set_high().unwrap();
|
|
|
|
|
|
- loop {
|
|
|
- timer.delay_ms(1000_u32);
|
|
|
- set_fault_led(State::High);
|
|
|
- timer.delay_ms(1000_u32);
|
|
|
- set_fault_led(State::Low);
|
|
|
- }
|
|
|
+ loop {}
|
|
|
}
|
|
|
|
|
|
fn set_fault_led(state: State) {
|
|
@@ -242,6 +240,21 @@ fn set_fault_led(state: State) {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+#[interrupt]
|
|
|
+fn EXTI9_5() {
|
|
|
+ free(|cs| {
|
|
|
+ let mut rtc_int_ref = RTC_INT.borrow(cs).borrow_mut();
|
|
|
+ if let Some(ref mut rtc_int) = rtc_int_ref.deref_mut() {
|
|
|
+ if rtc_int.check_interrupt() {
|
|
|
+ rtc_int.clear_interrupt_pending_bit();
|
|
|
+ set_fault_led(State::High);
|
|
|
+ asm::delay(8_000_000);
|
|
|
+ set_fault_led(State::Low);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
#[interrupt]
|
|
|
fn EXTI3() {
|
|
|
free(|cs| {
|