summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ds3231.rs49
-rw-r--r--src/i2c.rs82
-rw-r--r--src/main.rs37
3 files changed, 152 insertions, 16 deletions
diff --git a/src/ds3231.rs b/src/ds3231.rs
index 6ad75d8..6b20958 100644
--- a/src/ds3231.rs
+++ b/src/ds3231.rs
@@ -3,19 +3,22 @@ use ::i2c::{I2C, TransDir};
const DS3231_ADDR: u8 = 0b1101000;
const DS3231_REG_SEC: u8 = 0x00;
+const DS3231_REG_CTL: u8 = 0x0e;
pub struct DS3231<'a> {
i2c: I2C<'a>
}
pub struct Date {
- second: u8,
- minute: u8,
- hour: u8,
- day: u8,
- date: u8,
- month: u8,
- year: u8
+ pub second: u8,
+ pub minute: u8,
+ pub hour: u8,
+ pub day: u8,
+ pub date: u8,
+ pub month: u8,
+ pub year: u8,
+ pub am: bool,
+ pub am_enable: bool
}
impl<'a> DS3231<'a> {
@@ -31,6 +34,17 @@ impl<'a> DS3231<'a> {
((dec / 10) << 4) | (dec % 10)
}
+ pub fn init(&self) {
+ let i2c = &self.i2c;
+ i2c.init();
+ i2c.start(true, true);
+ i2c.send_addr(DS3231_ADDR, TransDir::TRANSMITTER, true);
+ i2c.send(DS3231_REG_CTL, true);
+ i2c.send(0x00, true);
+ i2c.send(0x00, true);
+ i2c.stop(true);
+ }
+
pub fn read_fulldate(&self) -> Date {
let mut buf: [u8; 7] = [0; 7];
let i2c = &self.i2c;
@@ -47,20 +61,35 @@ impl<'a> DS3231<'a> {
i2c.conf_ack(false); /* disable ack (send nack) */
buf[6] = i2c.recv(true);
i2c.stop(true);
+ let am_enable = (buf[2] >> 6) & 1 == 1;
+ let hour = if am_enable {
+ (buf[2] & 0x0f) + ((buf[2] >> 4) & 1) * 10
+ } else {
+ DS3231::bcd2dec(buf[2])
+ };
+ let am = if am_enable {(buf[2] >> 5) & 1 == 0} else {hour < 12};
Date{second: DS3231::bcd2dec(buf[0]),
minute: DS3231::bcd2dec(buf[1]),
- hour: DS3231::bcd2dec(buf[2]),
+ hour: hour,
day: DS3231::bcd2dec(buf[3]),
date: DS3231::bcd2dec(buf[4]),
month: DS3231::bcd2dec(buf[5]),
- year: DS3231::bcd2dec(buf[6])}
+ year: DS3231::bcd2dec(buf[6]),
+ am: am,
+ am_enable: am_enable}
}
pub fn write_fulldate(&self, date: &Date) {
let i2c = &self.i2c;
+ let hour = if date.am_enable {
+ (1 << 6) | ((if date.am {0} else {1}) << 5) |
+ ((date.hour % 10) << 4) | (date.hour & 0x0f)
+ } else {
+ DS3231::dec2bcd(date.hour)
+ };
let buf: [u8; 7] = [DS3231::dec2bcd(date.second),
DS3231::dec2bcd(date.minute),
- DS3231::dec2bcd(date.hour),
+ hour,
DS3231::dec2bcd(date.day),
DS3231::dec2bcd(date.date),
DS3231::dec2bcd(date.month),
diff --git a/src/i2c.rs b/src/i2c.rs
index 8b6d4da..6a8d7a4 100644
--- a/src/i2c.rs
+++ b/src/i2c.rs
@@ -1,5 +1,7 @@
#![allow(dead_code)]
extern crate stm32f103xx;
+use stm32f103xx::RCC;
+
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 */
@@ -8,9 +10,13 @@ pub const EVENT_MASTER_BYTE_RECEIVED: u32 = 0x00030040; /* BUSY, MSL and RXNE f
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;
+const HSI_VALUE: u32 = 8000000;
+const HSE_VALUE: u32 = 8000000;
+const CCR_CCR_SET: u16 = 0x0FFF;
+const CCR_FS_SET: u16 = 0x8000;
+const CR1_CLEAR_MASK: u16 = 0xFBF5;
+const I2C_ACK_ENABLE: u16 = 0x0400;
pub struct I2C<'a> {
i2c: &'a stm32f103xx::i2c1::RegisterBlock,
@@ -26,6 +32,78 @@ impl<'a> I2C<'a> {
I2C{i2c: reg}
}
+ fn get_pclk1() -> u32 {
+ unsafe {
+ use stm32f103xx::rcc::cfgr::{SWSR, PLLSRCR, PLLXTPRER};
+ let rcc: &stm32f103xx::rcc::RegisterBlock = &*RCC.get();
+ let cfgr = rcc.cfgr.read();
+ let sysclk_freq = match cfgr.sws() {
+ SWSR::HSI => HSI_VALUE,
+ SWSR::HSE => HSE_VALUE,
+ SWSR::PLL => {
+ let pllmull = cfgr.pllmul().bits();
+ let pllsource = cfgr.pllsrc();
+ let pllmull = (pllmull as u32 >> 18) + 2;
+ match pllsource {
+ PLLSRCR::INTERNAL => {
+ (HSI_VALUE >> 1) * pllmull
+ },
+ PLLSRCR::EXTERNAL => {
+ match cfgr.pllxtpre() {
+ PLLXTPRER::DIV2 => (HSE_VALUE >> 1) * pllmull,
+ PLLXTPRER::DIV1 => HSE_VALUE * pllmull
+ }
+ }
+ }
+ }
+ _ => HSI_VALUE
+ };
+ let div_table: [u8; 16] = [0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9];
+ let hclk_freq = sysclk_freq >> div_table[cfgr.hpre().bits() as usize];
+ let pclk1_freq = hclk_freq >> div_table[cfgr.ppre1().bits() as usize];
+ pclk1_freq
+ }
+ }
+
+ pub fn init(&self) {
+ let i2c = &self.i2c;
+ unsafe {
+ let rcc: &stm32f103xx::rcc::RegisterBlock = &*RCC.get();
+ rcc.apb1rstr.modify(|_, w| w.i2c1rst().set_bit());
+ rcc.apb1rstr.modify(|_, w| w.i2c1rst().clear_bit());
+ self.pe(true); /* PE = 1, enable I2C */
+ /* CR2 configuration */
+ let pclk1 = I2C::get_pclk1();
+ let freq_range: u16 = (pclk1 / 1000000) as u16;
+ i2c.cr2.modify(|r, w| w.bits(r.bits()).freq().bits(freq_range as u8));
+ /* CCR configuration */
+ self.pe(false);
+ let mut res = (pclk1 / (400000 * 3)) as u16;
+ if (res & CCR_CCR_SET) == 0 {
+ res |= 0x0001;
+ }
+ /* TRISE configuration */
+ i2c.trise.write(|w| w.bits(((freq_range * 300) / 1000 + 1) as u32));
+ i2c.ccr.modify(|r, w| w.bits((res | CCR_FS_SET) as u32));
+ self.pe(true); /* PE = 1, enable I2C */
+ /* CR1 configuration */
+ i2c.cr1.modify(|r, w| w.bits(((r.bits() as u16 & CR1_CLEAR_MASK) | I2C_ACK_ENABLE) as u32));
+ /* OAR1 configuration */
+ i2c.oar1.write(|w| w.addmode().clear_bit().add7().bits(0x01));
+ while i2c.sr2.read().busy().bit() {} /* wait until the bus is free */
+ }
+ }
+
+ pub fn pe(&self, enable: bool) {
+ let i2c = &self.i2c;
+ unsafe {
+ match enable {
+ true => i2c.cr1.modify(|r, w| w.bits(r.bits()).pe().set_bit()),
+ false => i2c.cr1.modify(|r, w| w.bits(r.bits()).pe().clear_bit())
+ }
+ }
+ }
+
pub fn start(&self, enable: bool, synced: bool) {
let i2c = &self.i2c;
unsafe {
diff --git a/src/main.rs b/src/main.rs
index 168e55a..6690828 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,7 +2,7 @@
#[macro_use] extern crate stm32f103xx;
extern crate cortex_m;
-use stm32f103xx::{GPIOA, RCC, SYST, I2C1};
+use stm32f103xx::{GPIOA, GPIOB, RCC, SYST, I2C1};
use cortex_m::peripheral::SystClkSource;
mod i2c;
mod ds3231;
@@ -23,6 +23,7 @@ fn systick_handler() {
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;
@@ -31,10 +32,16 @@ fn systick_handler() {
carry = if DIGITS[i] > 9 {DIGITS[i] = 0; 1} else {0};
i += 1;
}
+ */
+ let ds3231::Date{second: sec, minute: min, hour: hr, ..} = RTC.as_mut().unwrap().read_fulldate();
+ DIGITS[4] = sec / 10; DIGITS[5] = sec % 10;
+ DIGITS[2] = min / 10; DIGITS[3] = min % 10;
+ DIGITS[0] = hr / 10; DIGITS[1] = hr % 10;
+ SR.as_mut().unwrap().output_bits(digits2bcds(&DIGITS[..]));
}
}
-//exception!(SYS_TICK, systick_handler);
+exception!(SYS_TICK, systick_handler);
impl<'a> ShiftRegister<'a> {
fn new(g: &'a stm32f103xx::gpioa::RegisterBlock,
@@ -73,6 +80,7 @@ fn digits2bcds(digs: &[u8]) -> u32 {
fn main() {
let gpioa: &stm32f103xx::gpioa::RegisterBlock = unsafe { &*GPIOA.get() };
+ let gpiob: &stm32f103xx::gpioa::RegisterBlock = unsafe { &*GPIOB.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() };
@@ -81,16 +89,37 @@ fn main() {
syst.set_reload(100_000);
syst.enable_interrupt();
syst.enable_counter();
- rcc.apb2enr.modify(|_, w| w.iopaen().enabled());
+ rcc.apb2enr.modify(|_, w| w.iopaen().enabled()
+ .iopben().enabled()
+ .afioen().enabled());
gpioa.crl.modify(|_, w|
w.mode0().output().cnf0().push()
.mode1().output().cnf1().push()
.mode2().output().cnf2().push());
+ gpiob.crl.modify(|_, w|
+ w.mode6().output50().cnf6().alt_open()
+ .mode7().output50().cnf7().alt_open());
+
+ rcc.apb1enr.modify(|_, w| w.i2c1en().enabled());
+
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();
+ let rtc = RTC.as_mut().unwrap();
+ rtc.init();
+ let x = rtc.read_fulldate();
+ /*
+ rtc.write_fulldate(&ds3231::Date{second: 30,
+ minute: 48,
+ hour: 21,
+ day: 4,
+ date: 21,
+ month: 9,
+ year: 17,
+ am: false,
+ am_enable: false});
+ */
}
}