Browse Source

Add support for access to DS3231

Kevin Lee 2 years ago
parent
commit
a6e956eca4
3 changed files with 203 additions and 25 deletions
  1. 199 23
      Nixie_Firmware_Rust/src/ds3231.rs
  2. 4 2
      Nixie_Firmware_Rust/src/main.rs
  3. 0 0
      Nixie_Firmware_Rust/src/pca9685.rs

+ 199 - 23
Nixie_Firmware_Rust/src/ds3231.rs

@@ -1,7 +1,9 @@
 use field_offset::offset_of;
-use stm32l4xx_hal::prelude::{_embedded_hal_blocking_i2c_Read, _embedded_hal_blocking_i2c_Write};
+use stm32l4xx_hal::prelude::{
+    _embedded_hal_blocking_i2c_Write, _embedded_hal_blocking_i2c_WriteRead,
+};
 use tock_registers::{
-    interfaces::{ReadWriteable, Readable},
+    interfaces::{ReadWriteable, Readable, Writeable},
     register_bitfields, register_structs,
     registers::InMemoryRegister,
 };
@@ -18,10 +20,10 @@ register_bitfields![
         Value OFFSET(0) NUMBITS(6) [],
         n24 OFFSET(6) NUMBITS(1) [],
     ],
-    T_DAY [
+    T_WEEKDAY [
         Value OFFSET(0) NUMBITS(3) [],
     ],
-    T_DATE [
+    T_DAY [
         Value OFFSET(0) NUMBITS(6) [],
     ],
     T_MONTH [
@@ -84,8 +86,8 @@ register_structs! {
         (0x00 => second: InMemoryRegister<u8, T_SECOND::Register>),
         (0x01 => minute: InMemoryRegister<u8, T_MINUTE::Register>),
         (0x02 => hour: InMemoryRegister<u8, T_HOUR::Register>),
-        (0x03 => weekday: InMemoryRegister<u8, T_DAY::Register>),
-        (0x04 => day: InMemoryRegister<u8, T_DATE::Register>),
+        (0x03 => weekday: InMemoryRegister<u8, T_WEEKDAY::Register>),
+        (0x04 => day: InMemoryRegister<u8, T_DAY::Register>),
         (0x05 => month: InMemoryRegister<u8, T_MONTH::Register>),
         (0x06 => year: InMemoryRegister<u8, T_YEAR::Register>),
         (0x07 => a1_second: InMemoryRegister<u8, A_SECOND::Register>),
@@ -114,33 +116,207 @@ pub enum Weekday {
     Saturday = 6,
 }
 
+impl From<u8> for Weekday {
+    fn from(value: u8) -> Self {
+        match value {
+            0 => Weekday::Sunday,
+            1 => Weekday::Monday,
+            2 => Weekday::Tuesday,
+            3 => Weekday::Wednesday,
+            4 => Weekday::Thursday,
+            5 => Weekday::Friday,
+            6 => Weekday::Saturday,
+            _ => panic!(),
+        }
+    }
+}
+
 impl Ds3231Registers {
-    fn i2c_read_regs(&mut self, i2c: &mut impl _embedded_hal_blocking_i2c_Read) {}
-    fn set_time(second: &u32, minute: &u32, hour: &u32) {}
-    fn set_date(weekday: &Weekday, day: &u32, month: &u32, year: &u32, century: &u32) {}
-    fn get_time(second: &mut u32, minute: &mut u32, hour: &mut u32) {}
-    fn get_date(
-        weekday: &mut Weekday,
-        day: &mut u32,
-        month: &mut u32,
-        year: &mut u32,
-        century: &mut u32,
-    ) {
+    const fn default() -> Self {
+        Self {
+            second: InMemoryRegister::new(0x00),
+            minute: InMemoryRegister::new(0x00),
+            hour: InMemoryRegister::new(0x00),
+            weekday: InMemoryRegister::new(0x00),
+            day: InMemoryRegister::new(0x00),
+            month: InMemoryRegister::new(0x00),
+            year: InMemoryRegister::new(0x00),
+            a1_second: InMemoryRegister::new(0x00),
+            a1_minute: InMemoryRegister::new(0x00),
+            a1_hour: InMemoryRegister::new(0x00),
+            a1_day_date: InMemoryRegister::new(0x00),
+            a2_minute: InMemoryRegister::new(0x00),
+            a2_hour: InMemoryRegister::new(0x00),
+            a2_day_date: InMemoryRegister::new(0x00),
+            control_1: InMemoryRegister::new(0x00),
+            control_2: InMemoryRegister::new(0x00),
+            aging_offset: InMemoryRegister::new(0x00),
+            temp_msb: InMemoryRegister::new(0x00),
+            temp_lsb: InMemoryRegister::new(0x00),
+        }
+    }
+    fn i2c_write_ctrl(&self, address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_Write) {
+        let mut buffer: [u8; 3] = [0; 3];
+        buffer[0] = offset_of!(Ds3231Registers => control_1).get_byte_offset() as u8;
+        buffer[1] = self.control_1.get();
+        buffer[2] = self.control_2.get();
+
+        match i2c.write(address, &buffer) {
+            Ok(_) => (),
+            Err(_) => panic!(),
+        }
+    }
+    fn i2c_write_time(&self, address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_Write) {
+        let mut buffer: [u8; 4] = [0; 4];
+        buffer[0] = offset_of!(Ds3231Registers => second).get_byte_offset() as u8;
+        buffer[1] = self.second.get();
+        buffer[2] = self.minute.get();
+        buffer[3] = self.hour.get();
+
+        match i2c.write(address, &buffer) {
+            Ok(_) => (),
+            Err(_) => panic!(),
+        }
+    }
+    fn i2c_write_date(&self, address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_Write) {
+        let mut buffer: [u8; 5] = [0; 5];
+        buffer[0] = offset_of!(Ds3231Registers => weekday).get_byte_offset() as u8;
+        buffer[1] = self.weekday.get();
+        buffer[2] = self.day.get();
+        buffer[3] = self.month.get();
+        buffer[4] = self.year.get();
+
+        match i2c.write(address, &buffer) {
+            Ok(_) => (),
+            Err(_) => panic!(),
+        }
+    }
+    // Returns the second, minute, and hour from the RTC
+    fn i2c_read_time(&mut self, address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_WriteRead) {
+        let mut buffer: [u8; 3] = [0; 3];
+
+        match i2c.write_read(
+            address,
+            &[offset_of!(Ds3231Registers => second).get_byte_offset() as u8],
+            &mut buffer,
+        ) {
+            Ok(_) => (),
+            Err(_) => panic!(),
+        }
+    }
+    // Returns the weekday, day, month, year, and century from the RTC
+    fn i2c_read_date(&mut self, address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_WriteRead) {
+        let mut buffer: [u8; 4] = [0; 4];
+
+        match i2c.write_read(
+            address,
+            &[offset_of!(Ds3231Registers => weekday).get_byte_offset() as u8],
+            &mut buffer,
+        ) {
+            Ok(_) => (),
+            Err(_) => panic!(),
+        }
     }
 }
 
-fn init(address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_Write) {
+pub fn init(address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_Write) {
+    let regs = Ds3231Registers::default();
+
+    regs.control_1.modify(
+        CONTROL_1::nEOSC::CLEAR // Enable internal oscillator on VBAT
+            + CONTROL_1::BBSQW::CLEAR // Disable outputs on VBAT
+            + CONTROL_1::RS1::CLEAR   // Set square wave output to 1Hz
+            + CONTROL_1::RS2::CLEAR   // Set square wave output to 1Hz
+            + CONTROL_1::INTCN::CLEAR // Enable square wave output
+            + CONTROL_1::A1IE::CLEAR  // Disable alarm 1
+            + CONTROL_1::A2IE::CLEAR, // Disable alarm 2
+    );
 
+    // Disable 32kHz output
+    regs.control_2.modify(CONTROL_2::EN32KHZ::CLEAR);
+
+    regs.i2c_write_ctrl(address, i2c);
 }
 
-#[inline]
-fn bcd_to_decimal(value: u8) -> u8 {
-    ((value >> 4) * 10) + (value & 0xF)
+pub fn set_time(
+    address: u8,
+    i2c: &mut impl _embedded_hal_blocking_i2c_Write,
+    second: u32,
+    minute: u32,
+    hour: u32,
+) {
+    let regs = Ds3231Registers::default();
+
+    regs.second
+        .write(T_SECOND::Value.val(decimal_to_bcd(second)));
+    regs.minute
+        .write(T_MINUTE::Value.val(decimal_to_bcd(minute)));
+    regs.hour.write(T_HOUR::Value.val(decimal_to_bcd(hour)));
+
+    regs.i2c_write_time(address, i2c);
+}
+
+pub fn set_date(
+    address: u8,
+    i2c: &mut impl _embedded_hal_blocking_i2c_Write,
+    weekday: Weekday,
+    day: u32,
+    month: u32,
+    year: u32,
+    century: u32,
+) {
+    let regs = Ds3231Registers::default();
+
+    regs.weekday
+        .write(T_WEEKDAY::Value.val(decimal_to_bcd(weekday as u32)));
+    regs.day.write(T_DAY::Value.val(decimal_to_bcd(day)));
+    regs.month.modify(
+        T_MONTH::Value.val(decimal_to_bcd(month)) + T_MONTH::Century.val(decimal_to_bcd(century)),
+    );
+    regs.year.write(T_YEAR::Value.val(decimal_to_bcd(year)));
+
+    regs.i2c_write_time(address, i2c);
+}
+
+pub fn get_time(
+    address: u8,
+    i2c: &mut impl _embedded_hal_blocking_i2c_WriteRead,
+) -> (u32, u32, u32) {
+    let mut regs = Ds3231Registers::default();
+
+    regs.i2c_read_time(address, i2c);
+
+    let second = bcd_to_decimal(regs.second.read(T_SECOND::Value));
+    let minute = bcd_to_decimal(regs.minute.read(T_MINUTE::Value));
+    let hour = bcd_to_decimal(regs.hour.read(T_HOUR::Value));
+
+    (second, minute, hour)
 }
 
+pub fn get_date(
+    address: u8,
+    i2c: &mut impl _embedded_hal_blocking_i2c_WriteRead,
+) -> (Weekday, u32, u32, u32, u32) {
+    let mut regs = Ds3231Registers::default();
+
+    regs.i2c_read_date(address, i2c);
+
+    let weekday: Weekday = regs.weekday.read(T_WEEKDAY::Value).into();
+    let day = bcd_to_decimal(regs.day.read(T_DAY::Value));
+    let month = bcd_to_decimal(regs.month.read(T_MONTH::Value));
+    let year = bcd_to_decimal(regs.year.read(T_YEAR::Value));
+    let century = bcd_to_decimal(regs.month.read(T_MONTH::Century));
+
+    (weekday, day, month, year, century)
+}
+
+#[inline]
+fn bcd_to_decimal(value: u8) -> u32 {
+    (((value >> 4) * 10) + (value & 0xF)) as u32
+}
 #[inline]
-fn decimal_to_bcd(value: u8) -> u8 {
-    ((value / 10) << 4) | (value % 10)
+fn decimal_to_bcd(value: u32) -> u8 {
+    (((value / 10) << 4) | (value % 10)) as u8
 }
 
 pub fn in_dst(weekday: Weekday, day: u32, month: u32, hour_24: u32) -> bool {

+ 4 - 2
Nixie_Firmware_Rust/src/main.rs

@@ -76,8 +76,8 @@ fn main() -> ! {
         .pll_source(rcc::PllSource::HSI16)
         .sysclk(80.mhz())
         .hclk(80.mhz())
-        .pclk1(40.mhz())
-        .pclk2(40.mhz())
+        .pclk1(80.mhz())
+        .pclk2(80.mhz())
         .freeze(&mut flash.acr, &mut pwr);
 
     // Split GPIO peripheral into independent pins and registers
@@ -143,6 +143,8 @@ fn main() -> ! {
 
     tusb322::init(TUSB322_ADDR, &mut i2c);
 
+    ds3231::init(DS3231_ADDR, &mut i2c);
+
     // Configure abstract timer that operates off systick timer
     let mut timer = Delay::new(cp.SYST, clocks);
 

+ 0 - 0
Nixie_Firmware_Rust/src/pca9685.rs