aboutsummaryrefslogtreecommitdiff
path: root/src/i2c/mod.rs
blob: a1f84202945115213de01dd4c1853dda666bbc2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! I2C Support

use core::marker::PhantomData;

use embassy_hal_internal::PeripheralType;
use embassy_sync::waitqueue::AtomicWaker;
use paste::paste;

use crate::clocks::periph_helpers::Lpi2cConfig;
use crate::clocks::{ClockError, Gate};
use crate::gpio::{GpioPin, SealedPin};
use crate::{interrupt, pac};

/// Shorthand for `Result<T>`.
pub type Result<T> = core::result::Result<T, Error>;

pub mod controller;

/// Error information type
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
    /// Clock configuration error.
    ClockSetup(ClockError),
    /// Reading for I2C failed.
    ReadFail,
    /// Writing to I2C failed.
    WriteFail,
    /// I2C address NAK condition.
    AddressNack,
    /// Bus level arbitration loss.
    ArbitrationLoss,
    /// Address out of range.
    AddressOutOfRange(u8),
    /// Invalid write buffer length.
    InvalidWriteBufferLength,
    /// Invalid read buffer length.
    InvalidReadBufferLength,
    /// Other internal errors or unexpected state.
    Other,
}

/// I2C interrupt handler.
pub struct InterruptHandler<T: Instance> {
    _phantom: PhantomData<T>,
}

impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
    unsafe fn on_interrupt() {
        let waker = T::waker();

        waker.wake();

        todo!()
    }
}

mod sealed {
    /// Seal a trait
    pub trait Sealed {}
}

impl<T: GpioPin> sealed::Sealed for T {}

trait SealedInstance {
    fn regs() -> &'static pac::lpi2c0::RegisterBlock;
    fn waker() -> &'static AtomicWaker;
}

/// I2C Instance
#[allow(private_bounds)]
pub trait Instance: SealedInstance + PeripheralType + 'static + Send + Gate<MrccPeriphConfig = Lpi2cConfig> {
    /// Interrupt for this I2C instance.
    type Interrupt: interrupt::typelevel::Interrupt;
    /// Clock instance
    const CLOCK_INSTANCE: crate::clocks::periph_helpers::Lpi2cInstance;
}

macro_rules! impl_instance {
    ($($n:expr),*) => {
        $(
            paste!{
                impl SealedInstance for crate::peripherals::[<LPI2C $n>] {
                    fn regs() -> &'static pac::lpi2c0::RegisterBlock {
                        unsafe { &*pac::[<Lpi2c $n>]::ptr() }
                    }

                    fn waker() -> &'static AtomicWaker {
                        static WAKER: AtomicWaker = AtomicWaker::new();
                        &WAKER
                    }
                }

                impl Instance for crate::peripherals::[<LPI2C $n>] {
                    type Interrupt = crate::interrupt::typelevel::[<LPI2C $n>];
                    const CLOCK_INSTANCE: crate::clocks::periph_helpers::Lpi2cInstance
                        = crate::clocks::periph_helpers::Lpi2cInstance::[<Lpi2c $n>];
                }
            }
        )*
    };
}

impl_instance!(0, 1, 2, 3);

/// SCL pin trait.
pub trait SclPin<Instance>: GpioPin + sealed::Sealed + PeripheralType {
    fn mux(&self);
}

/// SDA pin trait.
pub trait SdaPin<Instance>: GpioPin + sealed::Sealed + PeripheralType {
    fn mux(&self);
}

/// Driver mode.
#[allow(private_bounds)]
pub trait Mode: sealed::Sealed {}

/// Blocking mode.
pub struct Blocking;
impl sealed::Sealed for Blocking {}
impl Mode for Blocking {}

/// Async mode.
pub struct Async;
impl sealed::Sealed for Async {}
impl Mode for Async {}

macro_rules! impl_pin {
    ($pin:ident, $peri:ident, $fn:ident, $trait:ident) => {
        impl $trait<crate::peripherals::$peri> for crate::peripherals::$pin {
            fn mux(&self) {
                self.set_pull(crate::gpio::Pull::Disabled);
                self.set_slew_rate(crate::gpio::SlewRate::Fast.into());
                self.set_drive_strength(crate::gpio::DriveStrength::Double.into());
                self.set_function(crate::pac::port0::pcr0::Mux::$fn);
                self.set_enable_input_buffer();
            }
        }
    };
}

impl_pin!(P0_16, LPI2C0, Mux2, SdaPin);
impl_pin!(P0_17, LPI2C0, Mux2, SclPin);
impl_pin!(P0_18, LPI2C0, Mux2, SclPin);
impl_pin!(P0_19, LPI2C0, Mux2, SdaPin);
impl_pin!(P1_0, LPI2C1, Mux3, SdaPin);
impl_pin!(P1_1, LPI2C1, Mux3, SclPin);
impl_pin!(P1_2, LPI2C1, Mux3, SdaPin);
impl_pin!(P1_3, LPI2C1, Mux3, SclPin);
impl_pin!(P1_8, LPI2C2, Mux3, SdaPin);
impl_pin!(P1_9, LPI2C2, Mux3, SclPin);
impl_pin!(P1_10, LPI2C2, Mux3, SdaPin);
impl_pin!(P1_11, LPI2C2, Mux3, SclPin);
impl_pin!(P1_12, LPI2C1, Mux2, SdaPin);
impl_pin!(P1_13, LPI2C1, Mux2, SclPin);
impl_pin!(P1_14, LPI2C1, Mux2, SclPin);
impl_pin!(P1_15, LPI2C1, Mux2, SdaPin);
impl_pin!(P1_30, LPI2C0, Mux3, SdaPin);
impl_pin!(P1_31, LPI2C0, Mux3, SclPin);
impl_pin!(P3_27, LPI2C3, Mux2, SclPin);
impl_pin!(P3_28, LPI2C3, Mux2, SdaPin);
// impl_pin!(P3_29, LPI2C3, Mux2, HreqPin); What is this HREQ pin?
impl_pin!(P3_30, LPI2C3, Mux2, SclPin);
impl_pin!(P3_31, LPI2C3, Mux2, SdaPin);
impl_pin!(P4_2, LPI2C2, Mux2, SdaPin);
impl_pin!(P4_3, LPI2C0, Mux2, SclPin);
impl_pin!(P4_4, LPI2C2, Mux2, SdaPin);
impl_pin!(P4_5, LPI2C0, Mux2, SclPin);
// impl_pin!(P4_6, LPI2C0, Mux2, HreqPin); What is this HREQ pin?