Browse Source

Finish support for PCA9685

Kevin Lee 2 years ago
parent
commit
325def295b
2 changed files with 134 additions and 88 deletions
  1. 59 1
      Nixie_Firmware_Rust/src/main.rs
  2. 75 87
      Nixie_Firmware_Rust/src/pca9685.rs

+ 59 - 1
Nixie_Firmware_Rust/src/main.rs

@@ -28,8 +28,8 @@ use stm32l4xx_hal::{
 };
 
 mod ds3231;
-// mod pca9685;
 mod tusb322;
+mod pca9685;
 
 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));
@@ -49,6 +49,64 @@ static I2C: Mutex<
 
 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] {

+ 75 - 87
Nixie_Firmware_Rust/src/pca9685.rs

@@ -1,16 +1,13 @@
+use core::mem::size_of;
 use field_offset::offset_of;
-use stm32l4xx_hal::prelude::{
-    _embedded_hal_blocking_i2c_Write, _embedded_hal_blocking_i2c_WriteRead,
-};
+use stm32l4xx_hal::prelude::_embedded_hal_blocking_i2c_Write;
 use tock_registers::{
     interfaces::{ReadWriteable, Readable, Writeable},
     register_bitfields, register_structs,
     registers::InMemoryRegister,
 };
 
-const PCA9685_ADDR_1: u8 = 0x41;
-const PCA9685_ADDR_2: u8 = 0x42;
-const PCA9685_ADDR_3: u8 = 0x43;
+const MAX_BRIGHTNESS: u32 = 4096;
 
 register_bitfields![
     u8,
@@ -59,95 +56,86 @@ register_structs! {
     }
 }
 
-impl Pca9685Registers {
-    const fn default() -> Self {
-        const ZERO_LED: InMemoryRegister<u32, LED_CTRL::Register> = InMemoryRegister::new(0x00);
-        Self {
-            mode1: InMemoryRegister::new(0x00),
-            mode2: InMemoryRegister::new(0x00),
-            subaddress1: InMemoryRegister::new(0x00),
-            subaddress2: InMemoryRegister::new(0x00),
-            subaddress3: InMemoryRegister::new(0x00),
-            allcalladdr: InMemoryRegister::new(0x00),
-            led: [ZERO_LED; 16],
-            _reserved: [0; 180],
-            all_led: InMemoryRegister::new(0x00),
-            prescale: InMemoryRegister::new(0x00),
-            testmode: InMemoryRegister::new(0x00),
-        }
-    }
-}
+pub fn init(address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_Write) {
+    let mode1_reg: InMemoryRegister<u8, MODE_1::Register> = InMemoryRegister::new(0);
+    let mode2_reg: InMemoryRegister<u8, MODE_2::Register> = InMemoryRegister::new(0);
 
-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
-    ],
-];
+    // Turn on autoincrement
+    // Start disabled
+    // Enable response to all call address
+    mode1_reg.modify(MODE_1::AI::SET + MODE_1::SLEEP::SET + MODE_1::ALLCALL::SET);
 
-pub fn init(i2c: &mut impl _embedded_hal_blocking_i2c_Write, ) {
+    // Configure output for totem pole drive
+    mode2_reg.modify(MODE_2::OUTDRV::SET);
 
-}
+    let buffer: [u8; 3] = [
+        offset_of!(Pca9685Registers => mode1).get_byte_offset() as u8,
+        mode1_reg.get(),
+        mode2_reg.get(),
+    ];
 
-pub fn set_voltage(percent: f32) {
-    
-}
+    match i2c.write(address, &buffer) {
+        Ok(_) => (),
+        Err(_) => panic!(),
+    }
 
-pub fn set_digit(tube: u32, digit: u32, pwm_start: u32, pwm_end: u32) {
+    let prescale_reg: InMemoryRegister<u8> = InMemoryRegister::new(0);
 
-}
+    // Set PWM frequency to 1526Hz
+    prescale_reg.set(0x03);
+
+    let buffer: [u8; 2] = [
+        offset_of!(Pca9685Registers => prescale).get_byte_offset() as u8,
+        prescale_reg.get(),
+    ];
+
+    match i2c.write(address, &buffer) {
+        Ok(_) => (),
+        Err(_) => panic!(),
+    }
 
-pub fn set_dot(pwm_start: u32, pwm_end: u32) {
+    // Re-enable outputs
+    mode1_reg.modify(MODE_1::SLEEP::CLEAR);
 
+    let buffer: [u8; 2] = [
+        offset_of!(Pca9685Registers => mode1).get_byte_offset() as u8,
+        mode1_reg.get(),
+    ];
+
+    match i2c.write(address, &buffer) {
+        Ok(_) => (),
+        Err(_) => panic!(),
+    }
 }
 
-pub fn enable_output(enabled: bool) {
+pub fn set_digit(
+    address: u8,
+    i2c: &mut impl _embedded_hal_blocking_i2c_Write,
+    digit: usize,
+    pwm_start: u32,
+    pwm_end: u32,
+) {
+    let led_reg: InMemoryRegister<u32, LED_CTRL::Register> = InMemoryRegister::new(0);
+
+    led_reg.modify(LED_CTRL::On.val(pwm_start));
+    led_reg.modify(LED_CTRL::On.val(pwm_end));
+
+    if pwm_end == 0 {
+        led_reg.modify(LED_CTRL::Off_Full::SET)
+    } else if pwm_end >= MAX_BRIGHTNESS {
+        led_reg.modify(LED_CTRL::On_Full::SET)
+    }
 
-}
+    let buffer: [u8; 5] = [
+        (offset_of!(Pca9685Registers => led).get_byte_offset() + size_of::<u32>() * digit) as u8,
+        led_reg.get().to_le_bytes()[0],
+        led_reg.get().to_le_bytes()[1],
+        led_reg.get().to_le_bytes()[2],
+        led_reg.get().to_le_bytes()[3],
+    ];
+
+    match i2c.write(address, &buffer) {
+        Ok(_) => (),
+        Err(_) => panic!(),
+    }
+}