Browse Source

Prelim support for TUSB322

Kevin Lee 2 years ago
parent
commit
c0e6b63968
3 changed files with 199 additions and 30 deletions
  1. 1 0
      Nixie_Firmware_Rust/Cargo.toml
  2. 57 30
      Nixie_Firmware_Rust/src/main.rs
  3. 141 0
      Nixie_Firmware_Rust/src/tusb322.rs

+ 1 - 0
Nixie_Firmware_Rust/Cargo.toml

@@ -10,6 +10,7 @@ cortex-m = "0.6.0"
 cortex-m-rt = "0.6.10"
 cortex-m-semihosting = "0.3.3"
 # panic-halt = "0.2.0"
+tock-registers = "0.7.0"
 
 # Uncomment for the panic example.
 # panic-itm = "0.4.1"

+ 57 - 30
Nixie_Firmware_Rust/src/main.rs

@@ -2,33 +2,37 @@
 #![cfg_attr(not(test), no_std)]
 #![cfg_attr(not(test), no_main)]
 
-// pick a panicking behavior
+// custom panic handler
 #[cfg(not(test))]
-use core::panic::PanicInfo; // custom panic handler
+use core::panic::PanicInfo;
 
-// use cortex_m::asm;
 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 stm32l4::stm32l4x2::interrupt;
+// use cortex_m_semihosting::hprintln;
 use stm32l4xx_hal::{
     delay::Delay,
     gpio::State,
     gpio::{Edge, Input, Output, PullUp, PushPull, PA3, PC15},
+    i2c::I2c,
     interrupt, pac,
     prelude::*,
     rcc,
     stm32::Interrupt,
 };
 
