Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/display-touch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use embedded_graphics_07::{
};

#[cfg(feature = "stm32f413")]
use stm32f4xx_hal::fmpi2c::FMPI2c;
use stm32f4xx_hal::fmpi2c::I2c;
#[cfg(feature = "stm32f412")]
use stm32f4xx_hal::i2c::I2c;

Expand Down Expand Up @@ -153,7 +153,7 @@ fn main() -> ! {
// STM32F413 uses FMPI2C1 type.
// The pins are mentioned in documentation -um2135-discovery-kit-with-stm32f413zh-mcu-stmicroelectronics
#[cfg(feature = "stm32f413")]
let mut i2c = { FMPI2c::new(p.FMPI2C1, (gpioc.pc6, gpioc.pc7), 400.kHz()) };
let mut i2c = { I2c::new(p.FMPI2C1, (gpioc.pc6, gpioc.pc7), 400.kHz()) };

#[cfg(feature = "stm32f412")]
let ts_int = gpiog.pg5.into_pull_down_input();
Expand Down
106 changes: 69 additions & 37 deletions src/fmpi2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,67 @@ use core::ops::Deref;

use crate::gpio;
use crate::i2c::{Error, NoAcknowledgeSource};
use crate::pac::{fmpi2c1, FMPI2C1, RCC};
use crate::rcc::{Enable, Reset};
use crate::pac::fmpi2c1 as i2c1;
use crate::pac::{self, RCC};
use crate::rcc::{BusClock, Enable, Reset};
use fugit::{HertzU32 as Hertz, RateExtU32};

// Old names
pub use I2c as FmpI2c;
pub use Mode as FmpMode;

mod hal_02;
mod hal_1;

pub trait Instance:
crate::Sealed
+ crate::Ptr<RB = fmpi2c1::RegisterBlock>
+ crate::Ptr<RB = i2c1::RegisterBlock>
+ Deref<Target = Self::RB>
+ Enable
+ Reset
+ BusClock
+ gpio::alt::I2cCommon
{
fn clock_hsi(rcc: &crate::pac::rcc::RegisterBlock);
}

impl Instance for FMPI2C1 {
fn clock_hsi(rcc: &crate::pac::rcc::RegisterBlock) {
rcc.dckcfgr2().modify(|_, w| w.fmpi2c1sel().hsi());
}
}
macro_rules! i2c {
($I2C:ty, $i2csel:ident, $I2Calias:ident) => {
pub type $I2Calias = I2c<$I2C>;

impl crate::Ptr for FMPI2C1 {
type RB = fmpi2c1::RegisterBlock;
#[inline(always)]
fn ptr() -> *const Self::RB {
Self::ptr()
}
impl Instance for $I2C {
fn clock_hsi(rcc: &crate::pac::rcc::RegisterBlock) {
rcc.dckcfgr2().modify(|_, w| w.$i2csel().hsi());
}
}

impl crate::Ptr for $I2C {
type RB = i2c1::RegisterBlock;
#[inline(always)]
fn ptr() -> *const Self::RB {
Self::ptr()
}
}
};
}

#[cfg(feature = "fmpi2c1")]
i2c!(pac::FMPI2C1, fmpi2c1sel, FMPI2c1);

/// I2C FastMode+ abstraction
pub struct FMPI2c<I2C: Instance> {
pub struct I2c<I2C: Instance> {
i2c: I2C,
pins: (I2C::Scl, I2C::Sda),
}

pub type FMPI2c1 = FMPI2c<FMPI2C1>;

#[derive(Debug, PartialEq)]
pub enum FmpMode {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Mode {
Standard { frequency: Hertz },
Fast { frequency: Hertz },
FastPlus { frequency: Hertz },
}

impl FmpMode {
impl Mode {
pub fn standard(frequency: Hertz) -> Self {
Self::Standard { frequency }
}
Expand All @@ -71,7 +84,7 @@ impl FmpMode {
}
}

impl From<Hertz> for FmpMode {
impl From<Hertz> for Mode {
fn from(frequency: Hertz) -> Self {
let k100: Hertz = 100.kHz();
let k400: Hertz = 400.kHz();
Expand All @@ -85,26 +98,39 @@ impl From<Hertz> for FmpMode {
}
}

impl<I2C: Instance> FMPI2c<I2C> {
pub trait I2cExt: Sized + Instance {
fn i2c<'a>(
self,
pins: (impl Into<Self::Scl>, impl Into<Self::Sda>),
mode: impl Into<Mode>,
) -> I2c<Self>;
}

impl<I2C: Instance> I2cExt for I2C {
fn i2c<'a>(
self,
pins: (impl Into<Self::Scl>, impl Into<Self::Sda>),
mode: impl Into<Mode>,
) -> I2c<Self> {
I2c::new(self, pins, mode)
}
}

impl<I2C: Instance> I2c<I2C> {
pub fn new(
i2c: I2C,
pins: (impl Into<I2C::Scl>, impl Into<I2C::Sda>),
mode: impl Into<FmpMode>,
mode: impl Into<Mode>,
) -> Self {
unsafe {
// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
let rcc = &(*RCC::ptr());

// Enable and reset clock.
I2C::enable(rcc);
I2C::reset(rcc);

I2C::clock_hsi(rcc);
I2C::enable_unchecked();
I2C::reset_unchecked();
}

let pins = (pins.0.into(), pins.1.into());

let i2c = FMPI2c { i2c, pins };
let i2c = I2c { i2c, pins };
i2c.i2c_init(mode);
i2c
}
Expand All @@ -114,14 +140,18 @@ impl<I2C: Instance> FMPI2c<I2C> {
}
}

impl<I2C: Instance> FMPI2c<I2C> {
fn i2c_init<M: Into<FmpMode>>(&self, mode: M) {
impl<I2C: Instance> I2c<I2C> {
fn i2c_init(&self, mode: impl Into<Mode>) {
let mode = mode.into();
use core::cmp;

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

// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
let rcc = unsafe { &(*RCC::ptr()) };
I2C::clock_hsi(rcc);

// Calculate settings for I2C speed modes
let presc;
let scldel;
Expand All @@ -135,21 +165,21 @@ impl<I2C: Instance> FMPI2c<I2C> {
// Normal I2C speeds use a different scaling than fast mode below and fast mode+ even more
// below
match mode {
FmpMode::Standard { frequency } => {
Mode::Standard { frequency } => {
presc = 3;
scll = cmp::max((((FREQ >> presc) >> 1) / frequency.raw()) - 1, 255) as u8;
sclh = scll - 4;
sdadel = 2;
scldel = 4;
}
FmpMode::Fast { frequency } => {
Mode::Fast { frequency } => {
presc = 1;
scll = cmp::max((((FREQ >> presc) >> 1) / frequency.raw()) - 1, 255) as u8;
sclh = scll - 6;
sdadel = 2;
scldel = 3;
}
FmpMode::FastPlus { frequency } => {
Mode::FastPlus { frequency } => {
presc = 0;
scll = cmp::max((((FREQ >> presc) >> 1) / frequency.raw()) - 4, 255) as u8;
sclh = scll - 2;
Expand All @@ -171,7 +201,8 @@ impl<I2C: Instance> FMPI2c<I2C> {
self.i2c.cr1().modify(|_, w| w.pe().set_bit());
}

fn check_and_clear_error_flags(&self, isr: &fmpi2c1::isr::R) -> Result<(), Error> {
#[inline(always)]
fn check_and_clear_error_flags(&self, isr: &i2c1::isr::R) -> Result<(), Error> {
// If we received a NACK, then this is an error
if isr.nackf().bit_is_set() {
self.i2c
Expand All @@ -183,6 +214,7 @@ impl<I2C: Instance> FMPI2c<I2C> {
Ok(())
}

#[inline(always)]
fn end_transaction(&self) -> Result<(), Error> {
// Check and clear flags if they somehow ended up set
self.check_and_clear_error_flags(&self.i2c.isr().read())
Expand Down
18 changes: 4 additions & 14 deletions src/fmpi2c/hal_02.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
mod blocking {
use super::super::{fmpi2c1, Error, FMPI2c, Instance};
use core::ops::Deref;
use super::super::{Error, I2c, Instance};
use embedded_hal_02::blocking::i2c::{Read, Write, WriteRead};

impl<I2C: Instance> WriteRead for FMPI2c<I2C>
where
I2C: Deref<Target = fmpi2c1::RegisterBlock>,
{
impl<I2C: Instance> WriteRead for I2c<I2C> {
type Error = Error;

fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
self.write_read(addr, bytes, buffer)
}
}

impl<I2C: Instance> Read for FMPI2c<I2C>
where
I2C: Deref<Target = fmpi2c1::RegisterBlock>,
{
impl<I2C: Instance> Read for I2c<I2C> {
type Error = Error;

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

impl<I2C: Instance> Write for FMPI2c<I2C>
where
I2C: Deref<Target = fmpi2c1::RegisterBlock>,
{
impl<I2C: Instance> Write for I2c<I2C> {
type Error = Error;

fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
Expand Down
10 changes: 3 additions & 7 deletions src/fmpi2c/hal_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@ use embedded_hal::i2c::ErrorType;

use super::Instance;

impl<I2C: Instance> ErrorType for super::FMPI2c<I2C> {
impl<I2C: Instance> ErrorType for super::I2c<I2C> {
type Error = super::Error;
}

mod blocking {
use super::super::{fmpi2c1, FMPI2c, Instance};
use core::ops::Deref;
use super::super::{I2c, Instance};
use embedded_hal::i2c::Operation;

impl<I2C: Instance> embedded_hal::i2c::I2c for FMPI2c<I2C>
where
I2C: Deref<Target = fmpi2c1::RegisterBlock>,
{
impl<I2C: Instance> embedded_hal::i2c::I2c for I2c<I2C> {
fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.read(addr, buffer)
}
Expand Down
30 changes: 6 additions & 24 deletions src/i2c/hal_02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ mod blocking {
Operation, Read, Transactional, Write, WriteIter, WriteIterRead, WriteRead,
};

impl<I2C> WriteRead for I2c<I2C>
where
I2C: Instance,
{
impl<I2C: Instance> WriteRead for I2c<I2C> {
type Error = Error;

fn write_read(
Expand All @@ -20,10 +17,7 @@ mod blocking {
}
}

impl<I2C> WriteIterRead for I2c<I2C>
where
I2C: Instance,
{
impl<I2C: Instance> WriteIterRead for I2c<I2C> {
type Error = Error;

fn write_iter_read<B>(
Expand All @@ -39,21 +33,15 @@ mod blocking {
}
}

impl<I2C> Write for I2c<I2C>
where
I2C: Instance,
{
impl<I2C: Instance> Write for I2c<I2C> {
type Error = Error;

fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
self.write(addr, bytes)
}
}

impl<I2C> WriteIter for I2c<I2C>
where
I2C: Instance,
{
impl<I2C: Instance> WriteIter for I2c<I2C> {
type Error = Error;

fn write<B>(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error>
Expand All @@ -64,21 +52,15 @@ mod blocking {
}
}

impl<I2C> Read for I2c<I2C>
where
I2C: Instance,
{
impl<I2C: Instance> Read for I2c<I2C> {
type Error = Error;

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

impl<I2C> Transactional for I2c<I2C>
where
I2C: Instance,
{
impl<I2C: Instance> Transactional for I2c<I2C> {
type Error = Error;

fn exec(
Expand Down
2 changes: 2 additions & 0 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ pub use crate::dma::traits::DmaEventExt as _;
pub use crate::dma::traits::DmaFlagExt as _;
pub use crate::dma::traits::Stream as _;
pub use crate::dma::traits::StreamISR as _;
#[cfg(feature = "fmpi2c1")]
pub use crate::fmpi2c::I2cExt as _;
pub use crate::gpio::outport::OutPort as _;
pub use crate::gpio::ExtiPin as _stm32f4xx_hal_gpio_ExtiPin;
pub use crate::gpio::GpioExt as _stm32f4xx_hal_gpio_GpioExt;
Expand Down