From b27ebb9f07d7ee0b60abe84738db712c8fbcb3f1 Mon Sep 17 00:00:00 2001 From: Determinant Date: Fri, 29 Sep 2017 01:20:46 -0400 Subject: support arbitrary write for EEPROM --- src/at24c.rs | 28 ++++++++++++++++++++++++++-- src/i2c.rs | 48 +++++++++++++++++++++++++++++++++++++----------- src/main.rs | 16 +++++++++------- 3 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/at24c.rs b/src/at24c.rs index 534f736..569f04a 100644 --- a/src/at24c.rs +++ b/src/at24c.rs @@ -14,7 +14,9 @@ impl<'a, 'b> AT24C<'a, 'b> { let &AT24C(ref i2c) = self; i2c.conf_ack(true); /* enable ack */ i2c.start(true, true); /* start condition (for writing addr) */ - i2c.send_addr(AT24C_ADDR, TransDir::TRANSMITTER, true); + while !i2c.send_addr(AT24C_ADDR, TransDir::TRANSMITTER, true) { + i2c.start(true, true); + } i2c.send(((start >> 8) & 0x0f) as u8, true); /* first word addr */ i2c.send((start & 0xff) as u8, true); /* second word addr */ i2c.start(true, true); /* restart to read */ @@ -31,7 +33,9 @@ impl<'a, 'b> AT24C<'a, 'b> { let &AT24C(ref i2c) = self; i2c.conf_ack(true); /* enable ack */ i2c.start(true, true); /* start condition (for writing addr) */ - i2c.send_addr(AT24C_ADDR, TransDir::TRANSMITTER, true); + while !i2c.send_addr(AT24C_ADDR, TransDir::TRANSMITTER, true) { + i2c.start(true, true); + } i2c.send(((start >> 8) & 0x0f) as u8, true); /* first word addr */ i2c.send((start & 0xff) as u8, true); /* second word addr */ for i in 0..size { @@ -39,4 +43,24 @@ impl<'a, 'b> AT24C<'a, 'b> { } i2c.stop(true); } + + pub fn write(&self, start: u16, size: usize, buf: &[u8]) { + let end = start + size as u16 - 1; + let pg_s_off = start & 0x1f; + let pg_e_off = end & 0x1f; + let pg_s = start >> 5; + let pg_e = end >> 5; + if pg_s == pg_e { + self.page_write(start, size, buf); + } else { + let mut buf = buf; + self.page_write(start, (0x20 - pg_s_off) as usize, buf); + buf = &buf[0x20 - pg_s_off as usize..]; + for i in (pg_s + 1)..pg_e { + self.page_write(i << 5, 0x20, buf); + buf = &buf[0x20..]; + } + self.page_write(pg_e << 5, (pg_e_off + 1) as usize, buf); + } + } } diff --git a/src/i2c.rs b/src/i2c.rs index 89e2072..1f8a57f 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -30,6 +30,7 @@ pub enum DutyType { } impl<'a, 'b> I2C<'a, 'b> { + #[inline(always)] pub fn new(i2c: &'a stm32f103xx::i2c1::RegisterBlock, rcc: &'b stm32f103xx::rcc::RegisterBlock) -> I2C<'a, 'b> { I2C{i2c, rcc} @@ -69,20 +70,28 @@ impl<'a, 'b> I2C<'a, 'b> { pub fn init(&self, addr: u8, scl_freq: u32, - duty_type: DutyType) { + duty_type: DutyType, + fast_mode: bool) { let i2c = &self.i2c; unsafe { let pclk1 = self.get_pclk1(); let freq_range: u16 = (pclk1 / 1_000_000) as u16; self.pe(false); /* TRISE configuration (in Fm mode, max rise interval is 300) */ - i2c.trise.write(|w| w.bits(((freq_range * 300) / 1000 + 1) as u32)); + i2c.trise.write(|w| w.bits(if fast_mode {(freq_range * 300) / 1000 + 1} + else {freq_range + 1} as u32)); /* CCR configuration */ - i2c.ccr.write(|w| match duty_type { - DutyType::DUTY0 => w.ccr().bits(max(pclk1 / (scl_freq * (2 + 1)), 0x1) as u16), - DutyType::DUTY1 => w.ccr().bits(max(pclk1 / (scl_freq * (16 + 9)), 0x1) as u16) - .duty().set_bit(), - }.f_s().set_bit()); + i2c.ccr.write(|w| + if fast_mode { + match duty_type { + DutyType::DUTY0 => w.ccr().bits(max(pclk1 / (scl_freq * (2 + 1)), 0x1) as u16), + DutyType::DUTY1 => w.ccr().bits(max(pclk1 / (scl_freq * (16 + 9)), 0x1) as u16) + .duty().set_bit(), + }.f_s().set_bit() + } else { + w.ccr().bits(max(pclk1 / (scl_freq * (1 + 1)), 0x4) as u16) + .f_s().clear_bit() + }); self.pe(true); /* PE = 1, enable I2C */ /* CR1 configuration */ i2c.cr1.modify(|r, w| w.bits(r.bits()) @@ -107,6 +116,10 @@ impl<'a, 'b> I2C<'a, 'b> { } } + pub fn is_ack_fail(&self) -> bool { + self.i2c.sr1.read().af().bit_is_set() + } + pub fn start(&self, enable: bool, synced: bool) { let i2c = &self.i2c; unsafe { @@ -116,7 +129,10 @@ impl<'a, 'b> I2C<'a, 'b> { } } if synced { - while !self.check_event(EVENT_MASTER_STARTED) {} + match enable { + true => while !self.check_event(EVENT_MASTER_STARTED) {}, + false => while self.check_event(EVENT_MASTER_STARTED) {} + } } } @@ -140,22 +156,32 @@ impl<'a, 'b> I2C<'a, 'b> { } } - pub fn send_addr(&self, addr: u8, d: TransDir, synced: bool) { + pub fn send_addr(&self, addr: u8, d: TransDir, synced: bool) -> bool { let addr = (addr << 1) | match d { TransDir::TRANSMITTER => 0, TransDir::RECEIVER => 1 }; unsafe { + self.i2c.sr1.write(|w| w.af().clear_bit()); self.i2c.dr.write(|w| w.dr().bits(addr)); } if synced { match d { TransDir::TRANSMITTER => - while !self.check_event(EVENT_MASTER_TRANSMITTER_MODE_SELECTED) {}, + while !self.check_event(EVENT_MASTER_TRANSMITTER_MODE_SELECTED) { + if self.is_ack_fail() { + return false + } + }, TransDir::RECEIVER => - while !self.check_event(EVENT_MASTER_RECEIVER_MODE_SELECTED) {} + while !self.check_event(EVENT_MASTER_RECEIVER_MODE_SELECTED) { + if self.is_ack_fail() { + return false + } + } } } + true } pub fn send(&self, data: u8, synced: bool) { diff --git a/src/main.rs b/src/main.rs index 2b3c97c..d5fdef9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,6 +51,7 @@ fn digits_countup() { fn update_clock() { unsafe { + if RTC.is_none() {return} if !TIME.tick() { let ds3231::Date{second: sec, minute: min, @@ -164,14 +165,14 @@ fn main() { unsafe { I2C = Some(i2c::I2C::new(i2c, rcc)); let i2c = I2C.as_mut().unwrap(); - RTC = Some(ds3231::DS3231::new(i2c)); + let rtc = ds3231::DS3231::new(i2c); ROM = Some(at24c::AT24C::new(i2c)); SR = Some(ShiftRegister::new(gpioa, 24)); - i2c.init(0x01, 400_000, i2c::DutyType::DUTY1); + i2c.init(0x01, 400_000, i2c::DutyType::DUTY1, true); + //i2c.init(0x01, 100_000, i2c::DutyType::DUTY1, false); SR.as_mut().unwrap().output_bits(0); - let rtc = RTC.as_mut().unwrap(); /* initialize the ds3231 */ /* rtc.write_fulldate(&ds3231::Date{second: 30, @@ -186,11 +187,12 @@ fn main() { */ /* let rom = ROM.as_mut().unwrap(); - let mut buf: [u8; 16] = [0; 16]; - rom.read(0, 16, &mut buf); - let mut buf2: [u8; 4] = [0, 1, 2, 3]; - rom.page_write(0, 4, &buf2); + let mut buf: [u8; 64] = [23; 64]; + rom.write(23, 64, &buf); + let mut buf2: [u8; 80] = [0; 80]; + rom.read(20, 80, &mut buf2); */ + RTC = Some(rtc); } update_clock(); -- cgit v1.2.3