+mod tusb322;
+
 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));
 
 #[cfg(not(test))]
 #[entry]
 fn main() -> ! {
-    hprintln!("Hello, world!").unwrap();
+    // 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();
@@ -46,8 +50,8 @@ fn main() -> ! {
         .pll_source(rcc::PllSource::HSI16)
         .sysclk(80.mhz())
         .hclk(80.mhz())
-        .pclk1(80.mhz())
-        .pclk2(80.mhz())
+        .pclk1(40.mhz())
+        .pclk2(40.mhz())
         .freeze(&mut flash.acr, &mut pwr);
 
     // Split GPIO peripheral into independent pins and registers
@@ -75,15 +79,20 @@ fn main() -> ! {
     fault_int.enable_interrupt(&mut dp.EXTI);
     fault_int.trigger_on_edge(&mut dp.EXTI, Edge::FALLING);
 
-    // Configure NVIC mask to enable interrupt source
-    unsafe {
-        NVIC::unmask(Interrupt::EXTI3);
-    }
+    // 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));
-    });
+        // 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 =
@@ -91,6 +100,23 @@ fn main() -> ! {
             .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(&mut i2c);
+
     // Configure abstract timer that operates off systick timer
     let mut timer = Delay::new(cp.SYST, clocks);
 
@@ -102,11 +128,11 @@ fn main() -> ! {
     }
 }
 
-fn set_fault_led(on: State) {
+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 on {
+            match state {
                 State::High => led.set_high().unwrap(),
                 State::Low => led.set_low().unwrap(),
             };
@@ -120,7 +146,7 @@ fn EXTI3() {
         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();
+                // hprintln!("Fault pin interrupt triggered!").unwrap();
                 // nfault.clear_interrupt_pending_bit();
                 panic!();
             }
@@ -131,17 +157,18 @@ fn EXTI3() {
 #[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();
-    }
+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;
     }

+ 141 - 0
Nixie_Firmware_Rust/src/tusb322.rs

@@ -0,0 +1,141 @@
+use stm32l4xx_hal::{prelude::_embedded_hal_blocking_i2c_Write};
+use tock_registers::{
+    interfaces::ReadWriteable, register_bitfields, register_structs, registers::InMemoryRegister,
+};
+
+register_bitfields![
+    u8,
+    // Connection status register
+    ConnStatus1 [
+        // Indicates that active cable has been plugged in
+        ACTIVE_CABLE_DETECTION OFFSET(0) NUMBITS(1) [],
+        // Read by the application to determine if accessory was attached
+        ACCESSORY_CONNECTED OFFSET(1) NUMBITS(3) [
+            None = 0,
+            Audio = 4,
+            AudioCharged = 5,
+            DebugDfp = 6,
+            DebugUfp = 7,
+        ],
+        // Set in UFP mode with the detected current mode
+        CURRENT_MODE_DETECT OFFSET(4) NUMBITS(2) [
+            Default = 0,
+            Medium = 1,
+            ChargeThrough = 2,
+            High = 3,
+        ],
+        // Programmed by application to change current advertisement
+        CURRENT_MODE_ADVERTISE OFFSET(6) NUMBITS(2) [
+            Default = 0,
+            Mid = 1,
+            High = 2,
+            Reserved = 3,
+        ],
+    ],
+    // Connection status and control register
+    ConnStatus2 [
+        // Setting this field will disable UFP accessory support
+        DISABLE_UFP_ACCESSORY OFFSET(0) NUMBITS(1) [],
+        // Percentage of time that a DRP advertised DFP during tDRP
+        DRP_DUTY_CYCLE OFFSET(1) NUMBITS(2) [
+            p30 = 0,
+            p40 = 1,
+            p50 = 2,
+            p60 = 3,
+        ],
+        // Set when over-current limit is triggered
+        VCONN_FAULT OFFSET(3) NUMBITS(1) [],
+        // Pulled low when a control or status register changes
+        INTERRUPT_STATUS OFFSET(4) NUMBITS(1) [
+            Clear = 0,
+            Changed = 1,
+        ],
+        // Cable orientation
+        CABLE_DIR OFFSET(5) NUMBITS(1) [
+            CC1 = 0,
+            CC2 = 1,
+        ],
+        // Attached state (same as ID pin)
+        ATTACHED_STATE OFFSET(6) NUMBITS(2) [
+            NotAttached = 0,
+            AttachedSrc_DFP = 1,
+            AttachedSnk_UFP = 2,
+            AttachedAccessory = 3,
+        ],
+    ],
+    // General control register
+    Control [
+        // Disable CC pin termination
+        DISABLE_TERM OFFSET(0) NUMBITS(1) [],
+        // Control behavior when configured as DRP
+        SOURCE_PERF OFFSET(1) NUMBITS(2) [
+            StandardDrp = 0,
+            DrpTrySnk = 1,
+            Reserved = 2,
+            DrpTrySrc = 3,
+        ],
+        // Soft reset internal logic (self-clearing)
+        I2C_SOFT_RESET OFFSET(3) NUMBITS(1) [],
+        // Configure device operation mode
+        MODE_SELECT OFFSET(4) NUMBITS(2) [
+            Drp = 0,
+            Ufp = 1,
+            Dfp = 2,
+        ],
+        // Debounce time on CC pins
+        DEBOUNCE OFFSET(6) NUMBITS(2) [
+            ms168 = 0,
+            ms118 = 1,
+            ms134 = 2,
+            ms152 = 3,
+        ],
+    ],
+];
+
+register_structs! {
+    Tusb322Registers {
+        (0x00 => id:    [u8; 8]),
+        (0x09 => stat1: InMemoryRegister<u8, ConnStatus1::Register>),
+        (0x0A => stat2: InMemoryRegister<u8, ConnStatus2::Register>),
+        (0x0B => ctrl:  InMemoryRegister<u8, Control::Register>),
+        (0x0C => @END),
+    }
+}
+
+impl Default for Tusb322Registers {
+    fn default() -> Self {
+        Self {
+            id: [0; 8],
+            stat1: InMemoryRegister::new(0),
+            stat2: InMemoryRegister::new(0),
+            ctrl: InMemoryRegister::new(0),
+        }
+    }
+}
+
+pub fn init(i2c: &mut impl _embedded_hal_blocking_i2c_Write) {
+    let reg: Tusb322Registers = Tusb322Registers::default();
+
+    // Disable UFP accessory support (otherwise IC stays in DRP mode)
+    reg.stat2.modify(ConnStatus2::DISABLE_UFP_ACCESSORY::SET);
+
+    // Disable CC termination to change to UFP mode
+    reg.ctrl.modify(Control::DISABLE_TERM::SET);
+
+    // For operation in UFP mode
+    reg.ctrl.modify(Control::MODE_SELECT::Ufp);
+
+    const TUSB322_ADDR: u8 = 0x47;
+
+    // For some reason i2c.write().unwrap() doesn't work here as it complains
+    // about an unsatisfied trait bound where the returned error value
+    // (_embedded_hal_blocking_i2c_Write::Error) doesnt implement trait Debug.
+    // Calling .unwrap() does work though if it's the caller that is doing so.
+
+    match i2c.write(TUSB322_ADDR, &[0x00]) {
+        Ok(_) => (),
+        Err(_) => panic!()
+    }
+
+}
+