Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow reuse of I2C code without macros #37

Merged
merged 8 commits into from
Dec 17, 2018
96 changes: 77 additions & 19 deletions src/i2c.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::stm32::{I2C1, RCC};
use core::ops::Deref;

use crate::stm32::i2c3;
use crate::stm32::{I2C1, I2C2, RCC};

use hal::blocking::i2c::{Read, Write, WriteRead};

use crate::gpio::gpiob::{PB6, PB7, PB8, PB9};
use crate::gpio::gpiob::{PB10, PB11, PB6, PB7, PB8, PB9};
use crate::gpio::{Alternate, AF4};
use crate::rcc::Clocks;
use crate::time::{Hertz, KiloHertz, U32Ext};
Expand All @@ -17,6 +20,9 @@ pub trait Pins<I2c> {}

impl Pins<I2C1> for (PB6<Alternate<AF4>>, PB7<Alternate<AF4>>) {}
impl Pins<I2C1> for (PB8<Alternate<AF4>>, PB9<Alternate<AF4>>) {}
impl Pins<I2C1> for (PB6<Alternate<AF4>>, PB9<Alternate<AF4>>) {}

impl Pins<I2C2> for (PB10<Alternate<AF4>>, PB11<Alternate<AF4>>) {}

#[derive(Debug)]
pub enum Error {
Expand All @@ -29,8 +35,6 @@ impl<PINS> I2c<I2C1, PINS> {
where
PINS: Pins<I2C1>,
{
let speed: Hertz = speed.into();

// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*RCC::ptr()) };

Expand All @@ -41,16 +45,52 @@ impl<PINS> I2c<I2C1, PINS> {
rcc.apb1rstr.modify(|_, w| w.i2c1rst().set_bit());
rcc.apb1rstr.modify(|_, w| w.i2c1rst().clear_bit());

let i2c = I2c { i2c, pins };
i2c.i2c_init(speed, clocks.pclk1());
i2c
}
}

impl<PINS> I2c<I2C2, PINS> {
pub fn i2c2(i2c: I2C2, pins: PINS, speed: KiloHertz, clocks: Clocks) -> Self
where
PINS: Pins<I2C2>,
{
// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*RCC::ptr()) };

// Enable clock for I2C2
rcc.apb1enr.modify(|_, w| w.i2c2en().set_bit());

// Reset I2C2
rcc.apb1rstr.modify(|_, w| w.i2c2rst().set_bit());
rcc.apb1rstr.modify(|_, w| w.i2c2rst().clear_bit());

let i2c = I2c { i2c, pins };
i2c.i2c_init(speed, clocks.pclk1());
i2c
}
}

type I2cRegisterBlock = i2c3::RegisterBlock;

impl<I2C, PINS> I2c<I2C, PINS>
where
I2C: Deref<Target = I2cRegisterBlock>,
{
fn i2c_init(&self, speed: KiloHertz, pclk: Hertz) {
let speed: Hertz = speed.into();

// Make sure the I2C unit is disabled so we can configure it
i2c.cr1.modify(|_, w| w.pe().clear_bit());
self.i2c.cr1.modify(|_, w| w.pe().clear_bit());

// Calculate settings for I2C speed modes
let clock = clocks.pclk1().0;
let clock = pclk.0;
let freq = clock / 1_000_000;
assert!(freq >= 2 && freq <= 50);

// Configure bus frequency into I2C peripheral
i2c.cr2.write(|w| unsafe { w.freq().bits(freq as u8) });
self.i2c.cr2.write(|w| unsafe { w.freq().bits(freq as u8) });

let trise = if speed <= 100.khz().into() {
freq + 1
Expand All @@ -59,7 +99,7 @@ impl<PINS> I2c<I2C1, PINS> {
};

// Configure correct rise times
i2c.trise.write(|w| w.trise().bits(trise as u8));
self.i2c.trise.write(|w| w.trise().bits(trise as u8));

// I2C clock control calculation
if speed <= 100.khz().into() {
Expand All @@ -73,7 +113,7 @@ impl<PINS> I2c<I2C1, PINS> {
};

// Set clock to standard mode with appropriate parameters for selected speed
i2c.ccr.write(|w| unsafe {
self.i2c.ccr.write(|w| unsafe {
w.f_s()
.clear_bit()
.duty()
Expand All @@ -88,38 +128,47 @@ impl<PINS> I2c<I2C1, PINS> {
let ccr = if ccr < 1 { 1 } else { ccr };

// Set clock to fast mode with appropriate parameters for selected speed (2:1 duty cycle)
i2c.ccr.write(|w| unsafe {
self.i2c.ccr.write(|w| unsafe {
w.f_s().set_bit().duty().clear_bit().ccr().bits(ccr as u16)
});
} else {
let ccr = clock / (speed.0 * 25);
let ccr = if ccr < 1 { 1 } else { ccr };

// Set clock to fast mode with appropriate parameters for selected speed (16:9 duty cycle)
i2c.ccr.write(|w| unsafe {
self.i2c.ccr.write(|w| unsafe {
w.f_s().set_bit().duty().set_bit().ccr().bits(ccr as u16)
});
}
}

// Enable the I2C processing
i2c.cr1.modify(|_, w| w.pe().set_bit());

I2c { i2c, pins }
self.i2c.cr1.modify(|_, w| w.pe().set_bit());
}

pub fn release(self) -> (I2C1, PINS) {
pub fn release(self) -> (I2C, PINS) {
(self.i2c, self.pins)
}
}

trait I2cCommon {
fn send_byte(&self, byte: u8) -> Result<(), Error>;

fn recv_byte(&self) -> Result<u8, Error>;
}

impl<I2C, PINS> I2cCommon for I2c<I2C, PINS>
where
I2C: Deref<Target = I2cRegisterBlock>,
{
fn send_byte(&self, byte: u8) -> Result<(), Error> {
// Wait until we're ready for sending
while self.i2c.sr1.read().tx_e().bit_is_clear() {}

// Push out a byte of data
self.i2c.dr.write(|w| unsafe { w.bits(u32::from(byte)) });

// While until byte is transferred
// Wait until byte is transferred
while {
let sr1 = self.i2c.sr1.read();

Expand All @@ -141,7 +190,10 @@ impl<PINS> I2c<I2C1, PINS> {
}
}

impl<PINS> WriteRead for I2c<I2C1, PINS> {
impl<I2C, PINS> WriteRead for I2c<I2C, PINS>
where
I2C: Deref<Target = I2cRegisterBlock>,
{
type Error = Error;

fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
Expand All @@ -152,7 +204,10 @@ impl<PINS> WriteRead for I2c<I2C1, PINS> {
}
}

impl<PINS> Write for I2c<I2C1, PINS> {
impl<I2C, PINS> Write for I2c<I2C, PINS>
where
I2C: Deref<Target = I2cRegisterBlock>,
{
type Error = Error;

fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
Expand Down Expand Up @@ -195,7 +250,10 @@ impl<PINS> Write for I2c<I2C1, PINS> {
}
}

impl<PINS> Read for I2c<I2C1, PINS> {
impl<I2C, PINS> Read for I2c<I2C, PINS>
where
I2C: Deref<Target = I2cRegisterBlock>,
{
type Error = Error;

fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
Expand Down