stm32f1-hal 0.12.3

HAL for the STM32F1 family
Documentation
mod i2c1;
mod i2c2;

pub use crate::common::i2c::*;

use crate::{
    Mcu, Steal,
    afio::{RemapMode, i2c_remap::*},
    os_trait::Mutex,
    prelude::*,
    rcc::{Enable, GetClock, Reset},
    time::*,
};
use core::marker::PhantomData;

pub trait I2cInit<T> {
    fn init<OS: OsInterface>(self, mcu: &mut Mcu) -> I2c<OS, T>;
}

pub trait I2cPeriphConfig: I2cPeriph + GetClock + Enable + Reset + Steal {
    fn config(&mut self, mode: &Mode);
    fn set_ack(&mut self, en: bool);
    /// Continue after the address has been sent.
    fn continue_after_addr(&mut self);
    fn write_data(&mut self, addr: u8);
    fn read_data(&self) -> u8;
    fn set_interrupt(&mut self, it: Interrupt, en: bool);
    fn it_clean_needless_flag(&self);
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Interrupt {
    Error,
    Event,
    Buffer,
}

// wrapper
pub struct I2c<OS: OsInterface, I> {
    i2c: I,
    _os: PhantomData<OS>,
}

impl<OS, I> I2c<OS, I>
where
    OS: OsInterface,
    I: I2cPeriphConfig,
{
    pub fn into_interrupt_sole<REMAP: RemapMode<I>>(
        mut self,
        pins: (impl I2cSclPin<REMAP>, impl I2cSdaPin<REMAP>),
        speed: HertzU32,
        max_operation: usize,
        mcu: &mut Mcu,
    ) -> (
        bus_it::I2cBus<OS, I>,
        bus_it::InterruptHandler<OS, I>,
        bus_it::ErrorInterruptHandler<OS, I>,
    ) {
        let _ = (pins.0.into_alternate(), pins.1.into_alternate());
        REMAP::remap(&mut mcu.afio);
        assert!(speed <= kHz(400));
        self.i2c.config(&Mode::from(speed));
        bus_it::I2cBus::<OS, I>::new(self.i2c, speed, max_operation)
    }

    pub fn into_interrupt_bus<REMAP: RemapMode<I>>(
        mut self,
        pins: (impl I2cSclPin<REMAP>, impl I2cSdaPin<REMAP>),
        speed: HertzU32,
        max_operation: usize,
        mcu: &mut Mcu,
    ) -> (
        I2cDeviceBuilder<OS, bus_it::I2cBus<OS, I>>,
        bus_it::InterruptHandler<OS, I>,
        bus_it::ErrorInterruptHandler<OS, I>,
    ) {
        let _ = (pins.0.into_alternate(), pins.1.into_alternate());
        REMAP::remap(&mut mcu.afio);
        assert!(speed <= kHz(400));
        self.i2c.config(&Mode::from(speed));
        let (bus, it, err_it) = bus_it::I2cBus::<OS, I>::new(self.i2c, speed, max_operation);
        (
            I2cDeviceBuilder {
                bus: Arc::new(OS::mutex(bus)),
            },
            it,
            err_it,
        )
    }
}

pub struct I2cDeviceBuilder<OS: OsInterface, BUS> {
    bus: Arc<Mutex<OS, BUS>>,
}

impl<OS, BUS> I2cDeviceBuilder<OS, BUS>
where
    OS: OsInterface,
    BUS: I2cBusInterface,
{
    pub fn new_device(&self) -> I2cMutexDevice<OS, BUS> {
        I2cMutexDevice::new(Arc::clone(&self.bus))
    }
}

#[inline]
fn convert_addr(addr: Address) -> Address {
    match addr {
        Address::Seven(addr) => Address::Seven(addr << 1),
        Address::Ten(addr) => {
            let [msb, lsb] = addr.to_be_bytes();
            let msb = ((msb & 0b11) << 1) | 0b11110000;
            Address::Ten(u16::from_be_bytes([msb, lsb]))
        }
    }
}

#[derive(Debug, Eq, PartialEq)]
pub enum DutyCycle {
    Ratio2to1,
    Ratio16to9,
}

#[derive(Debug, PartialEq, Eq)]
pub enum Mode {
    Standard {
        frequency: HertzU32,
    },
    Fast {
        frequency: HertzU32,
        duty_cycle: DutyCycle,
    },
}

impl Mode {
    pub fn standard(frequency: HertzU32) -> Self {
        Mode::Standard { frequency }
    }

    pub fn fast(frequency: HertzU32, duty_cycle: DutyCycle) -> Self {
        Mode::Fast {
            frequency,
            duty_cycle,
        }
    }

    pub fn get_frequency(&self) -> HertzU32 {
        match *self {
            Mode::Standard { frequency } => frequency,
            Mode::Fast { frequency, .. } => frequency,
        }
    }
}

impl From<HertzU32> for Mode {
    fn from(frequency: HertzU32) -> Self {
        if frequency <= kHz(100) {
            Self::Standard { frequency }
        } else {
            Self::Fast {
                frequency,
                duty_cycle: DutyCycle::Ratio2to1,
            }
        }
    }
}