summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <ted.sybil@gmail.com>2017-09-21 15:50:48 -0400
committerDeterminant <ted.sybil@gmail.com>2017-09-21 15:50:48 -0400
commitf6340e4d1f6bd9356830e0c73f0bd813912ea2cc (patch)
treeab6b1d658f1a03be0156e5354f8ee84ba4ec22bb
init
-rw-r--r--.cargo/config10
-rw-r--r--.gdbinit6
-rw-r--r--.gitignore5
-rw-r--r--Cargo.toml22
-rw-r--r--Xargo.toml6
-rw-r--r--build.rs17
-rw-r--r--memory.x5
-rw-r--r--src/ds3231.rs77
-rw-r--r--src/i2c.rs101
-rw-r--r--src/main.rs96
10 files changed, 345 insertions, 0 deletions
diff --git a/.cargo/config b/.cargo/config
new file mode 100644
index 0000000..6f29034
--- /dev/null
+++ b/.cargo/config
@@ -0,0 +1,10 @@
+[target.thumbv7m-none-eabi]
+runner = 'arm-none-eabi-gdb'
+rustflags = [
+ "-C", "link-arg=-Tlink.x",
+ "-C", "linker=arm-none-eabi-ld",
+ "-Z", "linker-flavor=ld",
+]
+
+[build]
+target = "thumbv7m-none-eabi"
diff --git a/.gdbinit b/.gdbinit
new file mode 100644
index 0000000..7c72d4f
--- /dev/null
+++ b/.gdbinit
@@ -0,0 +1,6 @@
+target remote :3333
+
+monitor arm semihosting enable
+
+load
+step
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8bc31d4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+**/*.rs.bk
+*.org
+.gdb_history
+Cargo.lock
+target/
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..332dd58
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "bluepill-ds3231"
+description = "Test the communication with DS3231"
+authors = ["Ted Yin <tederminant@gmail.com>"]
+keywords = ["no-std", "arm", "cortex-m", "stm32"]
+license = "GPL-3.0"
+version = "0.1.0"
+
+[dependencies.stm32f103xx]
+features = ["rt"]
+version = "0.7.2"
+
+[dependencies.cortex-m-rt]
+version = "0.3.5"
+features = ["abort-on-panic"]
+
+[dependencies.cortex-m]
+version = "0.3.0"
+
+[profile.release]
+debug = true
+lto = true
diff --git a/Xargo.toml b/Xargo.toml
new file mode 100644
index 0000000..89ad4cd
--- /dev/null
+++ b/Xargo.toml
@@ -0,0 +1,6 @@
+[dependencies.core]
+stage = 0
+
+[dependencies.compiler_builtins]
+features = ["mem"]
+stage = 1 \ No newline at end of file
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..34363d2
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,17 @@
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+
+pub fn main() {
+ // Put the linker script somewhere the linker can find it
+ let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
+ File::create(out.join("memory.x"))
+ .unwrap()
+ .write_all(include_bytes!("memory.x"))
+ .unwrap();
+ println!("cargo:rustc-link-search={}", out.display());
+
+ println!("cargo:rerun-if-changed=build.rs");
+ println!("cargo:rerun-if-changed=memory.x");
+}
diff --git a/memory.x b/memory.x
new file mode 100644
index 0000000..59195b8
--- /dev/null
+++ b/memory.x
@@ -0,0 +1,5 @@
+MEMORY
+{
+ FLASH : ORIGIN = 0x08000000, LENGTH = 64K
+ RAM : ORIGIN = 0x20000000, LENGTH = 20K
+}
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();
+ }
+}