diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ds3231.rs | 77 | ||||
-rw-r--r-- | src/i2c.rs | 101 | ||||
-rw-r--r-- | src/main.rs | 96 |
3 files changed, 274 insertions, 0 deletions
diff --git a/src/ds3231.rs b/src/ds3231.rs new file mode 100644 index 0000000..6ad75d8 --- /dev/null +++ b/src/ds3231.rs @@ -0,0 +1,77 @@ +extern crate stm32f103xx; +use ::i2c::{I2C, TransDir}; + +const DS3231_ADDR: u8 = 0b1101000; +const DS3231_REG_SEC: u8 = 0x00; + +pub struct DS3231<'a> { + i2c: I2C<'a> +} + +pub struct Date { + second: u8, + minute: u8, + hour: u8, + day: u8, + date: u8, + month: u8, + year: u8 +} + +impl<'a> DS3231<'a> { + pub fn new(i2c_reg: &'a stm32f103xx::i2c1::RegisterBlock) -> DS3231<'a> { + DS3231{i2c: I2C::new(i2c_reg)} + } + + fn bcd2dec(bcd: u8) -> u8 { + (bcd >> 4) * 10 + (bcd & 0x0f) + } + + fn dec2bcd(dec: u8) -> u8 { + ((dec / 10) << 4) | (dec % 10) + } + + pub fn read_fulldate(&self) -> Date { + let mut buf: [u8; 7] = [0; 7]; + let i2c = &self.i2c; + i2c.conf_ack(true); /* enable ack */ + i2c.start(true, true); /* start condition (for writing reg addr) */ + i2c.send_addr(DS3231_ADDR, TransDir::TRANSMITTER, true); + i2c.send(DS3231_REG_SEC, true); + /* restart condition (for reading val from the reg addr) */ + i2c.start(true, true); + i2c.send_addr(DS3231_ADDR, TransDir::RECEIVER, true); + for i in 0..6 { + buf[i] = i2c.recv(true); + } + i2c.conf_ack(false); /* disable ack (send nack) */ + buf[6] = i2c.recv(true); + i2c.stop(true); + Date{second: DS3231::bcd2dec(buf[0]), + minute: DS3231::bcd2dec(buf[1]), + hour: DS3231::bcd2dec(buf[2]), + day: DS3231::bcd2dec(buf[3]), + date: DS3231::bcd2dec(buf[4]), + month: DS3231::bcd2dec(buf[5]), + year: DS3231::bcd2dec(buf[6])} + } + + pub fn write_fulldate(&self, date: &Date) { + let i2c = &self.i2c; + let buf: [u8; 7] = [DS3231::dec2bcd(date.second), + DS3231::dec2bcd(date.minute), + DS3231::dec2bcd(date.hour), + DS3231::dec2bcd(date.day), + DS3231::dec2bcd(date.date), + DS3231::dec2bcd(date.month), + DS3231::dec2bcd(date.year)]; + i2c.conf_ack(true); + i2c.start(true, true); /* start condition for writing */ + i2c.send_addr(DS3231_ADDR, TransDir::TRANSMITTER, true); + i2c.send(DS3231_REG_SEC, true); + for i in 0..7 { + i2c.send(buf[i], true); + } + i2c.stop(true); + } +} diff --git a/src/i2c.rs b/src/i2c.rs new file mode 100644 index 0000000..8b6d4da --- /dev/null +++ b/src/i2c.rs @@ -0,0 +1,101 @@ +#![allow(dead_code)] +extern crate stm32f103xx; + +pub const EVENT_MASTER_STARTED: u32 = 0x00030001; /* BUSY, MSL and SB flag */ +pub const EVENT_MASTER_TRANSMITTER_MODE_SELECTED: u32 = 0x00070082; /* BUSY, MSL, ADDR, TXE and TRA flags */ +pub const EVENT_MASTER_RECEIVER_MODE_SELECTED: u32 = 0x00030002; /* BUSY, MSL and ADDR flags */ +pub const EVENT_MASTER_BYTE_RECEIVED: u32 = 0x00030040; /* BUSY, MSL and RXNE flags */ +pub const EVENT_MASTER_BYTE_TRANSMITTING: u32 = 0x00070080; /* TRA, BUSY, MSL, TXE flags */ +pub const EVENT_MASTER_BYTE_TRANSMITTED: u32 = 0x00070084; /* TRA, BUSY, MSL, TXE and BTF flags */ + +const CR1_START_MASK: u16 = 0x0100; +const CR1_STOP_MASK: u16 = 0x0200; +const FLAGS_MASK: u32 = 0x00ffffff; + +pub struct I2C<'a> { + i2c: &'a stm32f103xx::i2c1::RegisterBlock, +} + +pub enum TransDir { + TRANSMITTER, + RECEIVER +} + +impl<'a> I2C<'a> { + pub fn new(reg: &'a stm32f103xx::i2c1::RegisterBlock) -> I2C<'a> { + I2C{i2c: reg} + } + + pub fn start(&self, enable: bool, synced: bool) { + let i2c = &self.i2c; + unsafe { + match enable { + true => i2c.cr1.modify(|r, w| w.bits(r.bits()).start().set_bit()), + false => i2c.cr1.modify(|r, w| w.bits(r.bits()).start().clear_bit()) + } + } + if synced { + while !self.check_event(EVENT_MASTER_STARTED) {} + } + } + + pub fn stop(&self, enable: bool) { + let i2c = &self.i2c; + unsafe { + match enable { + true => i2c.cr1.modify(|r, w| w.bits(r.bits()).stop().set_bit()), + false => i2c.cr1.modify(|r, w| w.bits(r.bits()).stop().clear_bit()) + } + } + } + + pub fn conf_ack(&self, enable: bool) { + let i2c = &self.i2c; + unsafe { + match enable { + true => i2c.cr1.modify(|r, w| w.bits(r.bits()).ack().set_bit()), + false => i2c.cr1.modify(|r, w| w.bits(r.bits()).ack().clear_bit()) + } + } + } + + pub fn send_addr(&self, addr: u8, d: TransDir, synced: bool) { + let addr = (addr << 1) | match d { + TransDir::TRANSMITTER => 0, + TransDir::RECEIVER => 1 + }; + unsafe { + self.i2c.dr.write(|w| w.dr().bits(addr)); + } + if synced { + match d { + TransDir::TRANSMITTER => + while !self.check_event(EVENT_MASTER_TRANSMITTER_MODE_SELECTED) {}, + TransDir::RECEIVER => + while !self.check_event(EVENT_MASTER_RECEIVER_MODE_SELECTED) {} + } + } + } + + pub fn send(&self, data: u8, synced: bool) { + unsafe { + self.i2c.dr.write(|w| w.dr().bits(data)); + } + if synced { + while !self.check_event(EVENT_MASTER_BYTE_TRANSMITTED) {} + } + } + + pub fn recv(&self, synced: bool) -> u8 { + if synced { + while !self.check_event(EVENT_MASTER_BYTE_RECEIVED) {} + } + self.i2c.dr.read().dr().bits() + } + + pub fn check_event(&self, ev_mask: u32) -> bool { + let flags = self.i2c.sr1.read().bits() & 0xffff | + ((self.i2c.sr2.read().bits() & 0xffff) << 16) & FLAGS_MASK; + (flags & ev_mask) == ev_mask + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..168e55a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,96 @@ +#![no_std] + +#[macro_use] extern crate stm32f103xx; +extern crate cortex_m; +use stm32f103xx::{GPIOA, RCC, SYST, I2C1}; +use cortex_m::peripheral::SystClkSource; +mod i2c; +mod ds3231; + +struct ShiftRegister<'a> { + gpioa: &'a stm32f103xx::gpioa::RegisterBlock, + width: u8, +} + +static mut SR: Option<ShiftRegister> = None; +static mut RTC: Option<ds3231::DS3231> = None; +static mut N: u16 = 0; +static mut DIGITS: [u8; 6] = [0; 6]; + +fn systick_handler() { + unsafe { + /* + SR.as_mut().unwrap().output_bits(N as u32); + N += 1; + */ + SR.as_mut().unwrap().output_bits(digits2bcds(&DIGITS[..])); + let mut i = 0; + let mut carry = 1; + while carry > 0 && i < DIGITS.len() { + DIGITS[i] += carry; + carry = if DIGITS[i] > 9 {DIGITS[i] = 0; 1} else {0}; + i += 1; + } + } +} + +//exception!(SYS_TICK, systick_handler); + +impl<'a> ShiftRegister<'a> { + fn new(g: &'a stm32f103xx::gpioa::RegisterBlock, + width: u8) -> ShiftRegister<'a> { + let this = ShiftRegister{gpioa: g, width: width}; + this + } + + fn output_bits(&mut self, bits: u32) { + let bsrr = &self.gpioa.bsrr; + for i in (0..self.width).rev() { + bsrr.write(|w| w.br1().reset()); + /* feed the ser */ + match (bits >> i) & 1 { + 0 => bsrr.write(|w| w.br0().reset()), + 1 => bsrr.write(|w| w.bs0().set()), + _ => panic!() + } + /* shift (trigger the sclk) */ + bsrr.write(|w| w.bs1().set()); + } + /* latch on (trigger the clk) */ + bsrr.write(|w| w.br2().reset()); + bsrr.write(|w| w.bs2().set()); + } +} + +fn digits2bcds(digs: &[u8]) -> u32 { + let mut res: u32 = 0; + for d in digs.iter().rev() { + res = (res << 4) | (*d as u32); + } + res +} + +fn main() { + + let gpioa: &stm32f103xx::gpioa::RegisterBlock = unsafe { &*GPIOA.get() }; + let rcc: &stm32f103xx::rcc::RegisterBlock = unsafe { &*RCC.get() }; + let i2c: &stm32f103xx::i2c1::RegisterBlock = unsafe { &*I2C1.get() }; + let syst: &cortex_m::peripheral::SYST = unsafe { &*SYST.get() }; + + syst.set_clock_source(SystClkSource::Core); + syst.set_reload(100_000); + syst.enable_interrupt(); + syst.enable_counter(); + rcc.apb2enr.modify(|_, w| w.iopaen().enabled()); + gpioa.crl.modify(|_, w| + w.mode0().output().cnf0().push() + .mode1().output().cnf1().push() + .mode2().output().cnf2().push()); + + unsafe { + RTC = Some(ds3231::DS3231::new(i2c)); + SR = Some(ShiftRegister::new(gpioa, 24)); + SR.as_mut().unwrap().output_bits(0); + let t = RTC.as_mut().unwrap().read_fulldate(); + } +} |