diff options
Diffstat (limited to 'embassy-mcxa/src/i2c/mod.rs')
| -rw-r--r-- | embassy-mcxa/src/i2c/mod.rs | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/embassy-mcxa/src/i2c/mod.rs b/embassy-mcxa/src/i2c/mod.rs new file mode 100644 index 000000000..9a014224a --- /dev/null +++ b/embassy-mcxa/src/i2c/mod.rs | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | //! I2C Support | ||
| 2 | |||
| 3 | use core::marker::PhantomData; | ||
| 4 | |||
| 5 | use embassy_hal_internal::PeripheralType; | ||
| 6 | use maitake_sync::WaitCell; | ||
| 7 | use paste::paste; | ||
| 8 | |||
| 9 | use crate::clocks::periph_helpers::Lpi2cConfig; | ||
| 10 | use crate::clocks::{ClockError, Gate}; | ||
| 11 | use crate::gpio::{GpioPin, SealedPin}; | ||
| 12 | use crate::{interrupt, pac}; | ||
| 13 | |||
| 14 | /// Shorthand for `Result<T>`. | ||
| 15 | pub type Result<T> = core::result::Result<T, Error>; | ||
| 16 | |||
| 17 | pub mod controller; | ||
| 18 | |||
| 19 | /// Error information type | ||
| 20 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 22 | pub enum Error { | ||
| 23 | /// Clock configuration error. | ||
| 24 | ClockSetup(ClockError), | ||
| 25 | /// FIFO Error | ||
| 26 | FifoError, | ||
| 27 | /// Reading for I2C failed. | ||
| 28 | ReadFail, | ||
| 29 | /// Writing to I2C failed. | ||
| 30 | WriteFail, | ||
| 31 | /// I2C address NAK condition. | ||
| 32 | AddressNack, | ||
| 33 | /// Bus level arbitration loss. | ||
| 34 | ArbitrationLoss, | ||
| 35 | /// Address out of range. | ||
| 36 | AddressOutOfRange(u8), | ||
| 37 | /// Invalid write buffer length. | ||
| 38 | InvalidWriteBufferLength, | ||
| 39 | /// Invalid read buffer length. | ||
| 40 | InvalidReadBufferLength, | ||
| 41 | /// Other internal errors or unexpected state. | ||
| 42 | Other, | ||
| 43 | } | ||
| 44 | |||
| 45 | /// I2C interrupt handler. | ||
| 46 | pub struct InterruptHandler<T: Instance> { | ||
| 47 | _phantom: PhantomData<T>, | ||
| 48 | } | ||
| 49 | |||
| 50 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 51 | unsafe fn on_interrupt() { | ||
| 52 | if T::regs().mier().read().bits() != 0 { | ||
| 53 | T::regs().mier().write(|w| { | ||
| 54 | w.tdie() | ||
| 55 | .disabled() | ||
| 56 | .rdie() | ||
| 57 | .disabled() | ||
| 58 | .epie() | ||
| 59 | .disabled() | ||
| 60 | .sdie() | ||
| 61 | .disabled() | ||
| 62 | .ndie() | ||
| 63 | .disabled() | ||
| 64 | .alie() | ||
| 65 | .disabled() | ||
| 66 | .feie() | ||
| 67 | .disabled() | ||
| 68 | .pltie() | ||
| 69 | .disabled() | ||
| 70 | .dmie() | ||
| 71 | .disabled() | ||
| 72 | .stie() | ||
| 73 | .disabled() | ||
| 74 | }); | ||
| 75 | |||
| 76 | T::wait_cell().wake(); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | mod sealed { | ||
| 82 | /// Seal a trait | ||
| 83 | pub trait Sealed {} | ||
| 84 | } | ||
| 85 | |||
| 86 | impl<T: GpioPin> sealed::Sealed for T {} | ||
| 87 | |||
| 88 | trait SealedInstance { | ||
| 89 | fn regs() -> &'static pac::lpi2c0::RegisterBlock; | ||
| 90 | fn wait_cell() -> &'static WaitCell; | ||
| 91 | } | ||
| 92 | |||
| 93 | /// I2C Instance | ||
| 94 | #[allow(private_bounds)] | ||
| 95 | pub trait Instance: SealedInstance + PeripheralType + 'static + Send + Gate<MrccPeriphConfig = Lpi2cConfig> { | ||
| 96 | /// Interrupt for this I2C instance. | ||
| 97 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 98 | /// Clock instance | ||
| 99 | const CLOCK_INSTANCE: crate::clocks::periph_helpers::Lpi2cInstance; | ||
| 100 | } | ||
| 101 | |||
| 102 | macro_rules! impl_instance { | ||
| 103 | ($($n:expr),*) => { | ||
| 104 | $( | ||
| 105 | paste!{ | ||
| 106 | impl SealedInstance for crate::peripherals::[<LPI2C $n>] { | ||
| 107 | fn regs() -> &'static pac::lpi2c0::RegisterBlock { | ||
| 108 | unsafe { &*pac::[<Lpi2c $n>]::ptr() } | ||
| 109 | } | ||
| 110 | |||
| 111 | fn wait_cell() -> &'static WaitCell { | ||
| 112 | static WAIT_CELL: WaitCell = WaitCell::new(); | ||
| 113 | &WAIT_CELL | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | impl Instance for crate::peripherals::[<LPI2C $n>] { | ||
| 118 | type Interrupt = crate::interrupt::typelevel::[<LPI2C $n>]; | ||
| 119 | const CLOCK_INSTANCE: crate::clocks::periph_helpers::Lpi2cInstance | ||
| 120 | = crate::clocks::periph_helpers::Lpi2cInstance::[<Lpi2c $n>]; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | )* | ||
| 124 | }; | ||
| 125 | } | ||
| 126 | |||
| 127 | impl_instance!(0, 1, 2, 3); | ||
| 128 | |||
| 129 | /// SCL pin trait. | ||
| 130 | pub trait SclPin<Instance>: GpioPin + sealed::Sealed + PeripheralType { | ||
| 131 | fn mux(&self); | ||
| 132 | } | ||
| 133 | |||
| 134 | /// SDA pin trait. | ||
| 135 | pub trait SdaPin<Instance>: GpioPin + sealed::Sealed + PeripheralType { | ||
| 136 | fn mux(&self); | ||
| 137 | } | ||
| 138 | |||
| 139 | /// Driver mode. | ||
| 140 | #[allow(private_bounds)] | ||
| 141 | pub trait Mode: sealed::Sealed {} | ||
| 142 | |||
| 143 | /// Blocking mode. | ||
| 144 | pub struct Blocking; | ||
| 145 | impl sealed::Sealed for Blocking {} | ||
| 146 | impl Mode for Blocking {} | ||
| 147 | |||
| 148 | /// Async mode. | ||
| 149 | pub struct Async; | ||
| 150 | impl sealed::Sealed for Async {} | ||
| 151 | impl Mode for Async {} | ||
| 152 | |||
| 153 | macro_rules! impl_pin { | ||
| 154 | ($pin:ident, $peri:ident, $fn:ident, $trait:ident) => { | ||
| 155 | impl $trait<crate::peripherals::$peri> for crate::peripherals::$pin { | ||
| 156 | fn mux(&self) { | ||
| 157 | self.set_pull(crate::gpio::Pull::Disabled); | ||
| 158 | self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); | ||
| 159 | self.set_drive_strength(crate::gpio::DriveStrength::Double.into()); | ||
| 160 | self.set_function(crate::pac::port0::pcr0::Mux::$fn); | ||
| 161 | self.set_enable_input_buffer(); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | }; | ||
| 165 | } | ||
| 166 | |||
| 167 | impl_pin!(P0_16, LPI2C0, Mux2, SdaPin); | ||
| 168 | impl_pin!(P0_17, LPI2C0, Mux2, SclPin); | ||
| 169 | impl_pin!(P0_18, LPI2C0, Mux2, SclPin); | ||
| 170 | impl_pin!(P0_19, LPI2C0, Mux2, SdaPin); | ||
| 171 | impl_pin!(P1_0, LPI2C1, Mux3, SdaPin); | ||
| 172 | impl_pin!(P1_1, LPI2C1, Mux3, SclPin); | ||
| 173 | impl_pin!(P1_2, LPI2C1, Mux3, SdaPin); | ||
| 174 | impl_pin!(P1_3, LPI2C1, Mux3, SclPin); | ||
| 175 | impl_pin!(P1_8, LPI2C2, Mux3, SdaPin); | ||
| 176 | impl_pin!(P1_9, LPI2C2, Mux3, SclPin); | ||
| 177 | impl_pin!(P1_10, LPI2C2, Mux3, SdaPin); | ||
| 178 | impl_pin!(P1_11, LPI2C2, Mux3, SclPin); | ||
| 179 | impl_pin!(P1_12, LPI2C1, Mux2, SdaPin); | ||
| 180 | impl_pin!(P1_13, LPI2C1, Mux2, SclPin); | ||
| 181 | impl_pin!(P1_14, LPI2C1, Mux2, SclPin); | ||
| 182 | impl_pin!(P1_15, LPI2C1, Mux2, SdaPin); | ||
| 183 | impl_pin!(P1_30, LPI2C0, Mux3, SdaPin); | ||
| 184 | impl_pin!(P1_31, LPI2C0, Mux3, SclPin); | ||
| 185 | impl_pin!(P3_27, LPI2C3, Mux2, SclPin); | ||
| 186 | impl_pin!(P3_28, LPI2C3, Mux2, SdaPin); | ||
| 187 | // impl_pin!(P3_29, LPI2C3, Mux2, HreqPin); What is this HREQ pin? | ||
| 188 | impl_pin!(P3_30, LPI2C3, Mux2, SclPin); | ||
| 189 | impl_pin!(P3_31, LPI2C3, Mux2, SdaPin); | ||
| 190 | impl_pin!(P4_2, LPI2C2, Mux2, SdaPin); | ||
| 191 | impl_pin!(P4_3, LPI2C0, Mux2, SclPin); | ||
| 192 | impl_pin!(P4_4, LPI2C2, Mux2, SdaPin); | ||
| 193 | impl_pin!(P4_5, LPI2C0, Mux2, SclPin); | ||
| 194 | // impl_pin!(P4_6, LPI2C0, Mux2, HreqPin); What is this HREQ pin? | ||
